├── .gitignore ├── Angular.WinJS.nuspec ├── Gruntfile.js ├── License.txt ├── README.md ├── bower.json ├── js └── angular-winjs.js ├── karma.config.js ├── package.json ├── tasks └── check-bom.js └── tests ├── AppBar.js ├── AppBarCommand.js ├── AutoSuggestBox.js ├── BackButton.js ├── ContentDialog.js ├── DatePicker.js ├── FlipView.js ├── Flyout.js ├── Hub.js ├── HubSection.js ├── ItemContainer.js ├── ListView.js ├── ListViewLayouts.js ├── Menu.js ├── MenuCommand.js ├── Pivot.js ├── Rating.js ├── SemanticZoom.js ├── SplitView.js ├── SplitViewCommand.js ├── SplitViewPaneToggle.js ├── TimePicker.js ├── ToggleSwitch.js ├── ToolBar.js ├── ToolBarCommand.js └── Tooltip.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | 4 | Thumbs.db 5 | ehthumbs.db 6 | Desktop.ini 7 | $RECYCLE.BIN/ 8 | *.tmp.txt 9 | .DS_Store 10 | 11 | *.nupkg -------------------------------------------------------------------------------- /Angular.WinJS.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Angular.WinJS 5 | 1.0.0 6 | Microsoft Corporation and other contributors 7 | https://raw.githubusercontent.com/winjs/angular-winjs/master/License.txt 8 | https://github.com/winjs/angular-winjs 9 | false 10 | This code is a wrapper which facilitates usage of WinJS UI controls in an Angular application. 11 | Microsoft Corporation. All Rights Reserved 12 | winjs angular 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | "use strict"; 4 | 5 | var exec = require('child_process').exec; 6 | var execSync = require('child_process').execSync; 7 | 8 | module.exports = function(grunt) { 9 | 10 | var publishRoot = 'dist/'; 11 | var npmPublishRoot = publishRoot + 'npm/'; 12 | 13 | // All version number information is derived from package.json. This includes the version 14 | // info used with npm, bower, NuGet, and the GitHub release. 15 | var pkg = grunt.file.readJSON('package.json'); 16 | var fullWinjsVersion = pkg.devDependencies.winjs; 17 | if (!fullWinjsVersion) { 18 | grunt.fail.fatal('Unable to determine WinJS version required by angular-winjs'); 19 | } 20 | // package.json version contains ... We just want . 21 | var winjsVersion = fullWinjsVersion.split(".").slice(0, 2).join("."); 22 | 23 | var currentGitCommitHash = execSync('git rev-parse HEAD').toString().trim(); 24 | 25 | var bomGlob = "**/*.+(js|css|htm|html)"; 26 | 27 | // Project configuration. 28 | grunt.initConfig({ 29 | pkg: pkg, 30 | 31 | clean: { 32 | publish: [publishRoot] 33 | }, 34 | 35 | copy: { 36 | publish: { 37 | files: [{ 38 | expand: true, 39 | src: [ 40 | 'js/**', 41 | 'License.txt', 42 | 'package.json', 43 | 'README.md' 44 | ], 45 | dest: npmPublishRoot 46 | }] 47 | } 48 | }, 49 | 50 | compress: { 51 | publish: { 52 | options: { 53 | archive: publishRoot + 'angular-winjs.zip' 54 | }, 55 | files: [{ 56 | expand: true, 57 | cwd: npmPublishRoot, 58 | src: ["**"] 59 | }] 60 | } 61 | }, 62 | 63 | "check-bom": { 64 | publish: { 65 | files: [{ 66 | cwd: 'js', 67 | src: bomGlob, 68 | expand: true, 69 | nocase: true 70 | }, { 71 | cwd: publishRoot, 72 | src: bomGlob, 73 | expand: true, 74 | nocase: true 75 | }] 76 | } 77 | }, 78 | 79 | nugetpack: { 80 | publish: { 81 | src: 'Angular.WinJS.nuspec', 82 | dest: publishRoot, 83 | options: { 84 | version: '<%= pkg.version %>' 85 | } 86 | } 87 | }, 88 | 89 | // Publishes nuget package 90 | nugetpush: { 91 | // Requires NuGet API key to be set. You can do this with: 92 | // grunt nugetkey --key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 93 | publish: { 94 | src: publishRoot + '*.nupkg', 95 | } 96 | }, 97 | 98 | // Publishes GitHub release and bower package (bower consumes GitHub tags/releases) 99 | 'github-release': { 100 | // Requires this environment variable to be set: GITHUB_ACCESS_TOKEN 101 | // GITHUB_ACCESS_TOKEN can be generated from https://help.github.com/articles/creating-an-access-token-for-command-line-use/ 102 | publish: { 103 | options: { 104 | repository: 'winjs/angular-winjs', 105 | auth: { 106 | user: process.env.GITHUB_ACCESS_TOKEN 107 | }, 108 | release: { 109 | tag_name: 'v<%= pkg.version %>', // Must follow semver syntax in order for bower to pick it up 110 | target_commitish: currentGitCommitHash, 111 | name: '<%= pkg.version %>', 112 | body: 113 | 'Release of angular-winjs <%= pkg.version %>.\n' + 114 | '\n' + 115 | 'Compatible with WinJS ' + winjsVersion + '.\n' 116 | } 117 | }, 118 | files: { 119 | src: [publishRoot + 'angular-winjs.zip'] 120 | } 121 | } 122 | } 123 | }); 124 | 125 | grunt.loadTasks('tasks/'); 126 | 127 | var plugins = [ 128 | 'grunt-contrib-clean', 129 | 'grunt-contrib-compress', 130 | 'grunt-contrib-copy', 131 | 'grunt-nuget', 132 | 'grunt-github-releaser' 133 | ]; 134 | plugins.forEach(function (plugin) { 135 | grunt.loadNpmTasks(plugin); 136 | }); 137 | 138 | // Publishes npm package 139 | grunt.registerTask('npm-release', function (mode) { 140 | var done = this.async(); 141 | var cmd = 'npm publish ' + npmPublishRoot; 142 | 143 | exec(cmd, function (err, stdout) { 144 | if (err) { 145 | grunt.fatal('npm publish failed using command: ' + cmd); 146 | } 147 | done(); 148 | }); 149 | }); 150 | 151 | // Sets up all of the state necessary to do a publish but doesn't actually publish 152 | // to any of the package managers. 153 | grunt.registerTask('prepare-publish', [ 154 | 'clean:publish', 155 | 'copy:publish', 156 | 'compress:publish', 157 | 'nugetpack:publish', 158 | 'check-bom:publish', 159 | ]); 160 | 161 | grunt.registerTask('finished-publish', function (mode) { 162 | grunt.log.writeln(''); 163 | grunt.log.writeln('Publish complete. Hand tweak the GitHub release description if necessary (https://github.com/winjs/angular-winjs/releases)'); 164 | grunt.log.writeln(''); 165 | }); 166 | 167 | // 168 | // Public tasks designed to be run from the command line 169 | // 170 | 171 | // Populates the 'dist' folder and then uses it to: 172 | // - Create a GitHub release 173 | // - Publish to npm 174 | // - Publish to bower 175 | // - Publish to NuGet 176 | // When debugging publish, it's helpful to run just the 'prepare-publish' 177 | // task which puts all of the publication data into the 'dist' folder but 178 | // doesn't actually send the data to the package managers. 179 | grunt.registerTask('publish', function (mode) { 180 | if (!process.env.GITHUB_ACCESS_TOKEN) { 181 | grunt.fail.fatal('The GITHUB_ACCESS_TOKEN environment variable must be set in order to create GitHub releases'); 182 | } 183 | 184 | if (!mode) { 185 | grunt.log.writeln(''); 186 | grunt.log.writeln('Will publish version ' + pkg.version + ' of angular-winjs to npm, NuGet, etc. Double check that:'); 187 | grunt.log.writeln(' * You are on the branch you\'d like to publish'); 188 | grunt.log.writeln(' * The branch has been pushed to GitHub'); 189 | grunt.log.writeln(' * You don\'t have any local edits'); 190 | grunt.log.writeln(''); 191 | grunt.log.writeln('If everything is in order, run "grunt publish:force" to proceed'); 192 | } else if (mode === 'force') { 193 | grunt.task.run([ 194 | 'prepare-publish', 195 | 'nugetpush:publish', 196 | 'github-release:publish', 197 | 'npm-release', 198 | 'finished-publish', 199 | ]); 200 | } 201 | }); 202 | }; 203 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | angular-winjs 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | 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: 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 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. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angular-winjs 2 | ============= 3 | 4 | Project to smooth the AngularJS/WinJS interaction. This code is a shim layer which facilitates usage of WinJS UI controls in an Angular Windows application. It achieves this by creating directives for the various controls which allow them to show up in Angular markup like: 5 | 6 | How to use this in your Angular project? 7 | ---------------------------------------- 8 | 9 | Just make sure to include WinJS 4.0, and then include the shim. 10 | 11 | 12 | 13 | 14 | 15 | You must also add this module to your list of angular module dependencies: 16 | 17 | angular.module('your-module', ['winjs', 'other-module-you-depend-on', 'etc']); 18 | 19 | 20 | Examples of control usage 21 | ------------------------- 22 | 23 | ### AppBar and AppBarCommand 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ### AutoSuggestionBox 37 | 38 | The current query text is: {{queryText}}.
39 | 40 | 41 | 42 | ### Content Dialog 43 | angular.module("yourAngularApp", ["winjs"]).controller("yourController", function ($scope) { 44 | $scope.contentDialogHidden = true; 45 | $scope.showContentDialog = function () { 46 | $scope.contentDialogHidden = false; 47 | }; 48 | }); 49 | 52 | 53 | 54 | ### DatePicker 55 | 56 | 57 | 58 | ### FlipView 59 | 60 | 61 | This flip view item's rating is: {{item.data.rating}} 62 | 63 | 64 | ### Flyout 65 | 66 | 67 | This is the flyout content!! 68 | 69 | ### Hub and HubSection 70 | 71 | 72 | 73 | Hubs are useful for varied content 74 | 75 | 76 | This hub is boring however, it just has things like data bindings: {{ratings.length}} 77 | 78 | 79 | Because it's only purpose is to show how to create a hub 80 | 81 | 82 | 83 | ### ItemContainer 84 | 85 | 86 | An ItemContainer is a wrapper around content that adds pressed 87 | and cross-slide selection behaviors! 88 | 89 | 90 | ### ListView 91 | 92 |
Selected count: {{selection.length}}, indexes: {{selection.toString()}}
93 | 94 | This is a ListView header 95 | This list view item's rating is: {{item.data.rating}} 96 | 97 | This is a ListView footer 98 | 99 | 100 | ### Menu and MenuCommand 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | ### Pivot and PivotItem 110 | 111 | 112 | Custom Left Header 113 | 114 | Pivots are useful for varied content 115 | 116 | 117 | This Pivot is boring however, it just has things like data bindings: {{ratings.length}} 118 | 119 | 120 | Because it's only purpose is to show how to create a Pivot 121 | 122 | Custom Right Header 123 | 124 | 125 | ### Rating 126 | 127 | The current rating is: {{ratings[0].rating}}.
128 | 129 | 130 | ### SemanticZoom 131 | 132 | 133 | 134 | 135 | The data is: {{item.data}} 136 | 137 | 138 | The group is: {{item.key}} 139 | 140 | 141 | 142 | 143 | The group is: {{item.key}} 144 | 145 | 146 | 147 | 148 | ### SplitView and optional SplitViewPaneToggle 149 | angular.module("yourAngularApp", ["winjs"]).controller("yourController", function ($scope) { 150 | $scope.splitViewElement = document.getElementById("splitView"); 151 | }); 152 | 153 | 154 | 155 | SplitView Navigation Pane 156 | 157 | 158 | 159 | SplitView Content Area 160 | 161 | 162 | ### ToolBar 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | ### TimePicker 173 | 174 | 175 | 176 | ### ToggleSwitch 177 | 178 | 179 | The state is: {{toggleState}}
180 | 181 | 182 | ### Tooltip 183 | 184 | 185 | This can have arbitrary content, like images... 186 | This has a tooltip, hover and see... 187 | 188 | 189 | ### WinControl 190 | 191 | 192 | 193 | This Pivot is showing how to access its winControl through Angular. 194 | The winControl can now be accessed as a variable on the Angular scope, using the same name that was 195 | specified in the directive. In this case, $scope.pivotWinControl 196 | 197 | 198 | 199 | How to run unit tests 200 | ------------------------- 201 | 202 | ### Install Node 203 | In order run tests, ensure that you have [Node.js](http://nodejs.org/download/) installed. 204 | 205 | ### Run the tests 206 | From the local angular-winjs repository 207 | ``` 208 | npm install 209 | npm test 210 | ``` 211 | 212 | 213 | Notes 214 | ----- 215 | 216 | For all of the controls you can bind to: all public events, and camel cased property names, conveniently map to attributes. 217 | - ```appBar.closedDisplayMode = "compact"``` maps to `````` 218 | - ```flipView.onpageselected = pagesSelected()``` maps to `````` 219 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-winjs", 3 | "homepage": "https://github.com/winjs/angular-winjs", 4 | "authors": [ 5 | "Microsoft Corporation and other contributors" 6 | ], 7 | "description": "This code is a wrapper which facilitates usage of WinJS UI controls in an Angular application.", 8 | "main": "js/angular-winjs.js", 9 | "keywords": [ 10 | "winjs", 11 | "angular", 12 | "AngularJS" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "test", 20 | "tests", 21 | "package.json", 22 | "karma.config.js", 23 | "*.nuspec", 24 | "Gruntfile.js" 25 | ] 26 | } -------------------------------------------------------------------------------- /js/angular-winjs.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | (function (global) { 3 | "use strict"; 4 | 5 | // setImmediate is not implemented in all browsers. If it doesn't exist, use setTimeout(_, 0) instead. 6 | var setImmediate = window.setImmediate; 7 | if (!setImmediate) { 8 | setImmediate = function (f) { 9 | return setTimeout(f, 0); 10 | }; 11 | } 12 | 13 | // ObjectIndexMap is used in the list binding code. On browsers with Map support we simply use the built in 14 | // primitive, for list elements which are extensible we instead map from the list elements to their 15 | // current index (note that we must do the full mapping on every diff in order to ensure we don't 16 | // see stale indicies), and for non-extensible objects we fall back to using an array with O(N) 17 | // lookup behavior on get. 18 | // ObjectIndexMap is only intended to be used in the list binding code below. This helper 19 | // is limited in that only one key object can be in any map at a time. 20 | var ObjectIndexMap = window.Map; 21 | if (!ObjectIndexMap) { 22 | // A simple value -> integer map 23 | ObjectIndexMap = function () { 24 | this._nonExtensibleBacking = []; 25 | }; 26 | ObjectIndexMap.key = "$$$$mapkey"; 27 | ObjectIndexMap.prototype.has = function (key) { 28 | if (Object.isExtensible(key)) { 29 | return ObjectIndexMap.key in key; 30 | } else { 31 | return this._nonExtensibleBacking.indexOf(key) !== -1; 32 | } 33 | }; 34 | ObjectIndexMap.prototype.get = function (key) { 35 | if (Object.isExtensible(key)) { 36 | return key[ObjectIndexMap.key]; 37 | } else { 38 | return this._nonExtensibleBacking.indexOf(key); 39 | } 40 | }; 41 | ObjectIndexMap.prototype.set = function (key, value) { 42 | if (Object.isExtensible(key)) { 43 | key[ObjectIndexMap.key] = value; 44 | } else { 45 | this._nonExtensibleBacking[value] = key; 46 | } 47 | }; 48 | } 49 | 50 | // Pure utility functions 51 | function getElementRoot(element) { 52 | var curr = element; 53 | while (curr.parentNode) { 54 | curr = curr.parentNode; 55 | } 56 | return curr; 57 | } 58 | 59 | function select(selector, element) { 60 | return document.querySelector(selector) || getElementRoot(element).querySelector(selector); 61 | } 62 | 63 | // Directive utilities 64 | function addDestroyListener($scope, control, bindings, destroyed) { 65 | $scope.$on("$destroy", function () { 66 | (destroyed && destroyed()); 67 | 68 | bindings.forEach(function (w) { w(); }); 69 | 70 | if (control.dispose) { 71 | control.dispose(); 72 | } 73 | }); 74 | } 75 | 76 | function apply($scope, f) { 77 | switch ($scope.$root.$$phase) { 78 | case "$apply": 79 | case "$digest": 80 | f(); 81 | break; 82 | default: 83 | $scope.$apply(function () { 84 | f(); 85 | }); 86 | break; 87 | } 88 | } 89 | 90 | function exists(control) { 91 | return !!Object.getOwnPropertyDescriptor(WinJS.UI, control); 92 | } 93 | 94 | function list($scope, key, getControl, getList, bindings) { 95 | var value = $scope[key]; 96 | if (value && Array.isArray(value)) { 97 | var originalArray = value; 98 | var bindingList = new WinJS.Binding.List(originalArray); 99 | value = bindingList; 100 | 101 | bindings.push($scope.$watchCollection(key, function (array) { 102 | var list = getList(); 103 | if (!list) { 104 | return; 105 | } 106 | if (!array) { 107 | list.length = 0; 108 | return; 109 | } 110 | var targetIndicies = new ObjectIndexMap(); 111 | for (var i = 0, len = array.length; i < len; i++) { 112 | targetIndicies.set(array[i], i); 113 | } 114 | var arrayIndex = 0, listIndex = 0; 115 | while (arrayIndex < array.length) { 116 | var arrayData = array[arrayIndex]; 117 | if (listIndex >= list.length) { 118 | list.push(arrayData); 119 | } else { 120 | while (listIndex < list.length) { 121 | var listData = list.getAt(listIndex); 122 | if (listData === arrayData) { 123 | listIndex++; 124 | arrayIndex++; 125 | break; 126 | } else { 127 | if (targetIndicies.has(listData)) { 128 | var targetIndex = targetIndicies.get(listData); 129 | if (targetIndex < arrayIndex) { 130 | // Already in list, remove the duplicate 131 | list.splice(listIndex, 1); 132 | } else { 133 | list.splice(listIndex, 0, arrayData); 134 | arrayIndex++; 135 | listIndex++; 136 | break; 137 | } 138 | } else { 139 | // Deleted, remove from list 140 | list.splice(listIndex, 1); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | // Clip any items which are left over in the tail. 147 | list.length = array.length; 148 | })); 149 | 150 | var deferUpdate = false; 151 | var updateOriginalArray = function () { 152 | if (deferUpdate) { 153 | return; 154 | } 155 | 156 | // Defer here so that we can process all changes to the list in one go. 157 | deferUpdate = true; 158 | WinJS.Utilities._setImmediate(function () { 159 | apply($scope, function () { 160 | originalArray.length = 0; 161 | for (var i = 0, len = bindingList.length; i < len; i++) { 162 | originalArray.push(bindingList.getAt(i)); 163 | } 164 | deferUpdate = false; 165 | }); 166 | }); 167 | } 168 | 169 | // The Binding.List we're creating for the WinJS control can be altered by the control (eg, ListView will reorder the content of its Binding.List in drag and drop scenarios). 170 | // We need to make sure changes to this list propagate back to the original array on the Angular scope. We'll listen to all data changes in the Binding.List 171 | // and change the original array when something changes. 172 | var bindingListMutationEvents = ["itemchanged", "itemmoved", "itemmutated", "itemremoved", "reload"]; 173 | bindingListMutationEvents.forEach(function (event) { 174 | bindingList.addEventListener(event, updateOriginalArray); 175 | }); 176 | } else { 177 | // The value from $scope[key] can be undefined when this list function first runs. 178 | // If the binding behind that value has already been processed by angular but hasn't been applied to the scope yet, $scope[key] will be undefined, 179 | // but when this watch function is called, oldValue will have the same value as newValue instead of being undefined. 180 | // In most cases we want to avoid reprocessing the list when newValue === oldValue, but we will make an exeption for this case. 181 | // When $scope[key] is falsy, we'll set up the listener to use oldValue if oldValue is valid and it's the listener's first run. 182 | var updateValueOnFirstWatch = (!value); 183 | bindings.push($scope.$watch(key, function (newValue, oldValue) { 184 | if (newValue !== oldValue || (oldValue && updateValueOnFirstWatch)) { 185 | getControl()[key] = list($scope, key, getControl, getList, bindings); 186 | } 187 | updateValueOnFirstWatch = false; 188 | })); 189 | } 190 | 191 | if (value && value.dataSource) { 192 | value = value.dataSource; 193 | } 194 | return value; 195 | } 196 | 197 | function proxy($scope, controller, name) { 198 | Object.defineProperty(controller, name, { 199 | get: function () { return $scope[name]; }, 200 | set: function (value) { $scope[name] = value; } 201 | }); 202 | } 203 | 204 | // Refer to https://docs.angularjs.org/api/ng/service/$compile for documentation on what "=?" etc. means 205 | function BINDING_anchor($scope, key, element, getControl, bindings) { 206 | bindings.push($scope.$watch(key, function (newValue, oldValue) { 207 | newValue = typeof newValue === "string" ? select(newValue, element) : newValue; 208 | oldValue = typeof oldValue === "string" ? select(oldValue, element) : oldValue; 209 | if (oldValue && oldValue._anchorClick) { 210 | oldValue.removeEventListener("click", oldValue._anchorClick); 211 | oldValue._anchorClick = null; 212 | } 213 | if (newValue && !newValue._anchorClick) { 214 | newValue._anchorClick = function () { getControl().show(); }; 215 | newValue.addEventListener("click", newValue._anchorClick); 216 | } 217 | return newValue; 218 | })); 219 | var anchor = $scope[key]; 220 | return typeof anchor === "string" ? select(anchor, element) : anchor; 221 | } 222 | BINDING_anchor.binding = "=?"; 223 | 224 | function BINDING_dataSource($scope, key, element, getControl, bindings) { 225 | function getList() { 226 | var control = getControl(); 227 | if (control) { 228 | var dataSource = control[key]; 229 | if (dataSource) { 230 | return dataSource.list; 231 | } 232 | } 233 | } 234 | return list($scope, key, getControl, getList, bindings); 235 | } 236 | BINDING_dataSource.binding = "=?"; 237 | 238 | function BINDING_event($scope, key, element, getControl, bindings) { 239 | var lowerName = key.toLowerCase(); 240 | bindings.push($scope.$watch(key, function (newValue, oldValue) { 241 | if (newValue !== oldValue) { 242 | getControl()[lowerName] = newValue; 243 | } 244 | })); 245 | var value = $scope[key]; 246 | return function (event) { 247 | apply($scope, function () { value({ $event: event }); }); 248 | }; 249 | } 250 | BINDING_event.binding = "&"; 251 | 252 | function BINDING_property($scope, key, element, getControl, bindings) { 253 | bindings.push($scope.$watch(key, function (newValue, oldValue) { 254 | if (newValue !== oldValue) { 255 | (getControl() || {})[key] = newValue; 256 | } 257 | })); 258 | return $scope[key]; 259 | } 260 | BINDING_property.binding = "=?"; 261 | 262 | function BINDING_readonly_property($scope, key, element, getControl, bindings) { 263 | return $scope[key]; 264 | } 265 | BINDING_readonly_property.binding = "=?"; 266 | 267 | function BINDING_selection($scope, key, element, getControl, bindings) { 268 | bindings.push($scope.$watchCollection(key, function (selection) { 269 | var value = (getControl() || {})[key]; 270 | if (value) { 271 | value.set(selection); 272 | } 273 | })); 274 | return $scope[key]; 275 | } 276 | BINDING_selection.binding = "=?"; 277 | 278 | function getScopeForAPI(api) { 279 | var scopeDefinition = {}; 280 | for (var property in api) { 281 | scopeDefinition[property] = api[property].binding; 282 | } 283 | return scopeDefinition; 284 | } 285 | 286 | function initializeControlBindings($scope, api, controlRoot, getControl) { 287 | var controlOptions = {}, 288 | bindings = []; 289 | 290 | for (var property in api) { 291 | var binding = api[property]; 292 | var propertyValue = binding($scope, property, controlRoot, getControl, bindings); 293 | 294 | // The API defines event names in camel case. WinJS expects event names to be all lowercase. We'll fix the event names here. 295 | if (binding === BINDING_event) { 296 | property = property.toLowerCase(); 297 | } 298 | 299 | if (propertyValue !== undefined) { 300 | // We don't want to try setting read only properties on the WinJS control. BINDING_readonly_property and BINDING_selection are both read only. 301 | // BINDING_selection may not seem like it's read only at first glance, but that's only because we do extra work in this library to make it 302 | // seem like it's gettable and settable in Angular. 303 | if (binding !== BINDING_selection && 304 | binding !== BINDING_readonly_property) { 305 | controlOptions[property] = propertyValue; 306 | } 307 | } 308 | } 309 | 310 | return { 311 | options: controlOptions, 312 | bindings: bindings 313 | }; 314 | } 315 | 316 | function removeDuplicateAttributes(element, api) { 317 | // WinJS has a couple naming collisions with actual DOM attributes. When the control we're constructing has 318 | // these attributes on its DOM element, we'll remove them so the WinJS control can function as appropriate. 319 | var attributesToRemove = ["checked", "disabled", "hidden", "id", "title", "type"]; 320 | for (var i = 0, len = attributesToRemove.length; i < len; i++) { 321 | if (api.hasOwnProperty(attributesToRemove[i])) { 322 | element.removeAttribute(attributesToRemove[i]); 323 | } 324 | } 325 | } 326 | function initializeControl($scope, element, controlConstructor, api, extraOptions, onDestroyed) { 327 | removeDuplicateAttributes(element, api); 328 | 329 | var control, 330 | controlDetails = initializeControlBindings($scope, api, element, function () { return control; }); 331 | 332 | if (extraOptions) { 333 | for (var option in extraOptions) { 334 | controlDetails.options[option] = extraOptions[option]; 335 | } 336 | } 337 | 338 | control = new controlConstructor(element, controlDetails.options); 339 | addDestroyListener($scope, control, controlDetails.bindings, onDestroyed); 340 | return control; 341 | } 342 | 343 | // Shared compile/link functions 344 | function compileTemplate(name) { 345 | // Directive compile function 346 | return function (tElement, tAttrs, transclude) { 347 | var rootElement = document.createElement("div"); 348 | Object.keys(tAttrs).forEach(function (key) { 349 | if (key[0] !== '$') { 350 | rootElement.setAttribute(key, tAttrs[key]); 351 | } 352 | }); 353 | var immediateToken; 354 | // Directive link function 355 | return function ($scope, elements, attrs, parents) { 356 | var parent = parents.reduce(function (found, item) { return found || item; }); 357 | parent[name] = function (itemPromise) { 358 | // Actual item renderer 359 | return WinJS.Promise.as(itemPromise).then(function (item) { 360 | var itemScope = $scope.$new(); 361 | itemScope.item = item; 362 | var result = rootElement.cloneNode(false); 363 | transclude(itemScope, function (clonedElement) { 364 | for (var i = 0, len = clonedElement.length; i < len; i++) { 365 | result.appendChild(clonedElement[i]); 366 | } 367 | }); 368 | WinJS.Utilities.markDisposable(result, function () { 369 | itemScope.$destroy(); 370 | }); 371 | immediateToken = immediateToken || setImmediate(function () { 372 | immediateToken = null; 373 | itemScope.$apply(); 374 | }); 375 | return result; 376 | }) 377 | }; 378 | }; 379 | }; 380 | } 381 | 382 | // WinJS module definition 383 | var module = angular.module("winjs", []); 384 | 385 | module.config(['$compileProvider', function ($compileProvider) { 386 | switch (document.location.protocol.toLowerCase()) { 387 | // For reference on URI schemes refer to http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj655406.aspx 388 | case "ms-appx:": 389 | case "ms-appx-web:": 390 | // Whitelist the Windows Runtime URL schemes so Angular does not flag as 'unsafe'. 391 | var whitelist = /^\s*(http|https|ms-appx|ms-appx-web|ms-appdata):/i; 392 | $compileProvider.imgSrcSanitizationWhitelist(whitelist); 393 | $compileProvider.aHrefSanitizationWhitelist(whitelist); 394 | break; 395 | } 396 | }]); 397 | 398 | module.run(['$rootScope', function ($rootScope) { 399 | var Scope = Object.getPrototypeOf($rootScope); 400 | var Scope$eval = Scope.$eval; 401 | Scope.$eval = function (expr, locals) { 402 | var that = this; 403 | if (window.MSApp && MSApp.execUnsafeLocalFunction) { 404 | return MSApp.execUnsafeLocalFunction(function () { 405 | return Scope$eval.call(that, expr, locals); 406 | }); 407 | } else { 408 | return Scope$eval.call(that, expr, locals); 409 | } 410 | }; 411 | }]); 412 | 413 | function camelToDash(string) { 414 | return string.replace(/[A-Z]/g, function (letter) { 415 | return "-" + letter.toLowerCase(); 416 | }); 417 | } 418 | 419 | function createHelperDirective(requires, directiveName) { 420 | var helperClassName = camelToDash(directiveName); 421 | module.directive(directiveName, function () { 422 | return { 423 | require: "^" + requires, 424 | restrict: "E", 425 | replace: true, 426 | transclude: true, 427 | template: "
" 428 | }; 429 | }); 430 | } 431 | 432 | function extractHelperDirectiveElements(parentNode, directiveName) { 433 | var elements = parentNode.querySelectorAll("." + camelToDash(directiveName)); 434 | for (var i = 0, len = elements.length; i < len; i++) { 435 | elements[i].parentNode.removeChild(elements[i]); 436 | } 437 | return elements; 438 | } 439 | 440 | function getHelperDirectives(parentNode, directives) { 441 | var directivesFound = {}; 442 | directives.forEach(function (directive) { 443 | var matchingElements = extractHelperDirectiveElements(parentNode, directive.directiveName); 444 | if (matchingElements.length > 0) { 445 | directivesFound[directive.controlOptionName] = matchingElements[0]; 446 | } 447 | }); 448 | return directivesFound; 449 | } 450 | 451 | // Directives 452 | exists("AppBar") && module.directive("winAppBar", ['$parse', function ($parse) { 453 | var api = { 454 | closedDisplayMode: BINDING_property, 455 | data: BINDING_property, 456 | opened: BINDING_property, 457 | placement: BINDING_property, 458 | onAfterClose: BINDING_event, 459 | onAfterOpen: BINDING_event, 460 | onBeforeClose: BINDING_event, 461 | onBeforeOpen: BINDING_event 462 | }; 463 | return { 464 | restrict: "E", 465 | replace: true, 466 | scope: getScopeForAPI(api), 467 | template: "
", 468 | transclude: true, 469 | link: function ($scope, elements, attrs) { 470 | var control = initializeControl($scope, elements[0], WinJS.UI.AppBar, api); 471 | 472 | function onVisibilityChanged() { 473 | apply($scope, function () { 474 | $scope["opened"] = control["opened"]; 475 | }); 476 | } 477 | 478 | control.addEventListener("afteropen", onVisibilityChanged); 479 | control.addEventListener("afterclose", onVisibilityChanged); 480 | } 481 | }; 482 | }]); 483 | 484 | exists("AppBar") && module.directive("winAppBarCommand", function () { 485 | var api = { 486 | disabled: BINDING_property, 487 | extraClass: BINDING_property, 488 | firstElementFocus: BINDING_property, 489 | flyout: BINDING_property, 490 | hidden: BINDING_property, 491 | icon: BINDING_property, 492 | id: BINDING_property, 493 | label: BINDING_property, 494 | lastElementFocus: BINDING_property, 495 | priority: BINDING_property, 496 | section: BINDING_property, 497 | selected: BINDING_property, 498 | tooltip: BINDING_property, 499 | type: BINDING_property, 500 | onClick: BINDING_event 501 | }; 502 | return { 503 | restrict: "E", 504 | replace: true, 505 | scope: getScopeForAPI(api), 506 | template: "", 507 | transclude: true, 508 | link: function ($scope, elements) { 509 | initializeControl($scope, elements[0], WinJS.UI.Command, api); 510 | } 511 | }; 512 | }); 513 | 514 | exists("AppBar") && module.directive("winAppBarSeparator", function () { 515 | var api = { 516 | disabled: BINDING_property, 517 | extraClass: BINDING_property, 518 | firstElementFocus: BINDING_property, 519 | flyout: BINDING_property, 520 | hidden: BINDING_property, 521 | icon: BINDING_property, 522 | id: BINDING_property, 523 | label: BINDING_property, 524 | lastElementFocus: BINDING_property, 525 | priority: BINDING_property, 526 | section: BINDING_property, 527 | selected: BINDING_property, 528 | tooltip: BINDING_property, 529 | type: BINDING_property, 530 | onClick: BINDING_event 531 | }; 532 | return { 533 | restrict: "E", 534 | replace: true, 535 | scope: getScopeForAPI(api), 536 | template: "
", 537 | transclude: true, 538 | link: function ($scope, elements) { 539 | initializeControl($scope, elements[0], WinJS.UI.Command, api, { type: "separator" }); 540 | } 541 | }; 542 | }); 543 | 544 | exists("AppBar") && module.directive("winAppBarContent", function () { 545 | var api = { 546 | disabled: BINDING_property, 547 | extraClass: BINDING_property, 548 | firstElementFocus: BINDING_property, 549 | flyout: BINDING_property, 550 | hidden: BINDING_property, 551 | icon: BINDING_property, 552 | id: BINDING_property, 553 | label: BINDING_property, 554 | lastElementFocus: BINDING_property, 555 | priority: BINDING_property, 556 | section: BINDING_property, 557 | selected: BINDING_property, 558 | tooltip: BINDING_property, 559 | type: BINDING_property, 560 | onClick: BINDING_event 561 | }; 562 | return { 563 | restrict: "E", 564 | replace: true, 565 | scope: getScopeForAPI(api), 566 | template: "
", 567 | transclude: true, 568 | link: function ($scope, elements) { 569 | initializeControl($scope, elements[0], WinJS.UI.Command, api, { type: "content" }); 570 | } 571 | }; 572 | }); 573 | 574 | exists("AutoSuggestBox") && module.directive("winAutoSuggestBox", function () { 575 | var api = { 576 | chooseSuggestionOnEnter: BINDING_property, 577 | disabled: BINDING_property, 578 | placeholderText: BINDING_property, 579 | queryText: BINDING_property, 580 | searchHistoryContext: BINDING_property, 581 | searchHistoryDisabled: BINDING_property, 582 | onQueryChanged: BINDING_event, 583 | onQuerySubmitted: BINDING_event, 584 | onResultSuggestionChosen: BINDING_event, 585 | onSuggestionsRequested: BINDING_event 586 | }; 587 | return { 588 | restrict: "E", 589 | replace: true, 590 | scope: getScopeForAPI(api), 591 | template: "
", 592 | link: function ($scope, elements, attrs) { 593 | var control = initializeControl($scope, elements[0], WinJS.UI.AutoSuggestBox, api); 594 | 595 | control.addEventListener("querychanged", function () { 596 | apply($scope, function () { 597 | $scope["queryText"] = control["queryText"]; 598 | }); 599 | }); 600 | } 601 | }; 602 | }); 603 | 604 | exists("BackButton") && module.directive("winBackButton", function () { 605 | return { 606 | restrict: "E", 607 | replace: true, 608 | template: "", 609 | link: function ($scope, elements) { 610 | var control = new WinJS.UI.BackButton(elements[0]); 611 | } 612 | }; 613 | }); 614 | 615 | exists("CellSpanningLayout") && module.directive("winCellSpanningLayout", function () { 616 | var api = { 617 | groupHeaderPosition: BINDING_property, 618 | groupInfo: BINDING_property, 619 | itemInfo: BINDING_property, 620 | maximumRowsOrColumns: BINDING_property, 621 | orientation: BINDING_property 622 | }; 623 | return { 624 | require: "^winListView", 625 | restrict: "E", 626 | replace: true, 627 | template: "", 628 | scope: getScopeForAPI(api), 629 | link: function ($scope, elements, attrs, listView) { 630 | var layout; 631 | var controlBindings = initializeControlBindings($scope, api, null, function () { return layout; }) 632 | layout = listView.layout = new WinJS.UI.CellSpanningLayout(controlBindings.options); 633 | addDestroyListener($scope, layout, controlBindings.bindings); 634 | } 635 | }; 636 | }); 637 | 638 | exists("ContentDialog") && module.directive("winContentDialog", function () { 639 | var api = { 640 | hidden: BINDING_property, 641 | primaryCommandText: BINDING_property, 642 | primaryCommandDisabled: BINDING_property, 643 | secondaryCommandText: BINDING_property, 644 | secondaryCommandDisabled: BINDING_property, 645 | title: BINDING_property, 646 | onAfterHide: BINDING_event, 647 | onAfterShow: BINDING_event, 648 | onBeforeHide: BINDING_event, 649 | onBeforeShow: BINDING_event 650 | }; 651 | return { 652 | restrict: "E", 653 | replace: true, 654 | scope: getScopeForAPI(api), 655 | template: "
", 656 | transclude: true, 657 | link: function ($scope, elements, attrs) { 658 | var control = initializeControl($scope, elements[0], WinJS.UI.ContentDialog, api); 659 | 660 | function onVisibilityChanged() { 661 | apply($scope, function () { 662 | $scope["hidden"] = control["hidden"]; 663 | }); 664 | } 665 | 666 | control.addEventListener("afterhide", onVisibilityChanged); 667 | control.addEventListener("aftershow", onVisibilityChanged); 668 | } 669 | }; 670 | }); 671 | 672 | exists("DatePicker") && module.directive("winDatePicker", function () { 673 | var api = { 674 | calendar: BINDING_property, 675 | current: BINDING_property, 676 | datePattern: BINDING_property, 677 | disabled: BINDING_property, 678 | maxYear: BINDING_property, 679 | minYear: BINDING_property, 680 | monthPattern: BINDING_property, 681 | yearPattern: BINDING_property, 682 | onChange: BINDING_event 683 | }; 684 | return { 685 | restrict: "E", 686 | replace: true, 687 | scope: getScopeForAPI(api), 688 | template: "
", 689 | link: function ($scope, elements) { 690 | var control = initializeControl($scope, elements[0], WinJS.UI.DatePicker, api); 691 | 692 | control.addEventListener("change", function () { 693 | apply($scope, function () { 694 | $scope["current"] = control["current"]; 695 | }); 696 | }); 697 | } 698 | }; 699 | }); 700 | 701 | exists("FlipView") && module.directive("winFlipView", function () { 702 | var api = { 703 | currentPage: BINDING_property, 704 | itemDataSource: BINDING_dataSource, 705 | itemSpacing: BINDING_property, 706 | itemTemplate: BINDING_property, 707 | orientation: BINDING_property, 708 | onDataSourceCountChanged: BINDING_event, 709 | onPageCompleted: BINDING_event, 710 | onPageSelected: BINDING_event, 711 | onPageVisibilityChanged: BINDING_event 712 | }; 713 | return { 714 | restrict: "E", 715 | replace: true, 716 | scope: getScopeForAPI(api), 717 | template: "
", 718 | transclude: true, 719 | controller: ['$scope', function ($scope) { 720 | proxy($scope, this, "itemTemplate"); 721 | }], 722 | link: function ($scope, elements, attrs) { 723 | var control = initializeControl($scope, elements[0], WinJS.UI.FlipView, api); 724 | 725 | control.addEventListener("pageselected", function () { 726 | apply($scope, function () { 727 | $scope["currentPage"] = control["currentPage"]; 728 | }); 729 | }); 730 | } 731 | }; 732 | }); 733 | 734 | exists("Flyout") && module.directive("winFlyout", ['$parse', function ($parse) { 735 | var api = { 736 | alignment: BINDING_property, 737 | anchor: BINDING_anchor, 738 | disabled: BINDING_property, 739 | hidden: BINDING_property, 740 | placement: BINDING_property, 741 | onAfterHide: BINDING_event, 742 | onAfterShow: BINDING_event, 743 | onBeforeHide: BINDING_event, 744 | onBeforeShow: BINDING_event 745 | }; 746 | return { 747 | restrict: "E", 748 | replace: true, 749 | scope: getScopeForAPI(api), 750 | template: "
", 751 | transclude: true, 752 | link: function ($scope, elements, attrs) { 753 | var control = initializeControl($scope, elements[0], WinJS.UI.Flyout, api); 754 | 755 | function onVisibilityChanged() { 756 | apply($scope, function () { 757 | $scope["hidden"] = control["hidden"]; 758 | }); 759 | } 760 | 761 | control.addEventListener("afterhide", onVisibilityChanged); 762 | control.addEventListener("aftershow", onVisibilityChanged); 763 | } 764 | }; 765 | }]); 766 | 767 | exists("GridLayout") && module.directive("winGridLayout", function () { 768 | var api = { 769 | groupHeaderPosition: BINDING_property, 770 | maximumRowsOrColumns: BINDING_property, 771 | orientation: BINDING_property 772 | }; 773 | return { 774 | require: "^winListView", 775 | restrict: "E", 776 | replace: true, 777 | template: "", 778 | scope: getScopeForAPI(api), 779 | link: function ($scope, elements, attrs, listView) { 780 | var layout; 781 | var controlBindings = initializeControlBindings($scope, api, null, function () { return layout; }) 782 | layout = listView.layout = new WinJS.UI.GridLayout(controlBindings.options); 783 | addDestroyListener($scope, layout, controlBindings.bindings); 784 | return layout; 785 | } 786 | }; 787 | }); 788 | 789 | exists("ListView") && module.directive("winGroupHeaderTemplate", function () { 790 | return { 791 | require: ["^?winListView"], 792 | restrict: "E", 793 | replace: true, 794 | transclude: true, 795 | compile: compileTemplate("groupHeaderTemplate") 796 | }; 797 | }); 798 | 799 | exists("Hub") && module.directive("winHub", function () { 800 | var api = { 801 | headerTemplate: BINDING_property, 802 | indexOfFirstVisible: BINDING_readonly_property, 803 | indexOfLastVisible: BINDING_readonly_property, 804 | loadingState: BINDING_readonly_property, 805 | orientation: BINDING_property, 806 | scrollPosition: BINDING_property, 807 | sectionOnScreen: BINDING_property, 808 | sections: BINDING_property, 809 | onContentAnimating: BINDING_event, 810 | onHeaderInvoked: BINDING_event, 811 | onLoadingStateChanged: BINDING_event 812 | }; 813 | return { 814 | restrict: "E", 815 | replace: true, 816 | scope: getScopeForAPI(api), 817 | template: "
", 818 | transclude: true, 819 | controller: ['$scope', function ($scope) { 820 | // The children will (may) call back before the Hub is constructed so we queue up the calls to 821 | // addSection and removeSection and execute them later. 822 | $scope.deferredCalls = []; 823 | function deferred(wrapped) { 824 | return function () { 825 | var f = Function.prototype.apply.bind(wrapped, null, arguments); 826 | if ($scope.deferredCalls) { 827 | $scope.deferredCalls.push(f); 828 | } else { 829 | f(); 830 | } 831 | } 832 | } 833 | proxy($scope, this, "headerTemplate"); 834 | this.addSection = deferred(function (section, index) { 835 | $scope.addSection(section, index); 836 | }); 837 | this.removeSection = deferred(function (section) { 838 | $scope.removeSection(section); 839 | }); 840 | }], 841 | link: function ($scope, elements) { 842 | var element = elements[0]; 843 | // NOTE: the Hub will complain if this is in the DOM when it is constructed so we temporarially remove it. 844 | // It must be in the DOM when repeaters run and hosted under the hub. 845 | var sectionsHost = element.firstElementChild; 846 | sectionsHost.parentNode.removeChild(sectionsHost); 847 | var control = initializeControl($scope, element, WinJS.UI.Hub, api); 848 | 849 | element.appendChild(sectionsHost); 850 | $scope.addSection = function (section, index) { 851 | control.sections.splice(index, 0, section); 852 | }; 853 | $scope.removeSection = function (section) { 854 | control.sections.splice(control.sections.indexOf(section), 1); 855 | }; 856 | $scope.deferredCalls.forEach(function (f) { f(); }); 857 | $scope.deferredCalls = null; 858 | control.addEventListener("loadingstatechanged", function () { 859 | apply($scope, function () { 860 | $scope["loadingState"] = control["loadingState"]; 861 | }); 862 | }); 863 | } 864 | }; 865 | }); 866 | 867 | exists("HubSection") && module.directive("winHubSection", function () { 868 | var api = { 869 | header: BINDING_property, 870 | isHeaderStatic: BINDING_property 871 | }; 872 | return { 873 | restrict: "E", 874 | require: "^winHub", 875 | replace: true, 876 | scope: getScopeForAPI(api), 877 | // NOTE: there is an arbitrary wrapper here .placeholder which is used in scenarios where developers stamp 878 | // out hub sections using ng-repeat. In order to support things like that we need to infer the order 879 | // that the sections are in relative to static sections so we manage them in a .placeholder-holder 880 | // element (see winHub directive above), the placeholder always lives in that thing. The content 881 | // (meaning the real hub section) ends up being owned by the Hub. 882 | template: "
", 883 | transclude: true, 884 | link: function ($scope, elements, attrs, hub) { 885 | var placeholder = elements[0]; 886 | var element = placeholder.firstElementChild; 887 | var control = initializeControl($scope, element, WinJS.UI.HubSection, api, {}, function () { 888 | hub.removeSection(control); 889 | }); 890 | 891 | hub.addSection(control, Array.prototype.indexOf.call(placeholder.parentNode.children, placeholder)); 892 | } 893 | }; 894 | }); 895 | 896 | exists("ItemContainer") && module.directive("winItemContainer", function () { 897 | var api = { 898 | draggable: BINDING_property, 899 | selected: BINDING_property, 900 | selectionDisabled: BINDING_property, 901 | tapBehavior: BINDING_property, 902 | onInvoked: BINDING_event, 903 | onSelectionChanged: BINDING_event, 904 | onSelectionChanging: BINDING_event 905 | }; 906 | return { 907 | restrict: "E", 908 | replace: true, 909 | scope: getScopeForAPI(api), 910 | template: "
", 911 | transclude: true, 912 | link: function ($scope, elements) { 913 | var control = initializeControl($scope, elements[0], WinJS.UI.ItemContainer, api); 914 | 915 | control.addEventListener("selectionchanged", function () { 916 | apply($scope, function () { 917 | $scope["selected"] = control["selected"]; 918 | }); 919 | }); 920 | } 921 | }; 922 | }); 923 | 924 | (exists("ListView") || exists("FlipView")) && module.directive("winItemTemplate", function () { 925 | return { 926 | require: ["^?winListView", "^?winFlipView"], 927 | restrict: "E", 928 | replace: true, 929 | transclude: true, 930 | compile: compileTemplate("itemTemplate") 931 | }; 932 | }); 933 | 934 | exists("ListLayout") && module.directive("winListLayout", function () { 935 | var api = { 936 | groupHeaderPosition: BINDING_property, 937 | orientation: BINDING_property 938 | }; 939 | return { 940 | require: "^winListView", 941 | restrict: "E", 942 | replace: true, 943 | template: "", 944 | scope: getScopeForAPI(api), 945 | link: function ($scope, elements, attrs, listView) { 946 | var layout; 947 | var controlBindings = initializeControlBindings($scope, api, null, function () { return layout; }) 948 | layout = listView.layout = new WinJS.UI.ListLayout(controlBindings.options); 949 | addDestroyListener($scope, layout, controlBindings.bindings); 950 | } 951 | }; 952 | }); 953 | 954 | var listViewHelperDirectives = [ 955 | { 956 | controlOptionName: "header", 957 | directiveName: "winListViewHeader" 958 | }, 959 | { 960 | controlOptionName: "footer", 961 | directiveName: "winListViewFooter" 962 | } 963 | ]; 964 | exists("ListView") && module.directive("winListView", function () { 965 | var api = { 966 | currentItem: BINDING_property, 967 | footer: BINDING_property, 968 | groupDataSource: BINDING_dataSource, 969 | groupHeaderTemplate: BINDING_property, 970 | groupHeaderTapBehavior: BINDING_property, 971 | header: BINDING_property, 972 | indexOfFirstVisible: BINDING_property, 973 | indexOfLastVisible: BINDING_property, 974 | itemDataSource: BINDING_dataSource, 975 | itemsDraggable: BINDING_property, 976 | itemsReorderable: BINDING_property, 977 | itemTemplate: BINDING_property, 978 | layout: BINDING_property, 979 | maxDeferredItemCleanup: BINDING_property, 980 | maxLeadingPages: BINDING_property, 981 | maxTrailingPages: BINDING_property, 982 | scrollPosition: BINDING_property, 983 | selection: BINDING_selection, 984 | selectionMode: BINDING_property, 985 | tapBehavior: BINDING_property, 986 | onContentAnimating: BINDING_event, 987 | onFooterVisibilityChanged: BINDING_event, 988 | onGroupHeaderInvoked: BINDING_event, 989 | onHeaderVisibilityChanged: BINDING_event, 990 | onAccessibilityAnnotationComplete: BINDING_event, 991 | onItemDragStart: BINDING_event, 992 | onItemDragEnter: BINDING_event, 993 | onItemDragBetween: BINDING_event, 994 | onItemDragLeave: BINDING_event, 995 | onItemDragChanged: BINDING_event, 996 | onItemDragDrop: BINDING_event, 997 | onItemInvoked: BINDING_event, 998 | onKeyboardNavigating: BINDING_event, 999 | onLoadingStateChanged: BINDING_event, 1000 | onSelectionChanged: BINDING_event, 1001 | onSelectionChanging: BINDING_event 1002 | }; 1003 | return { 1004 | restrict: "E", 1005 | replace: true, 1006 | scope: getScopeForAPI(api), 1007 | template: "
", 1008 | transclude: true, 1009 | controller: ['$scope', function ($scope) { 1010 | proxy($scope, this, "itemTemplate"); 1011 | proxy($scope, this, "groupHeaderTemplate"); 1012 | proxy($scope, this, "layout"); 1013 | proxy($scope, this, "selection"); 1014 | }], 1015 | link: function ($scope, elements, attrs) { 1016 | var element = elements[0]; 1017 | var control = initializeControl($scope, element, WinJS.UI.ListView, api, getHelperDirectives(element, listViewHelperDirectives)); 1018 | 1019 | control.addEventListener("selectionchanged", function () { 1020 | var value = $scope["selection"]; 1021 | if (value) { 1022 | apply($scope, function () { 1023 | var current = control.selection.getIndices(); 1024 | value.length = 0; 1025 | current.forEach(function (item) { 1026 | value.push(item); 1027 | }); 1028 | }); 1029 | } 1030 | }); 1031 | } 1032 | }; 1033 | }); 1034 | exists("ListView") && listViewHelperDirectives.forEach(function (directive) { 1035 | createHelperDirective("winListView", directive.directiveName); 1036 | }); 1037 | 1038 | exists("Menu") && module.directive("winMenu", ['$parse', function ($parse) { 1039 | var api = { 1040 | alignment: BINDING_property, 1041 | anchor: BINDING_anchor, 1042 | commands: BINDING_property, 1043 | disabled: BINDING_property, 1044 | hidden: BINDING_property, 1045 | placement: BINDING_property, 1046 | onAfterHide: BINDING_event, 1047 | onAfterShow: BINDING_event, 1048 | onBeforeHide: BINDING_event, 1049 | onBeforeShow: BINDING_event 1050 | }; 1051 | return { 1052 | restrict: "E", 1053 | replace: true, 1054 | scope: getScopeForAPI(api), 1055 | template: "
", 1056 | transclude: true, 1057 | link: function ($scope, elements, attrs) { 1058 | var control = initializeControl($scope, elements[0], WinJS.UI.Menu, api); 1059 | 1060 | function onVisibilityChanged() { 1061 | apply($scope, function () { 1062 | $scope["hidden"] = control["hidden"]; 1063 | }); 1064 | } 1065 | 1066 | control.addEventListener("afterhide", onVisibilityChanged); 1067 | control.addEventListener("aftershow", onVisibilityChanged); 1068 | } 1069 | }; 1070 | }]); 1071 | 1072 | exists("MenuCommand") && module.directive("winMenuCommand", function () { 1073 | var api = { 1074 | disabled: BINDING_property, 1075 | extraClass: BINDING_property, 1076 | flyout: BINDING_property, 1077 | hidden: BINDING_property, 1078 | id: BINDING_property, 1079 | label: BINDING_property, 1080 | section: BINDING_property, 1081 | selected: BINDING_property, 1082 | type: BINDING_property, 1083 | onClick: BINDING_event 1084 | }; 1085 | return { 1086 | restrict: "E", 1087 | replace: true, 1088 | scope: getScopeForAPI(api), 1089 | template: "", 1090 | link: function ($scope, elements) { 1091 | initializeControl($scope, elements[0], WinJS.UI.MenuCommand, api); 1092 | } 1093 | }; 1094 | }); 1095 | 1096 | var pivotHelperDirectives = [ 1097 | { 1098 | controlOptionName: "customLeftHeader", 1099 | directiveName: "winPivotLeftHeader" 1100 | }, 1101 | { 1102 | controlOptionName: "customRightHeader", 1103 | directiveName: "winPivotRightHeader" 1104 | } 1105 | ]; 1106 | exists("Pivot") && module.directive("winPivot", function () { 1107 | var api = { 1108 | customLeftHeader: BINDING_property, 1109 | customRightHeader: BINDING_property, 1110 | items: BINDING_property, 1111 | locked: BINDING_property, 1112 | selectedIndex: BINDING_property, 1113 | selectedItem: BINDING_property, 1114 | title: BINDING_property, 1115 | onItemAnimationEnd: BINDING_event, 1116 | onItemAnimationStart: BINDING_event, 1117 | onSelectionChanged: BINDING_event 1118 | }; 1119 | return { 1120 | restrict: "E", 1121 | replace: true, 1122 | scope: getScopeForAPI(api), 1123 | template: "
", 1124 | transclude: true, 1125 | controller: ['$scope', function ($scope) { 1126 | // The children will (may) call back before the Pivot is constructed so we queue up the calls to 1127 | // addItem and removeItem and execute them later. 1128 | $scope.deferredCalls = []; 1129 | function deferred(wrapped) { 1130 | return function () { 1131 | var f = Function.prototype.apply.bind(wrapped, null, arguments); 1132 | if ($scope.deferredCalls) { 1133 | $scope.deferredCalls.push(f); 1134 | } else { 1135 | f(); 1136 | } 1137 | } 1138 | } 1139 | this.addItem = deferred(function (item, index, addedCallback) { 1140 | $scope.addItem(item, index, addedCallback); 1141 | }); 1142 | this.removeItem = deferred(function (item) { 1143 | $scope.removeItem(item); 1144 | }); 1145 | }], 1146 | link: function ($scope, elements) { 1147 | var element = elements[0]; 1148 | var helperDirectives = getHelperDirectives(element, pivotHelperDirectives); 1149 | // NOTE: the Pivot will complain if this is in the DOM when it is constructed so we temporarially remove it. 1150 | // It must be in the DOM when repeaters run and hosted under the pivot. 1151 | var itemsHost = element.firstElementChild; 1152 | itemsHost.parentNode.removeChild(itemsHost); 1153 | var control = initializeControl($scope, element, WinJS.UI.Pivot, api, helperDirectives); 1154 | 1155 | element.appendChild(itemsHost); 1156 | $scope.addItem = function (item, index, addedCallback) { 1157 | control.items.splice(index, 0, item); 1158 | addedCallback(); 1159 | }; 1160 | $scope.removeItem = function (item) { 1161 | control.items.splice(control.items.indexOf(item), 1); 1162 | }; 1163 | $scope.deferredCalls.forEach(function (f) { f(); }); 1164 | $scope.deferredCalls = null; 1165 | } 1166 | }; 1167 | }); 1168 | exists("Pivot") && pivotHelperDirectives.forEach(function (directive) { 1169 | createHelperDirective("winPivot", directive.directiveName); 1170 | }); 1171 | 1172 | exists("PivotItem") && module.directive("winPivotItem", function () { 1173 | var api = { 1174 | header: BINDING_property 1175 | }; 1176 | return { 1177 | restrict: "E", 1178 | require: "^winPivot", 1179 | replace: true, 1180 | scope: getScopeForAPI(api), 1181 | // NOTE: there is an arbitrary wrapper here .placeholder which is used in scenarios where developers stamp 1182 | // out pivot sections using ng-repeat. In order to support things like that we need to infer the order 1183 | // that the sections are in relative to static sections so we manage them in a .placeholder-holder 1184 | // element (see winPivot directive above), the placeholder always lives in that thing. The content 1185 | // (meaning the real pivot section) ends up being owned by the Hub. 1186 | template: "
", 1187 | transclude: true, 1188 | link: function ($scope, elements, attrs, pivot) { 1189 | var placeholder = elements[0], 1190 | element = placeholder.firstElementChild; 1191 | 1192 | // PivotItems try to communicate with the Pivot control they're instantiated into. This is okay when the Pivot hasn't yet been constructed, 1193 | // but if it has been constructed this will cause problems inside of the Pivot, because the PivotItem will try to set its header in the Pivot 1194 | // before the Pivot has been made aware of its existence via this wrapper's addItem implementation. 1195 | // Ideally we would handle this by removing the PivotItem temporarily from the DOM and adding it in post-initialization, but if we do that 1196 | // we'll cause problems with other WinJS controls that may be hosted in the PivotItem. To solve this problem without doing DOM manipulation, 1197 | // we'll break the PivotItem initialization up into two stages: We will construct the PivotItem manually without any options and allow that blank 1198 | // PivotItem to be processed by its parent Pivot. Once that processing is done and addItem is completed, we'll complete the initialization by 1199 | // setting the PivotItem's options 1200 | removeDuplicateAttributes(element, api); 1201 | var control = initializeControl($scope, element, WinJS.UI.PivotItem, {}, {}); 1202 | 1203 | pivot.addItem(control, Array.prototype.indexOf.call(placeholder.parentNode.children, placeholder), function () { 1204 | var controlDetails = initializeControlBindings($scope, api, element, function () { return control; }); 1205 | 1206 | WinJS.UI.setOptions(control, controlDetails.options); 1207 | addDestroyListener($scope, control, controlDetails.bindings, function () { 1208 | pivot.removeItem(control); 1209 | }); 1210 | 1211 | }); 1212 | } 1213 | }; 1214 | }); 1215 | 1216 | exists("Rating") && module.directive("winRating", function () { 1217 | var api = { 1218 | averageRating: BINDING_property, 1219 | disabled: BINDING_property, 1220 | enableClear: BINDING_property, 1221 | maxRating: BINDING_property, 1222 | tooltipStrings: BINDING_property, 1223 | userRating: BINDING_property, 1224 | onCancel: BINDING_event, 1225 | onChange: BINDING_event, 1226 | onPreviewChange: BINDING_event 1227 | }; 1228 | return { 1229 | restrict: "E", 1230 | replace: true, 1231 | scope: getScopeForAPI(api), 1232 | template: "
", 1233 | link: function ($scope, elements) { 1234 | var control = initializeControl($scope, elements[0], WinJS.UI.Rating, api); 1235 | 1236 | control.addEventListener("change", function () { 1237 | apply($scope, function () { 1238 | $scope["userRating"] = control["userRating"]; 1239 | }); 1240 | }); 1241 | } 1242 | }; 1243 | }); 1244 | 1245 | exists("SectionHeaderTemplate") && module.directive("winSectionHeaderTemplate", function () { 1246 | return { 1247 | require: ["^?winHub"], 1248 | restrict: "E", 1249 | replace: true, 1250 | transclude: true, 1251 | compile: compileTemplate("headerTemplate") 1252 | }; 1253 | }); 1254 | 1255 | exists("SemanticZoom") && module.directive("winSemanticZoom", function () { 1256 | var api = { 1257 | enableButton: BINDING_property, 1258 | locked: BINDING_property, 1259 | zoomedOut: BINDING_property, 1260 | zoomFactor: BINDING_property, 1261 | onZoomChanged: BINDING_event 1262 | }; 1263 | return { 1264 | restrict: "E", 1265 | replace: true, 1266 | scope: getScopeForAPI(api), 1267 | template: "
", 1268 | transclude: true, 1269 | link: function ($scope, elements) { 1270 | initializeControl($scope, elements[0], WinJS.UI.SemanticZoom, api); 1271 | 1272 | } 1273 | }; 1274 | }); 1275 | 1276 | exists("SplitView") && module.directive("winSplitView", ['$parse', function ($parse) { 1277 | var api = { 1278 | closedDisplayMode: BINDING_property, 1279 | openedDisplayMode: BINDING_property, 1280 | paneOpened: BINDING_property, 1281 | panePlacement: BINDING_property, 1282 | onBeforeOpen: BINDING_event, 1283 | onAfterOpen: BINDING_event, 1284 | onBeforeClose: BINDING_event, 1285 | onAfterClose: BINDING_event 1286 | }; 1287 | return { 1288 | restrict: "E", 1289 | replace: true, 1290 | scope: getScopeForAPI(api), 1291 | template: "
", 1292 | transclude: true, 1293 | link: function ($scope, elements, attrs) { 1294 | var element = elements[0], 1295 | paneElement, 1296 | contentElements = []; 1297 | var children = element.children; 1298 | while (element.firstElementChild) { 1299 | var currentElement = element.firstElementChild; 1300 | element.removeChild(currentElement); 1301 | if (currentElement.classList.contains("win-split-view-pane")) { 1302 | currentElement.classList.remove("win-split-view-pane"); 1303 | if (!paneElement) { 1304 | paneElement = currentElement; 1305 | } 1306 | } else if (currentElement.classList.contains("win-split-view-content")) { 1307 | currentElement.classList.remove("win-split-view-content"); 1308 | contentElements.push(currentElement); 1309 | } 1310 | } 1311 | 1312 | var control = initializeControl($scope, element, WinJS.UI.SplitView, api); 1313 | 1314 | if (paneElement) { 1315 | control.paneElement.appendChild(paneElement); 1316 | } 1317 | for (var i = 0; i < contentElements.length; i++) { 1318 | control.contentElement.appendChild(contentElements[i]); 1319 | } 1320 | 1321 | function onVisibilityChanged() { 1322 | apply($scope, function () { 1323 | $scope["paneOpened"] = control["paneOpened"]; 1324 | }); 1325 | } 1326 | 1327 | control.addEventListener("afteropen", onVisibilityChanged); 1328 | control.addEventListener("afterclose", onVisibilityChanged); 1329 | } 1330 | }; 1331 | }]); 1332 | 1333 | exists("SplitView") && module.directive("winSplitViewPane", function () { 1334 | return { 1335 | require: "^winSplitView", 1336 | restrict: "E", 1337 | replace: true, 1338 | transclude: true, 1339 | template: "
" 1340 | }; 1341 | }); 1342 | 1343 | exists("SplitView") && module.directive("winSplitViewContent", function () { 1344 | return { 1345 | require: "^winSplitView", 1346 | restrict: "E", 1347 | replace: true, 1348 | transclude: true, 1349 | template: "
" 1350 | }; 1351 | }); 1352 | 1353 | exists("SplitViewPaneToggle") && module.directive("winSplitViewPaneToggle", function () { 1354 | var api = { 1355 | splitView: BINDING_property, 1356 | onInvoked: BINDING_event, 1357 | }; 1358 | return { 1359 | restrict: "E", 1360 | replace: true, 1361 | scope: getScopeForAPI(api), 1362 | template: "", 1363 | transclude: true, 1364 | link: function ($scope, elements) { 1365 | initializeControl($scope, elements[0], WinJS.UI.SplitViewPaneToggle, api); 1366 | } 1367 | }; 1368 | }); 1369 | 1370 | exists("SplitViewCommand") && module.directive("winSplitViewCommand", function () { 1371 | var api = { 1372 | icon: BINDING_property, 1373 | label: BINDING_property, 1374 | tooltip: BINDING_property, 1375 | onInvoked: BINDING_event, 1376 | }; 1377 | return { 1378 | restrict: "E", 1379 | replace: true, 1380 | scope: getScopeForAPI(api), 1381 | template: "
", 1382 | transclude: true, 1383 | link: function ($scope, elements) { 1384 | initializeControl($scope, elements[0], WinJS.UI.SplitViewCommand, api); 1385 | } 1386 | }; 1387 | }); 1388 | 1389 | exists("TimePicker") && module.directive("winTimePicker", function () { 1390 | var api = { 1391 | clock: BINDING_property, 1392 | current: BINDING_property, 1393 | disabled: BINDING_property, 1394 | hourPattern: BINDING_property, 1395 | minuteIncrement: BINDING_property, 1396 | minutePattern: BINDING_property, 1397 | periodPattern: BINDING_property, 1398 | onChange: BINDING_event 1399 | }; 1400 | return { 1401 | restrict: "E", 1402 | replace: true, 1403 | scope: getScopeForAPI(api), 1404 | template: "
", 1405 | link: function ($scope, elements) { 1406 | var control = initializeControl($scope, elements[0], WinJS.UI.TimePicker, api); 1407 | 1408 | control.addEventListener("change", function () { 1409 | apply($scope, function () { 1410 | $scope["current"] = control["current"]; 1411 | }); 1412 | }); 1413 | } 1414 | }; 1415 | }); 1416 | 1417 | exists("ToggleSwitch") && module.directive("winToggleSwitch", function () { 1418 | var api = { 1419 | checked: BINDING_property, 1420 | disabled: BINDING_property, 1421 | labelOff: BINDING_property, 1422 | labelOn: BINDING_property, 1423 | title: BINDING_property, 1424 | onChange: BINDING_event 1425 | }; 1426 | return { 1427 | restrict: "E", 1428 | replace: true, 1429 | scope: getScopeForAPI(api), 1430 | template: "
", 1431 | link: function ($scope, elements) { 1432 | var control = initializeControl($scope, elements[0], WinJS.UI.ToggleSwitch, api); 1433 | 1434 | control.addEventListener("change", function () { 1435 | apply($scope, function () { 1436 | $scope["checked"] = control["checked"]; 1437 | }); 1438 | }); 1439 | } 1440 | }; 1441 | }); 1442 | 1443 | exists("ToolBar") && module.directive("winToolBar", function () { 1444 | var api = { 1445 | closedDisplayMode: BINDING_property, 1446 | data: BINDING_property, 1447 | opened: BINDING_property, 1448 | onAfterClose: BINDING_event, 1449 | onAfterOpen: BINDING_event, 1450 | onBeforeClose: BINDING_event, 1451 | onBeforeOpen: BINDING_event 1452 | }; 1453 | return { 1454 | restrict: "E", 1455 | replace: true, 1456 | scope: getScopeForAPI(api), 1457 | template: "
", 1458 | transclude: true, 1459 | link: function ($scope, elements, attrs) { 1460 | var control = initializeControl($scope, elements[0], WinJS.UI.ToolBar, api); 1461 | 1462 | function onVisibilityChanged() { 1463 | apply($scope, function () { 1464 | $scope["opened"] = control["opened"]; 1465 | }); 1466 | } 1467 | 1468 | control.addEventListener("afteropen", onVisibilityChanged); 1469 | control.addEventListener("afterclose", onVisibilityChanged); 1470 | } 1471 | }; 1472 | }); 1473 | 1474 | exists("ToolBar") && module.directive("winToolBarCommand", function () { 1475 | var api = { 1476 | disabled: BINDING_property, 1477 | extraClass: BINDING_property, 1478 | firstElementFocus: BINDING_property, 1479 | flyout: BINDING_property, 1480 | hidden: BINDING_property, 1481 | icon: BINDING_property, 1482 | id: BINDING_property, 1483 | label: BINDING_property, 1484 | lastElementFocus: BINDING_property, 1485 | priority: BINDING_property, 1486 | section: BINDING_property, 1487 | selected: BINDING_property, 1488 | tooltip: BINDING_property, 1489 | type: BINDING_property, 1490 | onClick: BINDING_event 1491 | }; 1492 | return { 1493 | restrict: "E", 1494 | replace: true, 1495 | scope: getScopeForAPI(api), 1496 | template: "", 1497 | transclude: true, 1498 | link: function ($scope, elements) { 1499 | initializeControl($scope, elements[0], WinJS.UI.Command, api); 1500 | } 1501 | }; 1502 | }); 1503 | 1504 | exists("ToolBar") && module.directive("winToolBarSeparator", function () { 1505 | var api = { 1506 | disabled: BINDING_property, 1507 | extraClass: BINDING_property, 1508 | firstElementFocus: BINDING_property, 1509 | flyout: BINDING_property, 1510 | hidden: BINDING_property, 1511 | icon: BINDING_property, 1512 | id: BINDING_property, 1513 | label: BINDING_property, 1514 | lastElementFocus: BINDING_property, 1515 | priority: BINDING_property, 1516 | section: BINDING_property, 1517 | selected: BINDING_property, 1518 | tooltip: BINDING_property, 1519 | type: BINDING_property, 1520 | onClick: BINDING_event 1521 | }; 1522 | return { 1523 | restrict: "E", 1524 | replace: true, 1525 | scope: getScopeForAPI(api), 1526 | template: "
", 1527 | transclude: true, 1528 | link: function ($scope, elements) { 1529 | initializeControl($scope, elements[0], WinJS.UI.Command, api, { type: "separator" }); 1530 | } 1531 | }; 1532 | }); 1533 | 1534 | exists("ToolBar") && module.directive("winToolBarContent", function () { 1535 | var api = { 1536 | disabled: BINDING_property, 1537 | extraClass: BINDING_property, 1538 | firstElementFocus: BINDING_property, 1539 | flyout: BINDING_property, 1540 | hidden: BINDING_property, 1541 | icon: BINDING_property, 1542 | id: BINDING_property, 1543 | label: BINDING_property, 1544 | lastElementFocus: BINDING_property, 1545 | priority: BINDING_property, 1546 | section: BINDING_property, 1547 | selected: BINDING_property, 1548 | tooltip: BINDING_property, 1549 | type: BINDING_property, 1550 | onClick: BINDING_event 1551 | }; 1552 | return { 1553 | restrict: "E", 1554 | replace: true, 1555 | scope: getScopeForAPI(api), 1556 | template: "
", 1557 | transclude: true, 1558 | link: function ($scope, elements) { 1559 | initializeControl($scope, elements[0], WinJS.UI.Command, api, { type: "content" }); 1560 | } 1561 | }; 1562 | }); 1563 | 1564 | exists("Tooltip") && module.directive("winTooltip", function () { 1565 | var api = { 1566 | contentElement: BINDING_property, 1567 | extraClass: BINDING_property, 1568 | innerHTML: BINDING_property, 1569 | infotip: BINDING_property, 1570 | placement: BINDING_property, 1571 | onBeforeClose: BINDING_event, 1572 | onBeforeOpen: BINDING_event, 1573 | onClosed: BINDING_event, 1574 | onOpened: BINDING_event 1575 | }; 1576 | return { 1577 | restrict: "E", 1578 | replace: true, 1579 | scope: getScopeForAPI(api), 1580 | template: "
", 1581 | transclude: true, 1582 | controller: ['$scope', function ($scope) { 1583 | proxy($scope, this, "contentElement"); 1584 | }], 1585 | link: function ($scope, elements, attrs) { 1586 | initializeControl($scope, elements[0], WinJS.UI.Tooltip, api); 1587 | } 1588 | }; 1589 | }); 1590 | 1591 | // Tooltop is a little odd because you have to be able to specify both the element 1592 | // which has a tooltip (the content) and the tooltip's content itself. We specify 1593 | // a special directive which represents the latter. 1594 | exists("Tooltip") && module.directive("winTooltipContent", function () { 1595 | return { 1596 | require: "^winTooltip", 1597 | restrict: "E", 1598 | replace: true, 1599 | transclude: true, 1600 | template: "\ 1601 |
\ 1602 |
\ 1603 |
", 1604 | link: function ($scope, elements, attrs, tooltip) { 1605 | tooltip.contentElement = elements[0].firstElementChild; 1606 | } 1607 | }; 1608 | }); 1609 | 1610 | // Surface winControl property as win-control directive. 1611 | // Keep priority set to a higher value than others (default is 0) as 'link' ie. postLink functions run highest priority last. 1612 | module.directive("winControl", ['$parse', function ($parse) { 1613 | return { 1614 | restrict: "A", 1615 | priority: 1, 1616 | link: function ($scope, element, attrs) { 1617 | if (attrs.winControl) { 1618 | $parse(attrs.winControl).assign($scope, element[0].winControl); 1619 | } 1620 | } 1621 | }; 1622 | }]); 1623 | 1624 | }(this)); 1625 | -------------------------------------------------------------------------------- /karma.config.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Dec 04 2014 11:26:12 GMT-0800 (Pacific Standard Time) 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | 7 | // base path, that will be used to resolve files and exclude 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | frameworks: ['jasmine'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'node_modules/winjs/js/base.js', 18 | 'node_modules/winjs/js/ui.js', 19 | 'node_modules/winjs/css/ui-dark.css', 20 | 'node_modules/angular/angular.js', 21 | 'node_modules/angular-mocks/angular-mocks.js', 22 | 'js/angular-winjs.js', 23 | 'tests/*.js', 24 | ], 25 | 26 | 27 | // list of files to exclude 28 | exclude: [ 29 | 30 | ], 31 | 32 | 33 | // test results reporter to use 34 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 35 | reporters: ['progress'], 36 | 37 | 38 | // web server port 39 | port: 9876, 40 | 41 | 42 | // enable / disable colors in the output (reporters and logs) 43 | colors: true, 44 | 45 | 46 | // level of logging 47 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 48 | logLevel: config.LOG_INFO, 49 | 50 | 51 | // enable / disable watching file and executing tests whenever any file changes 52 | autoWatch: true, 53 | 54 | 55 | // Start these browsers, currently available: 56 | // - Chrome 57 | // - ChromeCanary 58 | // - Firefox 59 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 60 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 61 | // - PhantomJS 62 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 63 | browsers: ['Chrome'], 64 | 65 | 66 | // If browser does not capture in given timeout [ms], kill it 67 | captureTimeout: 60000, 68 | 69 | 70 | // Continuous Integration mode 71 | // if true, it capture browsers, run tests and exit 72 | singleRun: false 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-winjs", 3 | "title": "Angular Wrapper for Windows Library for JavaScript (WinJS)", 4 | "description": "This code is a wrapper which facilitates usage of WinJS UI controls in an Angular application.", 5 | "homepage": "https://github.com/winjs/angular-winjs", 6 | "author": { 7 | "name": "Microsoft Corporation and other contributors", 8 | "url": "https://github.com/winjs/angular-winjs/graphs/contributors" 9 | }, 10 | "license": "MIT", 11 | "version": "4.4.0", 12 | "main": "js/angular-winjs.js", 13 | "scripts": { 14 | "test": "karma start karma.config.js" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/winjs/angular-winjs" 19 | }, 20 | "keywords": [ 21 | "AngularJS", 22 | "WinJS", 23 | "angular", 24 | "windows8", 25 | "windows10" 26 | ], 27 | "licenses": [ 28 | { 29 | "type": "MIT", 30 | "url": "https://github.com/winjs/angular-winjs/blob/master/License.txt" 31 | } 32 | ], 33 | "bugs": "https://github.com/winjs/angular-winjs/issues", 34 | "dependencies": { 35 | "angular": "~1.3.13" 36 | }, 37 | "devDependencies": { 38 | "angular-mocks": "~1.3.13", 39 | "karma": "~0.10", 40 | "winjs": "4.4.x", 41 | "grunt": "^0.4.5", 42 | "grunt-contrib-clean": "^0.6.0", 43 | "grunt-contrib-compress": "^0.13.0", 44 | "grunt-contrib-copy": "^0.8.0", 45 | "grunt-github-releaser": "^0.1.17", 46 | "grunt-nuget": "^0.1.4" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tasks/check-bom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | (function () { 3 | "use strict"; 4 | 5 | module.exports = function (grunt) { 6 | 7 | // Verifies that files begin with a UTF8 BOM. Files without one will not be able to pass the 8 | // Windows App Certification Kit test. 9 | 10 | grunt.registerMultiTask("check-bom", function () { 11 | function checkBom(filePath) { 12 | if (grunt.file.exists(filePath)) { 13 | var content = grunt.file.read(filePath, { encoding: null }); 14 | if (content.length < 3 || content[0] !== 0xef || content[1] !== 0xbb || content[2] !== 0xbf) { 15 | grunt.fail.fatal("check-bom File is missing BOM: " + filePath); 16 | } 17 | } else { 18 | grunt.log.warn("check-bom No such file: " + filePath); 19 | } 20 | } 21 | 22 | this.filesSrc.forEach(checkBom); 23 | }); 24 | 25 | }; 26 | })(); 27 | -------------------------------------------------------------------------------- /tests/AppBar.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("AppBar control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple AppBar", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.AppBar); 28 | expect(compiledControl.className).toContain("win-appbar"); 29 | }); 30 | 31 | it("should use child AppBarCommands", function () { 32 | var compiledControl = initControl("" + 33 | "" + 34 | "" + 35 | ""); 36 | 37 | expect(compiledControl.winControl).toBeDefined(); 38 | expect(compiledControl.winControl instanceof WinJS.UI.AppBar); 39 | expect(compiledControl.className).toContain("win-appbar"); 40 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 41 | }); 42 | 43 | it("should use the data attribute", function () { 44 | scope.testCommands = new WinJS.Binding.List([ 45 | new WinJS.UI.AppBarCommand(null, { label: "TestCommand0" }), 46 | new WinJS.UI.AppBarCommand(null, { label: "TestCommand1" }) 47 | ]); 48 | var compiledControl = initControl(""); 49 | 50 | var commands = compiledControl.querySelectorAll(".win-command"); 51 | expect(commands.length).toEqual(2); 52 | expect(commands[0].querySelector(".win-label").innerHTML).toEqual("TestCommand0"); 53 | expect(commands[1].querySelector(".win-label").innerHTML).toEqual("TestCommand1"); 54 | }); 55 | 56 | it("should use the closedDisplayMode attribute", function () { 57 | var compiledControl = initControl(""); 58 | expect(compiledControl.winControl.closedDisplayMode).toEqual("minimal"); 59 | }); 60 | 61 | it("should use the placement attribute", function () { 62 | var compiledControl = initControl(""); 63 | expect(compiledControl.winControl.placement).toEqual("top"); 64 | }); 65 | 66 | it("should use the opened attribute", function () { 67 | var compiledControl = initControl(""); 68 | expect(compiledControl.winControl.opened).toBeTruthy(); 69 | }); 70 | 71 | it("should use the onopen and onclose event handlers and opened attribute", function () { 72 | var gotBeforeOpenEvent = false, 73 | gotAfterOpenEvent = false, 74 | gotBeforeCloseEvent = false, 75 | gotAfterCloseEvent = false; 76 | scope.beforeOpenEventHandler = function (e) { 77 | gotBeforeOpenEvent = true; 78 | }; 79 | scope.afterOpenEventHandler = function (e) { 80 | gotAfterOpenEvent = true; 81 | }; 82 | scope.beforeCloseEventHandler = function (e) { 83 | gotBeforeCloseEvent = true; 84 | }; 85 | scope.afterCloseEventHandler = function (e) { 86 | gotAfterCloseEvent = true; 87 | }; 88 | scope.appbarOpened = false; 89 | var compiledControl = initControl(""); 91 | runs(function () { 92 | compiledControl.winControl.open(); 93 | }); 94 | 95 | waitsFor(function () { 96 | return (gotBeforeOpenEvent && gotAfterOpenEvent); 97 | }, "the AppBar's before+aftershow events", testTimeout); 98 | 99 | runs(function () { 100 | expect(scope.appbarOpened).toBeTruthy(); 101 | scope.appbarOpened = false; 102 | scope.$digest(); 103 | }); 104 | 105 | waitsFor(function () { 106 | return (gotBeforeCloseEvent && gotAfterCloseEvent); 107 | }, "the AppBar's before+afterhide events", testTimeout); 108 | }); 109 | 110 | afterEach(function () { 111 | var controls = document.querySelectorAll(".win-appbar"); 112 | for (var i = 0; i < controls.length; i++) { 113 | controls[i].parentNode.removeChild(controls[i]); 114 | } 115 | }); 116 | }); 117 | -------------------------------------------------------------------------------- /tests/AppBarCommand.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("AppBarCommand control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should use initialize an AppBar containing two child AppBarCommands", function () { 22 | var compiledControl = initControl("" + 23 | "" + 24 | "" + 25 | ""); 26 | 27 | var winControl = compiledControl.winControl; 28 | expect(compiledControl.winControl).toBeDefined(); 29 | expect(compiledControl.winControl instanceof WinJS.UI.AppBar); 30 | expect(compiledControl.className).toContain("win-appbar"); 31 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 32 | }); 33 | 34 | it("should use the id attribute on AppBarCommands", function () { 35 | var compiledControl = initControl("" + 36 | "" + 37 | "" + 38 | ""); 39 | 40 | var commands = compiledControl.querySelectorAll(".win-command"); 41 | expect(commands[0].id).toEqual("command1"); 42 | expect(commands[1].id).toEqual("command2"); 43 | }); 44 | 45 | it("should use the label attribute on AppBarCommands", function () { 46 | var compiledControl = initControl("" + 47 | "" + 48 | "" + 49 | ""); 50 | 51 | var commands = compiledControl.querySelectorAll(".win-command"); 52 | expect(commands[0].querySelector(".win-label").innerHTML).toEqual("command1"); 53 | expect(commands[1].querySelector(".win-label").innerHTML).toEqual("command2"); 54 | }); 55 | 56 | it("should use the disabled attribute on AppBarCommands", function () { 57 | var compiledControl = initControl("" + 58 | "" + 59 | "" + 60 | ""); 61 | 62 | var commands = compiledControl.querySelectorAll(".win-command"); 63 | expect(commands[0].winControl.disabled).toBeTruthy(); 64 | expect(commands[1].winControl.disabled).toBeFalsy(); 65 | }); 66 | 67 | it("should use the extraClass attribute on AppBarCommands", function () { 68 | var compiledControl = initControl("" + 69 | "" + 70 | ""); 71 | 72 | var commands = compiledControl.querySelectorAll(".win-command"); 73 | expect(commands[0].className).toContain("extraClass1"); 74 | }); 75 | 76 | it("should use the section attribute on AppBarCommands", function () { 77 | var compiledControl = initControl("" + 78 | "" + 79 | "" + 80 | ""); 81 | 82 | var commands = compiledControl.querySelectorAll(".win-command"); 83 | expect(commands[0].winControl.section).toEqual("global"); 84 | expect(commands[1].winControl.section).toEqual("selection"); 85 | }); 86 | 87 | it("should use the hidden attribute on AppBarCommands", function () { 88 | var compiledControl = initControl("" + 89 | "" + 90 | "" + 91 | ""); 92 | 93 | var commands = compiledControl.querySelectorAll(".win-command"); 94 | expect(commands[0].winControl.hidden).toBeTruthy(); 95 | expect(commands[1].winControl.hidden).toBeFalsy(); 96 | }); 97 | 98 | it("should use the icon attribute on AppBarCommands", function () { 99 | var compiledControl = initControl("" + 100 | "" + 101 | ""); 102 | 103 | var commandImage = compiledControl.querySelector(".win-commandimage"); 104 | expect(escape(commandImage.innerHTML)).toEqual("%uE109"); 105 | }); 106 | 107 | it("should use the win-app-bar command types", function () { 108 | var compiledControl = initControl("" + 109 | "" + 110 | "" + 111 | "" + 112 | ""); 113 | 114 | var commands = compiledControl.querySelectorAll(".win-command"); 115 | expect(commands[0].winControl.type).toEqual("separator"); 116 | expect(commands[1].winControl.type).toEqual("content"); 117 | expect(commands[2].winControl.type).toEqual("toggle"); 118 | }); 119 | 120 | it("should use the priority attribute", function () { 121 | var compiledControl = initControl("" + 122 | "" + 123 | "" + 124 | ""); 125 | 126 | var commands = compiledControl.querySelectorAll(".win-command"); 127 | expect(commands[0].winControl.priority).toEqual(1); 128 | expect(commands[1].winControl.priority).toEqual(2); 129 | }); 130 | 131 | it("should use the flyout attribute", function () { 132 | scope.flyout = new WinJS.UI.Flyout(); 133 | var compiledControl = initControl("" + 134 | "" + 135 | ""); 136 | 137 | var commands = compiledControl.querySelectorAll(".win-command"); 138 | expect(commands[0].winControl.flyout).toEqual(scope.flyout); 139 | }); 140 | 141 | afterEach(function () { 142 | var controls = document.querySelectorAll(".win-appbar"); 143 | for (var i = 0; i < controls.length; i++) { 144 | controls[i].parentNode.removeChild(controls[i]); 145 | } 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /tests/AutoSuggestBox.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("AutoSuggestBox control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple autosuggestbox", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.AutoSuggestBox); 26 | expect(compiledControl.className).toContain("win-autosuggestbox"); 27 | }); 28 | 29 | it("should use the chooseSuggestionOnEnter attribute", function () { 30 | var compiledControl = initControl(""); 31 | expect(compiledControl.winControl.chooseSuggestionOnEnter).toBeTruthy(); 32 | }); 33 | 34 | it("should use the placeholderText attribute", function () { 35 | var compiledControl = initControl(""); 36 | expect(compiledControl.winControl.placeholderText).toEqual("Some Placeholder Text"); 37 | }); 38 | 39 | it("should use the queryText attribute", function () { 40 | var compiledControl = initControl(""); 41 | expect(compiledControl.winControl.queryText).toEqual("Some Query Text"); 42 | }); 43 | 44 | it("should use the searchHistoryContext attribute", function () { 45 | var compiledControl = initControl(""); 46 | expect(compiledControl.winControl.searchHistoryContext).toEqual("searchContext"); 47 | }); 48 | 49 | it("should use the searchHistoryDisabled attribute", function () { 50 | var compiledControl = initControl(""); 51 | expect(compiledControl.winControl.searchHistoryDisabled).toBeTruthy(); 52 | }); 53 | 54 | afterEach(function () { 55 | var controls = document.querySelectorAll(".win-auto-suggest-box"); 56 | for (var i = 0; i < controls.length; i++) { 57 | controls[i].parentNode.removeChild(controls[i]); 58 | } 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /tests/BackButton.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("BackButton control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple BackButton", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.BackButton); 26 | expect(compiledControl.className).toContain("win-navigation-backbutton"); 27 | }); 28 | 29 | afterEach(function () { 30 | var controls = document.querySelectorAll(".win-navigation-backbutton"); 31 | for (var i = 0; i < controls.length; i++) { 32 | controls[i].parentNode.removeChild(controls[i]); 33 | } 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/ContentDialog.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ContentDialog control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple ContentDialog control", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.ContentDialog); 28 | expect(compiledControl.className).toContain("win-contentdialog"); 29 | }); 30 | 31 | it("should use the title attribute", function () { 32 | var compiledControl = initControl(""); 33 | expect(compiledControl.winControl.title).toEqual("ContentDialogTitle"); 34 | }); 35 | 36 | it("should use the primaryCommandText attribute", function () { 37 | var compiledControl = initControl(""); 38 | var primaryCommand = compiledControl.querySelector(".win-contentdialog-primarycommand"); 39 | expect(primaryCommand.innerHTML).toEqual("PrimaryCommandText"); 40 | }); 41 | 42 | it("should use the primaryCommandDisabled attribute", function () { 43 | var compiledControl = initControl(""); 44 | var primaryCommand = compiledControl.querySelector(".win-contentdialog-primarycommand"); 45 | expect(primaryCommand.disabled).toBeTruthy(); 46 | }); 47 | 48 | it("should use the secondaryCommandText attribute", function () { 49 | var compiledControl = initControl(""); 50 | var secondaryCommand = compiledControl.querySelector(".win-contentdialog-secondarycommand"); 51 | expect(secondaryCommand.innerHTML).toEqual("SecondaryCommandText"); 52 | }); 53 | 54 | it("should use the secondaryCommandDisabled attribute", function () { 55 | var compiledControl = initControl(""); 56 | var secondaryCommand = compiledControl.querySelector(".win-contentdialog-secondarycommand"); 57 | expect(secondaryCommand.disabled).toBeTruthy(); 58 | }); 59 | 60 | it("should use the onshow and onhide event handlers", function () { 61 | var gotBeforeShowEvent = false, 62 | gotAfterShowEvent = false, 63 | gotBeforeHideEvent = false, 64 | gotAfterHideEvent = false; 65 | scope.beforeShowEventHandler = function (e) { 66 | gotBeforeShowEvent = true; 67 | }; 68 | scope.afterShowEventHandler = function (e) { 69 | gotAfterShowEvent = true; 70 | }; 71 | scope.beforeHideEventHandler = function (e) { 72 | gotBeforeHideEvent = true; 73 | }; 74 | scope.afterHideEventHandler = function (e) { 75 | gotAfterHideEvent = true; 76 | }; 77 | scope.dialogHidden = true; 78 | var compiledControl = initControl(""); 80 | runs(function () { 81 | compiledControl.winControl.show(); 82 | }); 83 | 84 | waitsFor(function () { 85 | return (gotBeforeShowEvent && gotAfterShowEvent); 86 | }, "the ContentDialog's before+aftershow events", testTimeout); 87 | 88 | runs(function () { 89 | expect(compiledControl.winControl.hidden).toBeFalsy(); 90 | expect(scope.dialogHidden).toBeFalsy(); 91 | scope.dialogHidden = true; 92 | scope.$digest(); 93 | }); 94 | 95 | waitsFor(function () { 96 | return (gotBeforeHideEvent && gotAfterHideEvent); 97 | }, "the ContentDialog's before+afterhide events", testTimeout); 98 | 99 | runs(function () { 100 | expect(compiledControl.winControl.hidden).toBeTruthy(); 101 | expect(scope.dialogHidden).toBeTruthy(); 102 | }); 103 | }); 104 | 105 | afterEach(function () { 106 | var controls = document.querySelectorAll(".win-contentdialog"); 107 | for (var i = 0; i < controls.length; i++) { 108 | controls[i].parentNode.removeChild(controls[i]); 109 | } 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /tests/DatePicker.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("DatePicker control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple DatePicker", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.DatePicker); 26 | expect(compiledControl.className).toContain("win-datepicker"); 27 | }); 28 | 29 | it("should use the min and max year attributes", function () { 30 | var compiledControl = initControl(""); 31 | 32 | var winControl = compiledControl.winControl; 33 | expect(winControl.minYear).toBe(2013); 34 | expect(winControl.maxYear).toBe(2014); 35 | }); 36 | 37 | it("should use the disabled attribute", function () { 38 | var compiledControl = initControl(""); 39 | 40 | expect(compiledControl.winControl.disabled).toBeTruthy(); 41 | }); 42 | 43 | it("should use the current attribute", function () { 44 | scope.testDate = new Date(2013, 3, 7); 45 | var compiledControl = initControl(""); 46 | 47 | var winControl = compiledControl.winControl; 48 | expect(winControl.current.getYear()).toBe(113); 49 | expect(winControl.current.getMonth()).toBe(3); 50 | expect(winControl.current.getDate()).toBe(7); 51 | }); 52 | 53 | afterEach(function () { 54 | var controls = document.querySelectorAll(".win-datepicker"); 55 | for (var i = 0; i < controls.length; i++) { 56 | controls[i].parentNode.removeChild(controls[i]); 57 | } 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /tests/FlipView.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("FlipView control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDataSourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | scope.testDataSource = []; 15 | for (var i = 0; i < testDataSourceLength; i++) { 16 | scope.testDataSource.push({ title: "Item" + i }); 17 | } 18 | })); 19 | 20 | function initControl(markup) { 21 | var element = angular.element(markup)[0]; 22 | document.body.appendChild(element); 23 | var compiledControl = compile(element)(scope)[0]; 24 | scope.$digest(); 25 | return compiledControl; 26 | } 27 | 28 | function waitForPageComplete(flipView) { 29 | var pageComplete = false; 30 | flipView.addEventListener("pagecompleted", function (e) { 31 | pageComplete = true; 32 | }); 33 | 34 | return function () { 35 | return pageComplete; 36 | }; 37 | } 38 | 39 | it("should initialize a simple FlipView", function () { 40 | var compiledControl = initControl(""); 41 | 42 | expect(compiledControl.winControl).toBeDefined(); 43 | expect(compiledControl.winControl instanceof WinJS.UI.FlipView); 44 | expect(compiledControl.className).toContain("win-flipview"); 45 | }); 46 | 47 | it("should use an itemDataSource and render content with a win-item-template", function () { 48 | var compiledControl; 49 | var pageCompleted; 50 | runs(function () { 51 | compiledControl = initControl("" + 52 | "" + 53 | "Rendered{{item.data.title}}" + 54 | "" + 55 | ""); 56 | 57 | pageCompleted = waitForPageComplete(compiledControl); 58 | }); 59 | 60 | waitsFor(function () { 61 | return pageCompleted(); 62 | }, "the FlipView's pagecompleted event", testTimeout); 63 | 64 | runs(function () { 65 | var currentPage = compiledControl.winControl._pageManager._currentPage.element; 66 | var boundElement = currentPage.querySelector(".ng-binding"); 67 | expect(boundElement.innerHTML).toContain("RenderedItem0"); 68 | }); 69 | }); 70 | 71 | it("should receive a page completed event", function () { 72 | var gotCompletedEvent = false; 73 | scope.completedEventHandler = function (e) { 74 | gotCompletedEvent = true; 75 | }; 76 | var compiledControl; 77 | runs(function () { 78 | compiledControl = initControl(""); 79 | }); 80 | 81 | waitsFor(function () { 82 | return gotCompletedEvent; 83 | }, "the FlipView's pagecompleted event", testTimeout); 84 | }); 85 | 86 | it("should receive an on page selected event", function () { 87 | var gotSelectedEvent = false; 88 | scope.selectedEventHandler = function (e) { 89 | gotSelectedEvent = true; 90 | }; 91 | var compiledControl; 92 | runs(function () { 93 | compiledControl = initControl(""); 94 | }); 95 | 96 | waitsFor(function () { 97 | return gotSelectedEvent; 98 | }, "the FlipView's pageselected event", testTimeout); 99 | }); 100 | 101 | it("should receive an on page visibility changed event", function () { 102 | var gotChangedEvent = false; 103 | scope.changedEventHandler = function (e) { 104 | gotChangedEvent = true; 105 | }; 106 | var compiledControl; 107 | runs(function () { 108 | compiledControl = initControl(""); 109 | }); 110 | 111 | waitsFor(function () { 112 | return gotChangedEvent; 113 | }, "the FlipView's pagevisibilitychanged event", testTimeout); 114 | }); 115 | 116 | it("should receive a datasource count changed event", function () { 117 | var compiledControl; 118 | var pageCompleted; 119 | 120 | runs(function () { 121 | compiledControl = initControl(""); 122 | pageCompleted = waitForPageComplete(compiledControl); 123 | }); 124 | 125 | waitsFor(function () { 126 | return pageCompleted(); 127 | }, "the FlipView's pagecompleted event", testTimeout); 128 | 129 | var gotCountChangedEvent = false; 130 | scope.countChangedEventHandler = function (e) { 131 | gotCountChangedEvent = true; 132 | }; 133 | 134 | runs(function () { 135 | scope.testDataSource.push({ title: "NewItem" }); 136 | scope.$digest(); 137 | }); 138 | 139 | waitsFor(function () { 140 | return gotCountChangedEvent; 141 | }, "the FlipView's datasourcecountchanged event", testTimeout); 142 | }); 143 | 144 | it("should update currentPage on navigation", function () { 145 | scope.testCurrentPage = 0; 146 | var compiledControl = initControl(""); 147 | var pageCompleted = waitForPageComplete(compiledControl); 148 | 149 | waitsFor(function () { 150 | return pageCompleted(); 151 | }, "the FlipView's pagecompleted event", testTimeout); 152 | 153 | runs(function () { 154 | compiledControl.winControl.currentPage = 2; 155 | }); 156 | 157 | waitsFor(function () { 158 | return (scope.testCurrentPage === 2); 159 | }, "the FlipView to update testCurrentPage", testTimeout); 160 | }); 161 | 162 | afterEach(function () { 163 | var controls = document.querySelectorAll(".win-flipview"); 164 | for (var i = 0; i < controls.length; i++) { 165 | controls[i].parentNode.removeChild(controls[i]); 166 | } 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /tests/Flyout.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Flyout control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple Flyout control", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.Flyout); 28 | expect(compiledControl.className).toContain("win-flyout"); 29 | }); 30 | 31 | it("should use the alignment attribute", function () { 32 | var compiledControl = initControl(""); 33 | expect(compiledControl.winControl.alignment).toEqual("left"); 34 | }); 35 | 36 | it("should use the disabled attribute", function () { 37 | var compiledControl = initControl(""); 38 | expect(compiledControl.winControl.disabled).toBeTruthy(); 39 | }); 40 | 41 | it("should use the placement attribute", function () { 42 | var compiledControl = initControl(""); 43 | expect(compiledControl.winControl.placement).toEqual("right"); 44 | }); 45 | 46 | it("should use the anchor attribute", function () { 47 | var anchorEl = document.createElement("div"); 48 | anchorEl.className = "flyoutTestAnchorElement"; 49 | document.body.appendChild(anchorEl); 50 | scope.flyoutAnchor = anchorEl; 51 | var compiledControl = initControl(""); 52 | expect(compiledControl.winControl.anchor).toBe(anchorEl); 53 | }); 54 | 55 | it("should use the onshow and onhide event handlers and hidden attribute", function () { 56 | var gotBeforeShowEvent = false, 57 | gotAfterShowEvent = false, 58 | gotBeforeHideEvent = false, 59 | gotAfterHideEvent = false; 60 | scope.beforeShowEventHandler = function (e) { 61 | gotBeforeShowEvent = true; 62 | }; 63 | scope.afterShowEventHandler = function (e) { 64 | gotAfterShowEvent = true; 65 | }; 66 | scope.beforeHideEventHandler = function (e) { 67 | gotBeforeHideEvent = true; 68 | }; 69 | scope.afterHideEventHandler = function (e) { 70 | gotAfterHideEvent = true; 71 | }; 72 | scope.flyoutHidden = true; 73 | var compiledControl = initControl(""); 75 | runs(function () { 76 | compiledControl.winControl.show(document.body); 77 | }); 78 | 79 | waitsFor(function () { 80 | return (gotBeforeShowEvent && gotAfterShowEvent); 81 | }, "the Flyout's before+aftershow events", testTimeout); 82 | 83 | runs(function () { 84 | expect(scope.flyoutHidden).toBeFalsy(); 85 | scope.flyoutHidden = true; 86 | scope.$digest(); 87 | }); 88 | 89 | waitsFor(function () { 90 | return (gotBeforeHideEvent && gotAfterHideEvent); 91 | }, "the Flyout's before+afterhide events", testTimeout); 92 | 93 | runs(function () { 94 | expect(scope.flyoutHidden).toBeTruthy(); 95 | expect(compiledControl.winControl.hidden).toBeTruthy(); 96 | }); 97 | }); 98 | 99 | afterEach(function () { 100 | var controls = document.querySelectorAll(".win-flyout"); 101 | for (var i = 0; i < controls.length; i++) { 102 | controls[i].parentNode.removeChild(controls[i]); 103 | } 104 | var anchors = document.querySelectorAll(".flyoutTestAnchorElement"); 105 | for (var i = 0; i < anchors.length; i++) { 106 | anchors[i].parentNode.removeChild(anchors[i]); 107 | } 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /tests/Hub.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Hub control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple Hub", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.Hub); 28 | expect(compiledControl.className).toContain("win-hub"); 29 | }); 30 | 31 | it("should use the orientation attribute", function () { 32 | var compiledControl = initControl(""); 33 | expect(compiledControl.winControl.orientation).toEqual("vertical"); 34 | }); 35 | 36 | afterEach(function () { 37 | var controls = document.querySelectorAll(".win-hub"); 38 | for (var i = 0; i < controls.length; i++) { 39 | controls[i].parentNode.removeChild(controls[i]); 40 | } 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /tests/HubSection.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("HubSection control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDataSourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | scope.testDataSource = []; 15 | for (var i = 0; i < testDataSourceLength; i++) { 16 | scope.testDataSource.push({ title: "Item" + i }); 17 | } 18 | })); 19 | 20 | function initControl(markup) { 21 | var element = angular.element(markup)[0]; 22 | document.body.appendChild(element); 23 | var compiledControl = compile(element)(scope)[0]; 24 | scope.$digest(); 25 | return compiledControl; 26 | } 27 | 28 | it("should initialize a simple Hub with a single HubSection", function () { 29 | var compiledControl = initControl("" + 30 | "Simple Section" + 31 | ""); 32 | 33 | expect(compiledControl.winControl).toBeDefined(); 34 | expect(compiledControl.winControl instanceof WinJS.UI.Hub); 35 | expect(compiledControl.className).toContain("win-hub"); 36 | expect(compiledControl.querySelectorAll(".win-hub-section").length).toEqual(1); 37 | }); 38 | 39 | it("should use the header attribute", function () { 40 | var compiledControl = initControl("" + 41 | "Simple Section" + 42 | ""); 43 | 44 | waitsFor(function () { 45 | return (compiledControl.winControl.loadingState === "complete"); 46 | }, "the Hub to load", testTimeout); 47 | 48 | runs(function () { 49 | var headers = compiledControl.querySelectorAll(".win-hub-section-header"); 50 | expect(headers.length).toEqual(1); 51 | var headerContent = headers[0].querySelectorAll(".win-hub-section-header-content"); 52 | expect(headerContent.length).toEqual(1); 53 | expect(headerContent[0].innerHTML).toEqual("SimpleHeader"); 54 | }); 55 | }); 56 | 57 | it("should use the isHeaderStatic attribute", function () { 58 | var compiledControl = initControl("" + 59 | "Simple Section" + 60 | ""); 61 | var headers = compiledControl.querySelectorAll(".win-hub-section"); 62 | expect(headers.length).toEqual(1); 63 | expect(headers[0].winControl.isHeaderStatic).toBeTruthy(); 64 | }); 65 | 66 | it("should allow ng-repeat to be used in conjunction with the Hub to create HubSections", function () { 67 | var compiledControl = initControl("" + 68 | "" + 69 | ""); 70 | 71 | waitsFor(function () { 72 | return (compiledControl.winControl.loadingState === "complete"); 73 | }, "the Hub to load", testTimeout); 74 | 75 | runs(function () { 76 | var headers = compiledControl.querySelectorAll(".win-hub-section-header"); 77 | var headerContent = compiledControl.querySelectorAll(".win-hub-section-header-content"); 78 | expect(headers.length).toEqual(testDataSourceLength); 79 | expect(headerContent.length).toEqual(testDataSourceLength); 80 | for (var i = 0; i < testDataSourceLength; i++) { 81 | expect(headerContent[i].innerHTML).toEqual("Item" + i); 82 | } 83 | }); 84 | }); 85 | 86 | afterEach(function () { 87 | var controls = document.querySelectorAll(".win-hub"); 88 | for (var i = 0; i < controls.length; i++) { 89 | controls[i].parentNode.removeChild(controls[i]); 90 | } 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /tests/ItemContainer.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ItemContainer control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple ItemContainer", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.ItemContainer); 26 | expect(compiledControl.className).toContain("win-itemcontainer"); 27 | }); 28 | 29 | it("should use the draggable attribute", function () { 30 | var compiledControl = initControl(""); 31 | 32 | var winControl = compiledControl.winControl; 33 | expect(winControl.draggable).toBeTruthy(); 34 | }); 35 | 36 | it("should use the selected attribute", function () { 37 | var compiledControl = initControl(""); 38 | 39 | var winControl = compiledControl.winControl; 40 | expect(winControl.selected).toBeTruthy(); 41 | }); 42 | 43 | it("should use the selectionDisabled attribute", function () { 44 | var compiledControl = initControl(""); 45 | 46 | var winControl = compiledControl.winControl; 47 | expect(winControl.selectionDisabled).toBeTruthy(); 48 | }); 49 | 50 | it("should use the tapBehavior attribute", function () { 51 | var compiledControl = initControl(""); 52 | 53 | var winControl = compiledControl.winControl; 54 | expect(winControl.tapBehavior).toBe(WinJS.UI.TapBehavior.toggleSelect); 55 | }); 56 | 57 | it("should receive selection events", function () { 58 | var gotChangingEvent = false, 59 | gotChangedEvent = false; 60 | scope.changingEventHandler = function (e) { 61 | gotChangingEvent = true; 62 | }; 63 | scope.changedEventHandler = function (e) { 64 | gotChangedEvent = true; 65 | }; 66 | var compiledControl = initControl(""); 67 | 68 | var winControl = compiledControl.winControl; 69 | expect(winControl.selected).toBeFalsy(); 70 | expect(gotChangingEvent).toBeFalsy(); 71 | expect(gotChangedEvent).toBeFalsy(); 72 | winControl.selected = true; 73 | scope.$digest(); 74 | expect(winControl.selected).toBeTruthy(); 75 | expect(gotChangingEvent).toBeTruthy(); 76 | expect(gotChangedEvent).toBeTruthy(); 77 | }); 78 | 79 | afterEach(function () { 80 | var controls = document.querySelectorAll(".win-itemcontainer"); 81 | for (var i = 0; i < controls.length; i++) { 82 | controls[i].parentNode.removeChild(controls[i]); 83 | } 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /tests/ListView.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ListView control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDataSourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | scope.testDataSource = []; 15 | for (var i = 0; i < testDataSourceLength; i++) { 16 | scope.testDataSource.push({ title: "Item" + i }); 17 | } 18 | })); 19 | beforeEach(function () { 20 | WinJS.Utilities._fastAnimations = true; 21 | }); 22 | 23 | function initControl(markup) { 24 | var element = angular.element(markup)[0]; 25 | document.body.appendChild(element); 26 | var compiledControl = compile(element)(scope)[0]; 27 | scope.$digest(); 28 | return compiledControl; 29 | } 30 | 31 | function waitForLoadingComplete(listView) { 32 | var loadingComplete = false; 33 | listView.addEventListener("loadingstatechanged", function (e) { 34 | if (listView.loadingState === "complete") { 35 | loadingComplete = true; 36 | } 37 | }); 38 | 39 | return function () { 40 | return loadingComplete; 41 | }; 42 | } 43 | 44 | it("should initialize a simple ListView", function () { 45 | var compiledControl = initControl(""); 46 | 47 | expect(compiledControl.winControl).toBeDefined(); 48 | expect(compiledControl.winControl instanceof WinJS.UI.ListView); 49 | expect(compiledControl.className).toContain("win-listview"); 50 | }); 51 | 52 | it("should use the itemDataSource attribute", function () { 53 | var compiledControl = initControl(""); 54 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 55 | 56 | waitsFor(function () { 57 | return loadingComplete(); 58 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 59 | 60 | runs(function () { 61 | expect(compiledControl.querySelectorAll(".win-container").length).toEqual(testDataSourceLength); 62 | }); 63 | }); 64 | 65 | it("should use the inline item template", function () { 66 | var compiledControl = initControl("" + 67 | "{{item.data.title}}" + 68 | ""); 69 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 70 | 71 | waitsFor(function () { 72 | return loadingComplete(); 73 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 74 | 75 | runs(function () { 76 | var renderedItems = compiledControl.querySelectorAll(".win-item"); 77 | expect(renderedItems.length).toEqual(testDataSourceLength); 78 | for (var i = 0; i < renderedItems.length; i++) { 79 | expect(renderedItems[i].firstElementChild.innerHTML).toEqual(scope.testDataSource[i].title); 80 | } 81 | }); 82 | }); 83 | 84 | it("should use the inline group header template", function () { 85 | function simpleGroupingFunction(data) { 86 | return data.title; 87 | } 88 | scope.groupedDataSource = new WinJS.Binding.List(scope.testDataSource).createGrouped(simpleGroupingFunction, simpleGroupingFunction); 89 | 90 | var compiledControl = initControl("" + 91 | "{{item.data}}" + 92 | "{{item.data.title}}" + 93 | ""); 94 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 95 | 96 | waitsFor(function () { 97 | return loadingComplete(); 98 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 99 | 100 | runs(function () { 101 | var renderedItems = compiledControl.querySelectorAll(".win-item"); 102 | expect(renderedItems.length).toEqual(testDataSourceLength); 103 | for (var i = 0; i < renderedItems.length; i++) { 104 | expect(renderedItems[i].firstElementChild.innerHTML).toEqual(scope.testDataSource[i].title); 105 | } 106 | 107 | var renderedHeaders = compiledControl.querySelectorAll(".win-groupheader"); 108 | expect(renderedHeaders.length).toEqual(testDataSourceLength); 109 | for (var i = 0; i < renderedHeaders.length; i++) { 110 | expect(renderedHeaders[i].firstElementChild.innerHTML).toEqual(scope.testDataSource[i].title); 111 | } 112 | }); 113 | }); 114 | 115 | it("should use the itemsReorderable attribute", function () { 116 | var compiledControl = initControl(""); 117 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 118 | 119 | waitsFor(function () { 120 | return loadingComplete(); 121 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 122 | 123 | runs(function () { 124 | expect(compiledControl.winControl.itemsReorderable).toBeTruthy(); 125 | var itemBoxes = compiledControl.querySelectorAll(".win-itembox"); 126 | for (var i = 0; i < itemBoxes.length; i++) { 127 | expect(itemBoxes[i].draggable).toBeTruthy(); 128 | } 129 | }); 130 | }); 131 | 132 | it("should use the itemsDraggable attribute", function () { 133 | var compiledControl = initControl(""); 134 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 135 | 136 | waitsFor(function () { 137 | return loadingComplete(); 138 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 139 | 140 | runs(function () { 141 | expect(compiledControl.winControl.itemsDraggable).toBeTruthy(); 142 | var itemBoxes = compiledControl.querySelectorAll(".win-itembox"); 143 | for (var i = 0; i < itemBoxes.length; i++) { 144 | expect(itemBoxes[i].draggable).toBeTruthy(); 145 | } 146 | }); 147 | }); 148 | 149 | it("should use the loadingStateChanged event handler", function () { 150 | var expectedEventsInOrder = ["itemsLoading", "viewPortLoaded", "itemsLoaded", "complete"], 151 | currentEvent = 0; 152 | scope.loadingStateChangedHandler = function (e) { 153 | expect(e.srcElement.winControl.loadingState).toEqual(expectedEventsInOrder[currentEvent++]); 154 | }; 155 | var compiledControl = initControl("" + 156 | "{{item.data.title}}" + 157 | ""); 158 | waitsFor(function () { 159 | return (currentEvent === expectedEventsInOrder.length); 160 | }, "the ListView's loadingStateChanged events", testTimeout); 161 | }); 162 | 163 | it("should use the maxDeferredItemCleanup attribute", function () { 164 | var compiledControl = initControl(""); 165 | expect(compiledControl.winControl.maxDeferredItemCleanup).toEqual(10); 166 | }); 167 | 168 | it("should use the maxLeadingPages attribute", function () { 169 | var compiledControl = initControl(""); 170 | expect(compiledControl.winControl.maxLeadingPages).toEqual(7); 171 | }); 172 | 173 | it("should use the maxTrailingPages attribute", function () { 174 | var compiledControl = initControl(""); 175 | expect(compiledControl.winControl.maxTrailingPages).toEqual(7); 176 | }); 177 | 178 | it("should use the currentItem attribute", function () { 179 | scope.testCurrentItem = { 180 | index: 2 181 | }; 182 | var compiledControl = initControl(""); 183 | expect(compiledControl.winControl.currentItem.index).toEqual(2); 184 | }); 185 | 186 | it("should use the tapBehavior attribute", function () { 187 | var compiledControl = initControl(""); 188 | expect(compiledControl.winControl.tapBehavior).toEqual("toggleSelect"); 189 | }); 190 | 191 | it("should use the groupHeaderTapBehavior attribute", function () { 192 | var compiledControl = initControl(""); 193 | expect(compiledControl.winControl.groupHeaderTapBehavior).toEqual("none"); 194 | }); 195 | 196 | it("should use the selectionMode attribute", function () { 197 | var compiledControl = initControl(""); 198 | expect(compiledControl.winControl.selectionMode).toEqual("none"); 199 | }); 200 | 201 | it("should use the layout attribute", function () { 202 | scope.layout = new WinJS.UI.ListLayout(); 203 | var compiledControl = initControl(""); 204 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 205 | 206 | waitsFor(function () { 207 | return loadingComplete(); 208 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 209 | 210 | runs(function () { 211 | expect(compiledControl.winControl.layout instanceof WinJS.UI.ListLayout).toBeTruthy(); 212 | }); 213 | }); 214 | 215 | it("should use the onAccessibilityAnnotationComplete event", function () { 216 | var gotEvent = false; 217 | scope.handler = function (e) { 218 | gotEvent = true; 219 | }; 220 | var compiledControl = initControl("" + 221 | "{{item.data.title}}" + 222 | ""); 223 | waitsFor(function () { 224 | return gotEvent; 225 | }, "the ListView's onAccessibilityAnnotationComplete event", testTimeout); 226 | }); 227 | 228 | it("should use the onContentAnimating event", function () { 229 | var gotAnimatingEvent = false; 230 | scope.contentAnimatingEventHandler = function (e) { 231 | expect(e.detail.type).toEqual("entrance"); 232 | gotAnimatingEvent = true; 233 | }; 234 | var compiledControl = initControl("" + 235 | "{{item.data.title}}" + 236 | ""); 237 | waitsFor(function () { 238 | return gotAnimatingEvent; 239 | }, "the ListView's onContentAnimating event", testTimeout); 240 | }); 241 | 242 | it("should use the selection attribute", function () { 243 | scope.selection = []; 244 | var compiledControl = initControl("" + 245 | "{{item.data.title}}" + 246 | ""); 247 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 248 | 249 | waitsFor(function () { 250 | return loadingComplete(); 251 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 252 | 253 | runs(function () { 254 | var control = compiledControl.winControl; 255 | expect(control.selection.count()).toEqual(0); 256 | scope.selection.push(2); 257 | scope.$digest(); 258 | expect(control.selection.count()).toEqual(1); 259 | expect(control.selection.getIndices()[0]).toEqual(2); 260 | }); 261 | }); 262 | 263 | it("should apply reorders back to the scope", function () { 264 | var compiledControl = initControl("" + 265 | "{{item.data.title}}" + 266 | ""); 267 | var originalDataSource = []; 268 | for (var i = 0; i < testDataSourceLength; i++) { 269 | originalDataSource[i] = scope.testDataSource[i]; 270 | } 271 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 272 | 273 | waitsFor(function () { 274 | return loadingComplete(); 275 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 276 | 277 | runs(function () { 278 | var control = compiledControl.winControl; 279 | control.selection.set([testDataSourceLength - 1]); 280 | control._currentMode()._reorderItems(0, control.selection, false, true, false); 281 | loadingComplete = waitForLoadingComplete(compiledControl.winControl); 282 | }); 283 | 284 | waitsFor(function () { 285 | return loadingComplete(); 286 | }, "the ListView's loadingStateChanged=complete event after reorder", testTimeout); 287 | 288 | runs(function () { 289 | expect(originalDataSource[testDataSourceLength - 1]).toEqual(scope.testDataSource[0]); 290 | expect(originalDataSource[0]).toEqual(scope.testDataSource[1]); 291 | }); 292 | }); 293 | 294 | it("should use the header and footer attributes", function () { 295 | scope.headerElement = document.createElement("div"); 296 | scope.footerElement = document.createElement("div"); 297 | var compiledControl = initControl("" + 298 | "{{item.data.title}}" + 299 | ""); 300 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 301 | 302 | waitsFor(function () { 303 | return loadingComplete(); 304 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 305 | 306 | runs(function () { 307 | var control = compiledControl.winControl; 308 | expect(control.header).toEqual(scope.headerElement); 309 | expect(control.footer).toEqual(scope.footerElement); 310 | }); 311 | }); 312 | 313 | it("should use an inline header and footer", function () { 314 | var compiledControl = initControl("" + 315 | "HeaderElement" + 316 | "{{item.data.title}}" + 317 | "FooterElement" + 318 | ""); 319 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 320 | 321 | waitsFor(function () { 322 | return loadingComplete(); 323 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 324 | 325 | runs(function () { 326 | var control = compiledControl.winControl; 327 | expect(control.header.firstElementChild.innerHTML).toEqual("HeaderElement"); 328 | expect(control.footer.firstElementChild.innerHTML).toEqual("FooterElement"); 329 | }); 330 | }); 331 | 332 | afterEach(function () { 333 | var controls = document.querySelectorAll(".win-listview"); 334 | for (var i = 0; i < controls.length; i++) { 335 | controls[i].parentNode.removeChild(controls[i]); 336 | } 337 | WinJS.Utilities._fastAnimations = false; 338 | }); 339 | }); 340 | -------------------------------------------------------------------------------- /tests/ListViewLayouts.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ListView Layout control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDatasourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | scope.testDataSource = []; 15 | for (var i = 0; i < testDatasourceLength; i++) { 16 | scope.testDataSource.push({ title: "Item" + i }); 17 | } 18 | })); 19 | beforeEach(function () { 20 | WinJS.Utilities._fastAnimations = true; 21 | }); 22 | 23 | function initControl(markup) { 24 | var element = angular.element(markup)[0]; 25 | document.body.appendChild(element); 26 | var compiledControl = compile(element)(scope)[0]; 27 | scope.$digest(); 28 | return compiledControl; 29 | } 30 | 31 | function waitForLoadingComplete(listView) { 32 | var loadingComplete = false; 33 | listView.addEventListener("loadingstatechanged", function (e) { 34 | if (listView.loadingState === "complete") { 35 | loadingComplete = true; 36 | } 37 | }); 38 | 39 | return function () { 40 | return loadingComplete; 41 | }; 42 | } 43 | 44 | it("should use the ListLayout defined inline", function () { 45 | var compiledControl = initControl("" + 46 | "{{item.data.title}}" + 47 | "" + 48 | ""); 49 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 50 | 51 | waitsFor(function () { 52 | return loadingComplete(); 53 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 54 | 55 | runs(function () { 56 | expect(compiledControl.winControl.layout instanceof WinJS.UI.ListLayout).toBeTruthy(); 57 | }); 58 | }); 59 | 60 | it("should use the orientation attribute on the ListLayout element", function () { 61 | var compiledControl = initControl("" + 62 | "{{item.data.title}}" + 63 | "" + 64 | ""); 65 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 66 | 67 | waitsFor(function () { 68 | return loadingComplete(); 69 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 70 | 71 | runs(function () { 72 | expect(compiledControl.winControl.layout.orientation).toEqual("horizontal"); 73 | }); 74 | }); 75 | 76 | it("should use the groupHeaderPosition attribute on the ListLayout element", function () { 77 | var compiledControl = initControl("" + 78 | "{{item.data.title}}" + 79 | "" + 80 | ""); 81 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 82 | 83 | waitsFor(function () { 84 | return loadingComplete(); 85 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 86 | 87 | runs(function () { 88 | expect(compiledControl.winControl.layout.groupHeaderPosition).toEqual("left"); 89 | }); 90 | }); 91 | 92 | it("should use the GridLayout defined inline", function () { 93 | var compiledControl = initControl("" + 94 | "{{item.data.title}}" + 95 | "" + 96 | ""); 97 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 98 | 99 | waitsFor(function () { 100 | return loadingComplete(); 101 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 102 | 103 | runs(function () { 104 | expect(compiledControl.winControl.layout instanceof WinJS.UI.GridLayout).toBeTruthy(); 105 | }); 106 | }); 107 | 108 | it("should use the orientation attribute on the GridLayout element", function () { 109 | var compiledControl = initControl("" + 110 | "{{item.data.title}}" + 111 | "" + 112 | ""); 113 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 114 | 115 | waitsFor(function () { 116 | return loadingComplete(); 117 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 118 | 119 | runs(function () { 120 | expect(compiledControl.winControl.layout.orientation).toEqual("vertical"); 121 | }); 122 | }); 123 | 124 | it("should use the groupHeaderPosition attribute on the GridLayout element", function () { 125 | var compiledControl = initControl("" + 126 | "{{item.data.title}}" + 127 | "" + 128 | ""); 129 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 130 | 131 | waitsFor(function () { 132 | return loadingComplete(); 133 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 134 | 135 | runs(function () { 136 | expect(compiledControl.winControl.layout.groupHeaderPosition).toEqual("left"); 137 | }); 138 | }); 139 | 140 | it("should use the maximumRowsOrColumns attribute on the GridLayout element", function () { 141 | var compiledControl = initControl("" + 142 | "{{item.data.title}}" + 143 | "" + 144 | ""); 145 | var loadingComplete = waitForLoadingComplete(compiledControl.winControl); 146 | 147 | waitsFor(function () { 148 | return loadingComplete(); 149 | }, "the ListView's loadingStateChanged=complete event", testTimeout); 150 | 151 | runs(function () { 152 | expect(compiledControl.winControl.layout.maximumRowsOrColumns).toEqual(3); 153 | }); 154 | }); 155 | 156 | afterEach(function () { 157 | var controls = document.querySelectorAll(".win-listview"); 158 | for (var i = 0; i < controls.length; i++) { 159 | controls[i].parentNode.removeChild(controls[i]); 160 | } 161 | WinJS.Utilities._fastAnimations = false; 162 | }); 163 | }); 164 | -------------------------------------------------------------------------------- /tests/Menu.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Menu control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple Menu", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.Menu); 28 | expect(compiledControl.className).toContain("win-menu"); 29 | }); 30 | 31 | it("should use child MenuCommands", function () { 32 | var compiledControl = initControl("" + 33 | "" + 34 | "" + 35 | ""); 36 | 37 | expect(compiledControl.winControl).toBeDefined(); 38 | expect(compiledControl.winControl instanceof WinJS.UI.Menu); 39 | expect(compiledControl.className).toContain("win-menu"); 40 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 41 | }); 42 | 43 | it("should use the alignment attribute", function () { 44 | var compiledControl = initControl(""); 45 | expect(compiledControl.winControl.alignment).toEqual("right"); 46 | }); 47 | 48 | it("should use the disabled attribute", function () { 49 | var compiledControl = initControl(""); 50 | expect(compiledControl.winControl.disabled).toBeTruthy(); 51 | }); 52 | 53 | it("should use the placement attribute", function () { 54 | var compiledControl = initControl(""); 55 | expect(compiledControl.winControl.placement).toEqual("top"); 56 | }); 57 | 58 | it("should use the onshow and onhide event handlers and hidden attribute", function () { 59 | var gotBeforeShowEvent = false, 60 | gotAfterShowEvent = false, 61 | gotBeforeHideEvent = false, 62 | gotAfterHideEvent = false; 63 | scope.beforeShowEventHandler = function (e) { 64 | gotBeforeShowEvent = true; 65 | }; 66 | scope.afterShowEventHandler = function (e) { 67 | gotAfterShowEvent = true; 68 | }; 69 | scope.beforeHideEventHandler = function (e) { 70 | gotBeforeHideEvent = true; 71 | }; 72 | scope.afterHideEventHandler = function (e) { 73 | gotAfterHideEvent = true; 74 | }; 75 | scope.menuHidden = true; 76 | var compiledControl = initControl(""); 78 | runs(function () { 79 | compiledControl.winControl.show(document.body); 80 | }); 81 | 82 | waitsFor(function () { 83 | return (gotBeforeShowEvent && gotAfterShowEvent); 84 | }, "the Menu's before+aftershow events", testTimeout); 85 | 86 | runs(function () { 87 | expect(scope.menuHidden).toBeFalsy(); 88 | scope.menuHidden = true; 89 | scope.$digest(); 90 | }); 91 | 92 | waitsFor(function () { 93 | return (gotBeforeHideEvent && gotAfterHideEvent); 94 | }, "the Menu's before+afterhide events", testTimeout); 95 | 96 | runs(function () { 97 | expect(scope.menuHidden).toBeTruthy(); 98 | expect(compiledControl.winControl.hidden).toBeTruthy(); 99 | }); 100 | }); 101 | 102 | afterEach(function () { 103 | var controls = document.querySelectorAll(".win-menu"); 104 | for (var i = 0; i < controls.length; i++) { 105 | controls[i].parentNode.removeChild(controls[i]); 106 | } 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /tests/MenuCommand.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("MenuCommand control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should use initialize a Menu containing two child MenuCommands", function () { 22 | var compiledControl = initControl("" + 23 | "" + 24 | "" + 25 | ""); 26 | 27 | var winControl = compiledControl.winControl; 28 | expect(compiledControl.winControl).toBeDefined(); 29 | expect(compiledControl.winControl instanceof WinJS.UI.Menu); 30 | expect(compiledControl.className).toContain("win-menu"); 31 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 32 | }); 33 | 34 | it("should use the id attribute on MenuCommands", function () { 35 | var compiledControl = initControl("" + 36 | "" + 37 | "" + 38 | ""); 39 | 40 | var commands = compiledControl.querySelectorAll(".win-command"); 41 | expect(commands[0].id).toEqual("command1"); 42 | expect(commands[1].id).toEqual("command2"); 43 | }); 44 | 45 | it("should use the label attribute on MenuCommands", function () { 46 | var compiledControl = initControl("" + 47 | "" + 48 | "" + 49 | ""); 50 | 51 | var commands = compiledControl.querySelectorAll(".win-command"); 52 | expect(commands[0].querySelector(".win-label").innerHTML).toEqual("command1"); 53 | expect(commands[1].querySelector(".win-label").innerHTML).toEqual("command2"); 54 | }); 55 | 56 | it("should use the disabled attribute on MenuCommands", function () { 57 | var compiledControl = initControl("" + 58 | "" + 59 | "" + 60 | ""); 61 | 62 | var commands = compiledControl.querySelectorAll(".win-command"); 63 | expect(commands[0].winControl.disabled).toBeTruthy(); 64 | expect(commands[1].winControl.disabled).toBeFalsy(); 65 | }); 66 | 67 | it("should use the extraClass attribute on MenuCommands", function () { 68 | var compiledControl = initControl("" + 69 | "" + 70 | ""); 71 | 72 | var commands = compiledControl.querySelectorAll(".win-command"); 73 | expect(commands[0].className).toContain("extraClass1"); 74 | }); 75 | 76 | it("should use the section attribute on MenuCommands", function () { 77 | var compiledControl = initControl("" + 78 | "" + 79 | "" + 80 | ""); 81 | 82 | var commands = compiledControl.querySelectorAll(".win-command"); 83 | expect(commands[0].winControl.section).toEqual("global"); 84 | expect(commands[1].winControl.section).toEqual("selection"); 85 | }); 86 | 87 | it("should use the type attribute on MenuCommands", function () { 88 | var compiledControl = initControl("" + 89 | "" + 90 | "" + 91 | ""); 92 | 93 | var commands = compiledControl.querySelectorAll(".win-command"); 94 | expect(commands[0].winControl.type).toEqual("button"); 95 | expect(commands[1].winControl.type).toEqual("toggle"); 96 | 97 | }); 98 | 99 | afterEach(function () { 100 | var controls = document.querySelectorAll(".win-menu"); 101 | for (var i = 0; i < controls.length; i++) { 102 | controls[i].parentNode.removeChild(controls[i]); 103 | } 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /tests/Pivot.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Pivot control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDatasourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | })); 15 | beforeEach(function () { 16 | WinJS.Utilities._fastAnimations = true; 17 | }); 18 | 19 | function initControl(markup) { 20 | var element = angular.element(markup)[0]; 21 | document.body.appendChild(element); 22 | var compiledControl = compile(element)(scope)[0]; 23 | scope.$digest(); 24 | return compiledControl; 25 | } 26 | 27 | it("should initialize a simple Pivot", function () { 28 | var compiledControl = initControl(""); 29 | 30 | expect(compiledControl.winControl).toBeDefined(); 31 | expect(compiledControl.winControl instanceof WinJS.UI.Pivot); 32 | expect(compiledControl.className).toContain("win-pivot"); 33 | }); 34 | 35 | it("should use the locked attribute", function () { 36 | var compiledControl = initControl(""); 37 | expect(compiledControl.winControl.locked).toBeTruthy(); 38 | }); 39 | 40 | it("should use the title attribute", function () { 41 | var compiledControl = initControl(""); 42 | expect(compiledControl.winControl.title).toEqual("PivotTitle"); 43 | }); 44 | 45 | it("should use inline pivot items", function () { 46 | var compiledControl = initControl("" + 47 | "Item1" + 48 | "Item2" + 49 | ""); 50 | // The Pivot doesn't have a loadingStateChanged event (or any similar loading complete events). 51 | // We'll use itemanimationend as a signal for loading complete. 52 | var gotItemAnimationEndEvent = false; 53 | compiledControl.addEventListener("itemanimationend", function () { 54 | gotItemAnimationEndEvent = true; 55 | }, false); 56 | waitsFor(function () { 57 | return gotItemAnimationEndEvent; 58 | }, "the Pivot to load", testTimeout); 59 | 60 | runs(function () { 61 | var pivotHeaders = compiledControl.querySelectorAll(".win-pivot-header"); 62 | var pivotItemContent = compiledControl.querySelectorAll(".win-pivot-item-content"); 63 | expect(pivotHeaders.length).toEqual(2); 64 | expect(pivotItemContent.length).toEqual(2); 65 | expect(pivotHeaders[0].innerHTML).toEqual("Header1"); 66 | expect(pivotHeaders[1].innerHTML).toEqual("Header2"); 67 | expect(pivotItemContent[0].firstElementChild.innerHTML).toEqual("Item1"); 68 | expect(pivotItemContent[1].firstElementChild.innerHTML).toEqual("Item2"); 69 | }); 70 | }); 71 | 72 | it("should use the selectedIndex attribute", function () { 73 | scope.selectedIndex = 0; 74 | var compiledControl = initControl("" + 75 | "Item1" + 76 | "Item2" + 77 | ""), 78 | pivot = compiledControl.winControl; 79 | 80 | var gotItemAnimationEndEvent = false; 81 | compiledControl.addEventListener("itemanimationend", function () { 82 | gotItemAnimationEndEvent = true; 83 | }, false); 84 | 85 | waitsFor(function () { 86 | return gotItemAnimationEndEvent; 87 | }, "the Pivot to load", testTimeout); 88 | 89 | runs(function () { 90 | gotItemAnimationEndEvent = false; 91 | expect(pivot.selectedIndex).toEqual(0); 92 | scope.selectedIndex = 1; 93 | scope.$digest(); 94 | }); 95 | 96 | waitsFor(function () { 97 | return gotItemAnimationEndEvent; 98 | }, "the Pivot to change pages", testTimeout); 99 | 100 | runs(function () { 101 | expect(pivot.selectedIndex).toEqual(1); 102 | }); 103 | }); 104 | 105 | it("should use the selectedItem attribute", function () { 106 | scope.selectedItem = null; 107 | var compiledControl = initControl("" + 108 | "Item1" + 109 | "Item2" + 110 | ""), 111 | pivot = compiledControl.winControl; 112 | 113 | var gotItemAnimationEndEvent = false; 114 | compiledControl.addEventListener("itemanimationend", function () { 115 | gotItemAnimationEndEvent = true; 116 | }, false); 117 | 118 | waitsFor(function () { 119 | return gotItemAnimationEndEvent; 120 | }, "the Pivot to load", testTimeout); 121 | 122 | runs(function () { 123 | gotItemAnimationEndEvent = false; 124 | expect(pivot.selectedIndex).toEqual(0); 125 | scope.selectedItem = compiledControl.querySelectorAll(".win-pivot-item")[1].winControl; 126 | scope.$digest(); 127 | }); 128 | 129 | waitsFor(function () { 130 | return gotItemAnimationEndEvent; 131 | }, "the Pivot to change pages", testTimeout); 132 | 133 | runs(function () { 134 | expect(pivot.selectedIndex).toEqual(1); 135 | }); 136 | }); 137 | 138 | it("should use the on-item-animation-end event handler", function () { 139 | var gotItemAnimationEndEvent = false; 140 | scope.itemAnimationEndHandler = function (e) { 141 | gotItemAnimationEndEvent = true; 142 | }; 143 | var compiledControl = initControl("" + 144 | "Item1" + 145 | ""); 146 | waitsFor(function () { 147 | return gotItemAnimationEndEvent; 148 | }, "the Pivot to fire animation events", testTimeout); 149 | }); 150 | 151 | it("should use the custom header attributes", function () { 152 | scope.customLeftHeader = document.createElement("div"); 153 | scope.customRightHeader = document.createElement("div"); 154 | var control = initControl("" + 155 | "Item1" + 156 | "").winControl; 157 | 158 | expect(control.customLeftHeader).toEqual(scope.customLeftHeader); 159 | expect(control.customRightHeader).toEqual(scope.customRightHeader); 160 | }); 161 | 162 | it("should use the custom header directives", function () { 163 | var control = initControl("" + 164 | "LeftHeader" + 165 | "Item1" + 166 | "RightHeader" + 167 | "").winControl; 168 | 169 | expect(control.customLeftHeader.firstElementChild.innerHTML).toEqual("LeftHeader"); 170 | expect(control.customRightHeader.firstElementChild.innerHTML).toEqual("RightHeader"); 171 | }); 172 | 173 | it("should render child WinJS controls that need to measure", function () { 174 | var listViewLoaded; 175 | scope.onListViewStateChanged = function (e) { 176 | if (e.currentTarget.winControl && e.currentTarget.winControl.loadingState === "complete") { 177 | listViewLoaded = true; 178 | } 179 | }; 180 | scope.childData = [1, 2, 3]; 181 | var compiledControl = initControl("" + 182 | "" + 183 | ""); 184 | 185 | waitsFor(function () { 186 | return listViewLoaded; 187 | }, "the child ListView to load", testTimeout); 188 | 189 | runs(function () { 190 | expect(compiledControl.querySelectorAll(".win-item").length > 0); 191 | }); 192 | }); 193 | 194 | it("should let ng-repeat add new pivot items", function () { 195 | scope.items = [ 196 | { title: "Item0" }, 197 | { title: "Item1" } 198 | ]; 199 | var compiledControl = initControl("" + 200 | "" + 201 | ""); 202 | 203 | var gotItemAnimationEndEvent = false; 204 | compiledControl.addEventListener("itemanimationend", function () { 205 | gotItemAnimationEndEvent = true; 206 | }, false); 207 | waitsFor(function () { 208 | return gotItemAnimationEndEvent; 209 | }, "the Pivot to load", testTimeout); 210 | 211 | runs(function () { 212 | var pivotHeaders = compiledControl.querySelectorAll(".win-pivot-header"); 213 | expect(pivotHeaders.length).toEqual(2); 214 | expect(pivotHeaders[0].innerHTML).toEqual("Item0"); 215 | expect(pivotHeaders[1].innerHTML).toEqual("Item1"); 216 | scope.items.push({ title: "NewItem" }); 217 | scope.$digest(); 218 | pivotHeaders = compiledControl.querySelectorAll(".win-pivot-header"); 219 | expect(pivotHeaders.length).toEqual(3); 220 | expect(pivotHeaders[0].innerHTML).toEqual("Item0"); 221 | expect(pivotHeaders[1].innerHTML).toEqual("Item1"); 222 | expect(pivotHeaders[2].innerHTML).toEqual("NewItem"); 223 | }); 224 | }); 225 | 226 | afterEach(function () { 227 | var controls = document.querySelectorAll(".win-pivot"); 228 | for (var i = 0; i < controls.length; i++) { 229 | controls[i].parentNode.removeChild(controls[i]); 230 | } 231 | WinJS.Utilities._fastAnimations = false; 232 | }); 233 | }); 234 | -------------------------------------------------------------------------------- /tests/Rating.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Rating control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple Rating control", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.Rating); 26 | expect(compiledControl.className).toContain("win-rating"); 27 | }); 28 | 29 | it("should use rating attributes", function () { 30 | var compiledControl = initControl(""); 31 | 32 | var winControl = compiledControl.winControl; 33 | expect(winControl.maxRating).toEqual(10); 34 | expect(winControl.userRating).toEqual(9); 35 | expect(winControl.averageRating).toEqual(3); 36 | }); 37 | 38 | it("should use the diabled attribute", function () { 39 | var compiledControl = initControl(""); 40 | 41 | expect(compiledControl.winControl.disabled).toBeTruthy(); 42 | }); 43 | 44 | afterEach(function () { 45 | var controls = document.querySelectorAll(".win-rating"); 46 | for (var i = 0; i < controls.length; i++) { 47 | controls[i].parentNode.removeChild(controls[i]); 48 | } 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /tests/SemanticZoom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("SemanticZoom control directive tests", function () { 4 | var testTimeout = 5000, 5 | testDatasourceLength = 5; 6 | 7 | var scope, 8 | compile; 9 | 10 | beforeEach(angular.mock.module("winjs")); 11 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 12 | scope = $rootScope.$new(); 13 | compile = $compile; 14 | scope.rawData = []; 15 | for (var i = 0; i < testDatasourceLength; i++) { 16 | scope.rawData.push({ title: "Item" + i }); 17 | } 18 | function simpleGroupingFunction(data) { 19 | return data.title; 20 | } 21 | scope.zoomedInSource = new WinJS.Binding.List(scope.rawData).createGrouped(simpleGroupingFunction, simpleGroupingFunction); 22 | scope.zoomedOutSource = scope.zoomedInSource.groups; 23 | })); 24 | beforeEach(function () { 25 | WinJS.Utilities._fastAnimations = true; 26 | }); 27 | 28 | function initControl(markup) { 29 | var element = angular.element(markup)[0]; 30 | document.body.appendChild(element); 31 | var compiledControl = compile(element)(scope)[0]; 32 | scope.$digest(); 33 | return compiledControl; 34 | } 35 | 36 | it("should initialize a simple SemanticZoom", function () { 37 | var compiledControl = initControl("" + 38 | "" + 39 | "" + 40 | ""); 41 | 42 | expect(compiledControl.winControl).toBeDefined(); 43 | expect(compiledControl.winControl instanceof WinJS.UI.SemanticZoom); 44 | expect(compiledControl.className).toContain("win-semanticzoom"); 45 | }); 46 | 47 | it("should use the enableButton attribute", function () { 48 | var compiledControl = initControl("" + 49 | "" + 50 | "" + 51 | ""); 52 | 53 | expect(compiledControl.winControl.enableButton).toBeFalsy(); 54 | }); 55 | 56 | it("should use the zoomFactor attribute", function () { 57 | var compiledControl = initControl("" + 58 | "" + 59 | "" + 60 | ""); 61 | 62 | expect(compiledControl.winControl.zoomFactor).toEqual(0.25); 63 | }); 64 | 65 | it("should use the onZoomChanged event handler", function () { 66 | var gotZoomChangedEvent = false; 67 | scope.zoomChangedHandler = function (e) { 68 | gotZoomChangedEvent = true; 69 | }; 70 | var compiledControl = initControl("" + 71 | "" + 72 | "" + 73 | ""); 74 | 75 | compiledControl.winControl.zoomedOut = true; 76 | waitsFor(function () { 77 | return gotZoomChangedEvent; 78 | }, "SemanticZoom's onZoomChanged event") 79 | }); 80 | 81 | afterEach(function () { 82 | var controls = document.querySelectorAll(".win-semanticzoom"); 83 | for (var i = 0; i < controls.length; i++) { 84 | controls[i].parentNode.removeChild(controls[i]); 85 | } 86 | WinJS.Utilities._fastAnimations = false; 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /tests/SplitView.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("SplitView control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | beforeEach(function () { 15 | WinJS.Utilities._fastAnimations = true; 16 | }); 17 | 18 | function initControl(markup) { 19 | var element = angular.element(markup)[0]; 20 | document.body.appendChild(element); 21 | var compiledControl = compile(element)(scope)[0]; 22 | scope.$digest(); 23 | return compiledControl; 24 | } 25 | 26 | it("should initialize a simple SplitView", function () { 27 | var compiledControl = initControl(""); 28 | 29 | expect(compiledControl.winControl).toBeDefined(); 30 | expect(compiledControl.winControl instanceof WinJS.UI.SplitView); 31 | expect(compiledControl.className).toContain("win-splitview"); 32 | }); 33 | 34 | it("should use the closedDisplayMode attribute", function () { 35 | var compiledControl = initControl(""); 36 | expect(compiledControl.winControl.closedDisplayMode).toEqual("inline"); 37 | }); 38 | 39 | it("should use the openedDisplayMode attribute", function () { 40 | var compiledControl = initControl(""); 41 | expect(compiledControl.winControl.openedDisplayMode).toEqual("inline"); 42 | }); 43 | 44 | it("should use the panePlacement attribute", function () { 45 | var compiledControl = initControl(""); 46 | expect(compiledControl.winControl.panePlacement).toEqual("top"); 47 | }); 48 | 49 | it("should use inline content and pane nodes", function () { 50 | var compiledControl = initControl("" + 51 | "" + 52 | "" + 53 | ""); 54 | 55 | var splitview = compiledControl.winControl; 56 | expect(splitview.paneElement.querySelectorAll(".paneShouldBeInDom").length).toEqual(1); 57 | expect(splitview.contentElement.querySelectorAll(".contentShouldBeInDom").length).toEqual(1); 58 | }); 59 | 60 | it("should use inline content and pane nodes regardless of the order they are defined in", function () { 61 | var compiledControl = initControl("" + 62 | "" + 63 | "" + 64 | ""); 65 | 66 | var splitview = compiledControl.winControl; 67 | expect(splitview.paneElement.querySelectorAll(".paneShouldBeInDom").length).toEqual(1); 68 | expect(splitview.contentElement.querySelectorAll(".contentShouldBeInDom").length).toEqual(1); 69 | }); 70 | 71 | it("should accept multiple splitview content nodes", function () { 72 | var compiledControl = initControl("" + 73 | "" + 74 | "" + 75 | "" + 76 | ""); 77 | 78 | var splitview = compiledControl.winControl; 79 | expect(splitview.contentElement.querySelectorAll(".shouldBeInDom").length).toEqual(3); 80 | expect(splitview.paneElement.querySelectorAll(".shouldBeInDom").length).toEqual(0); 81 | }); 82 | 83 | it("should ignore additional inline panes", function () { 84 | var compiledControl = initControl("" + 85 | "" + 86 | "" + 87 | ""); 88 | expect(compiledControl.querySelectorAll(".shouldBeInDom").length).toEqual(1); 89 | expect(compiledControl.querySelectorAll(".shouldNotBeInDom").length).toEqual(0); 90 | }); 91 | 92 | it("should use the open and close event handlers and paneOpened attribute", function () { 93 | var gotBeforeOpenEvent = false, 94 | gotAfterOpenEvent = false, 95 | gotBeforeCloseEvent = false, 96 | gotAfterCloseEvent = false; 97 | scope.beforeOpenEventHandler = function (e) { 98 | gotBeforeOpenEvent = true; 99 | }; 100 | scope.afterOpenEventHandler = function (e) { 101 | gotAfterOpenEvent = true; 102 | }; 103 | scope.beforeCloseEventHandler = function (e) { 104 | gotBeforeCloseEvent = true; 105 | }; 106 | scope.afterCloseEventHandler = function (e) { 107 | gotAfterCloseEvent = true; 108 | }; 109 | scope.paneOpened = false; 110 | var compiledControl = initControl(""); 112 | 113 | runs(function () { 114 | compiledControl.winControl.openPane(); 115 | }); 116 | 117 | waitsFor(function () { 118 | return (gotBeforeOpenEvent && gotAfterOpenEvent); 119 | }, "the SplitView's before+aftershow events", testTimeout); 120 | 121 | runs(function () { 122 | expect(scope.paneOpened).toBeTruthy(); 123 | scope.paneOpened = false; 124 | scope.$digest(); 125 | }); 126 | 127 | waitsFor(function () { 128 | return (gotBeforeCloseEvent && gotAfterCloseEvent); 129 | }, "the SplitView's before+afterhide events", testTimeout); 130 | }); 131 | 132 | afterEach(function () { 133 | var controls = document.querySelectorAll(".win-splitview"); 134 | for (var i = 0; i < controls.length; i++) { 135 | controls[i].parentNode.removeChild(controls[i]); 136 | } 137 | WinJS.Utilities._fastAnimations = false; 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /tests/SplitViewCommand.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("SplitViewCommand control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple SplitViewCommand", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.SplitViewCommand); 26 | expect(compiledControl.className).toContain("win-splitviewcommand"); 27 | }); 28 | 29 | it("should use the label attribute", function () { 30 | var compiledControl = initControl(""); 31 | 32 | expect(compiledControl.querySelector(".win-splitviewcommand-label").innerHTML).toEqual("add"); 33 | }); 34 | 35 | it("should use the onInvoked attribute", function () { 36 | var gotInvokedEvent = false; 37 | scope.onInvoked = function () { 38 | gotInvokedEvent = true; 39 | }; 40 | var compiledControl = initControl(""); 41 | var button = compiledControl.querySelector(".win-splitviewcommand-button"); 42 | expect(gotInvokedEvent).toBeFalsy(); 43 | button.click(); 44 | expect(gotInvokedEvent).toBeTruthy(); 45 | }); 46 | 47 | afterEach(function () { 48 | var controls = document.querySelectorAll(".win-splitviewcommand"); 49 | for (var i = 0; i < controls.length; i++) { 50 | controls[i].parentNode.removeChild(controls[i]); 51 | } 52 | }); 53 | }); 54 | 55 | -------------------------------------------------------------------------------- /tests/SplitViewPaneToggle.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("SplitViewPaneToggle control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple SplitViewPaneToggle", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.SplitViewPaneToggle); 26 | expect(compiledControl.className).toContain("win-splitviewpanetoggle"); 27 | }); 28 | 29 | it("should use the splitView attribute", function () { 30 | scope.splitView = new WinJS.UI.SplitView().element; 31 | var control = initControl("").winControl; 32 | 33 | expect(control.splitView).toEqual(scope.splitView); 34 | }); 35 | 36 | it("should use the onInvoked attribute", function () { 37 | var gotInvokedEvent = false; 38 | scope.onInvoked = function () { 39 | gotInvokedEvent = true; 40 | }; 41 | var compiledControl = initControl(""); 42 | expect(gotInvokedEvent).toBeFalsy(); 43 | compiledControl.click(); 44 | expect(gotInvokedEvent).toBeTruthy(); 45 | }); 46 | 47 | afterEach(function () { 48 | var controls = document.querySelectorAll(".win-splitviewpanetoggle"); 49 | for (var i = 0; i < controls.length; i++) { 50 | controls[i].parentNode.removeChild(controls[i]); 51 | } 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /tests/TimePicker.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("TimePicker control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple TimePicker", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.TimePicker); 26 | expect(compiledControl.className).toContain("win-timepicker"); 27 | }); 28 | 29 | it("should use the clock attribute", function () { 30 | scope.testClock = "24HourClock"; 31 | var compiledControl = initControl(""); 32 | 33 | expect(compiledControl.winControl.clock).toBe("24HourClock"); 34 | }); 35 | 36 | it("should use the disabled attribute", function () { 37 | var compiledControl = initControl(""); 38 | 39 | expect(compiledControl.winControl.disabled).toBeTruthy(); 40 | }); 41 | 42 | it("should use the current attribute", function () { 43 | scope.testDate = new Date(2000, 1, 1, 11, 12); 44 | var compiledControl = initControl(""); 45 | 46 | var winControl = compiledControl.winControl; 47 | expect(winControl.current.getHours()).toBe(11); 48 | expect(winControl.current.getMinutes()).toBe(12); 49 | }); 50 | 51 | it("should use the minuteIncrement attribute", function () { 52 | var compiledControl = initControl(""); 53 | 54 | expect(compiledControl.winControl.minuteIncrement).toBe(10); 55 | }); 56 | 57 | afterEach(function () { 58 | var controls = document.querySelectorAll(".win-timepicker"); 59 | for (var i = 0; i < controls.length; i++) { 60 | controls[i].parentNode.removeChild(controls[i]); 61 | } 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /tests/ToggleSwitch.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ToggleSwitch control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple toggle switch", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.ToggleSwitch); 26 | expect(compiledControl.className).toContain("win-toggleswitch"); 27 | }); 28 | 29 | it("should use the checked attribute", function () { 30 | var compiledControl = initControl(""); 31 | 32 | var winControl = compiledControl.winControl; 33 | expect(winControl.checked).toBeTruthy(); 34 | }); 35 | 36 | it("should use label attributes", function () { 37 | var compiledControl = initControl(""); 38 | 39 | expect(compiledControl.querySelector(".win-toggleswitch-value-on").innerHTML).toBe("onLabel"); 40 | expect(compiledControl.querySelector(".win-toggleswitch-value-off").innerHTML).toBe("offLabel"); 41 | }); 42 | 43 | it("should use the title attribute", function () { 44 | var compiledControl = initControl(""); 45 | 46 | expect(compiledControl.querySelector(".win-toggleswitch-header").innerHTML).toBe("toggleTitle"); 47 | }); 48 | 49 | it("should use the disabled attribute", function () { 50 | var compiledControl = initControl(""); 51 | 52 | expect(compiledControl.winControl.disabled).toBeTruthy(); 53 | }); 54 | 55 | it("should allow event handlers to be set up in markup", function () { 56 | var eventHandlerCalled = false; 57 | scope.changedEventHandler = function (e) { 58 | eventHandlerCalled = true; 59 | }; 60 | scope.isChecked = false; 61 | var compiledControl = initControl(""); 62 | 63 | var winControl = compiledControl.winControl; 64 | expect(winControl.checked).toBeFalsy(); 65 | scope.isChecked = true; 66 | scope.$digest(); 67 | expect(winControl.checked).toBeTruthy(); 68 | expect(eventHandlerCalled).toBeTruthy(); 69 | }); 70 | 71 | afterEach(function () { 72 | var controls = document.querySelectorAll(".win-toggleswitch"); 73 | for (var i = 0; i < controls.length; i++) { 74 | controls[i].parentNode.removeChild(controls[i]); 75 | } 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /tests/ToolBar.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ToolBar control directive tests", function () { 4 | var testTimeout = 5000; 5 | 6 | var scope, 7 | compile; 8 | 9 | beforeEach(angular.mock.module("winjs")); 10 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 11 | scope = $rootScope.$new(); 12 | compile = $compile; 13 | })); 14 | 15 | function initControl(markup) { 16 | var element = angular.element(markup)[0]; 17 | document.body.appendChild(element); 18 | var compiledControl = compile(element)(scope)[0]; 19 | scope.$digest(); 20 | return compiledControl; 21 | } 22 | 23 | it("should initialize a simple ToolBar", function () { 24 | var compiledControl = initControl(""); 25 | 26 | expect(compiledControl.winControl).toBeDefined(); 27 | expect(compiledControl.winControl instanceof WinJS.UI.ToolBar); 28 | expect(compiledControl.className).toContain("win-toolbar"); 29 | }); 30 | 31 | it("should use child ToolBarCommands", function () { 32 | var compiledControl = initControl("" + 33 | "" + 34 | "" + 35 | ""); 36 | 37 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 38 | }); 39 | 40 | it("should use the closedDisplayMode attribute", function () { 41 | var compiledControl = initControl(""); 42 | expect(compiledControl.winControl.closedDisplayMode).toEqual("full"); 43 | }); 44 | 45 | it("should use the onopen and onclose event handlers and opened attribute", function () { 46 | var gotBeforeOpenEvent = false, 47 | gotAfterOpenEvent = false, 48 | gotBeforeCloseEvent = false, 49 | gotAfterCloseEvent = false; 50 | scope.beforeOpenEventHandler = function (e) { 51 | gotBeforeOpenEvent = true; 52 | }; 53 | scope.afterOpenEventHandler = function (e) { 54 | gotAfterOpenEvent = true; 55 | }; 56 | scope.beforeCloseEventHandler = function (e) { 57 | gotBeforeCloseEvent = true; 58 | }; 59 | scope.afterCloseEventHandler = function (e) { 60 | gotAfterCloseEvent = true; 61 | }; 62 | scope.toolbarOpened = false; 63 | var compiledControl = initControl(""); 65 | runs(function () { 66 | compiledControl.winControl.open(); 67 | }); 68 | 69 | waitsFor(function () { 70 | return (gotBeforeOpenEvent && gotAfterOpenEvent); 71 | }, "the ToolBar's before+aftershow events", testTimeout); 72 | 73 | runs(function () { 74 | expect(scope.toolbarOpened).toBeTruthy(); 75 | scope.toolbarOpened = false; 76 | scope.$digest(); 77 | }); 78 | 79 | waitsFor(function () { 80 | return (gotBeforeCloseEvent && gotAfterCloseEvent); 81 | }, "the ToolBar's before+afterhide events", testTimeout); 82 | }); 83 | 84 | afterEach(function () { 85 | var controls = document.querySelectorAll(".win-toolbar"); 86 | for (var i = 0; i < controls.length; i++) { 87 | controls[i].parentNode.removeChild(controls[i]); 88 | } 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /tests/ToolBarCommand.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("ToolBarCommand control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should use initialize a ToolBar containing two child ToolBarCommands", function () { 22 | var compiledControl = initControl("" + 23 | "" + 24 | "" + 25 | ""); 26 | 27 | var winControl = compiledControl.winControl; 28 | expect(compiledControl.winControl).toBeDefined(); 29 | expect(compiledControl.winControl instanceof WinJS.UI.ToolBar); 30 | expect(compiledControl.className).toContain("win-toolbar"); 31 | expect(compiledControl.querySelectorAll(".win-command").length).toEqual(2); 32 | }); 33 | 34 | it("should use the id attribute on ToolBarCommands", function () { 35 | var compiledControl = initControl("" + 36 | "" + 37 | "" + 38 | ""); 39 | 40 | var commands = compiledControl.querySelectorAll(".win-command"); 41 | expect(commands[0].id).toEqual("command1"); 42 | expect(commands[1].id).toEqual("command2"); 43 | }); 44 | 45 | it("should use the label attribute on ToolBarCommands", function () { 46 | var compiledControl = initControl("" + 47 | "" + 48 | "" + 49 | ""); 50 | 51 | var commands = compiledControl.querySelectorAll(".win-command"); 52 | expect(commands[0].querySelector(".win-label").innerHTML).toEqual("command1"); 53 | expect(commands[1].querySelector(".win-label").innerHTML).toEqual("command2"); 54 | }); 55 | 56 | it("should use the disabled attribute on ToolBarCommands", function () { 57 | var compiledControl = initControl("" + 58 | "" + 59 | "" + 60 | ""); 61 | 62 | var commands = compiledControl.querySelectorAll(".win-command"); 63 | expect(commands[0].winControl.disabled).toBeTruthy(); 64 | expect(commands[1].winControl.disabled).toBeFalsy(); 65 | }); 66 | 67 | it("should use the extraClass attribute on ToolBarCommands", function () { 68 | var compiledControl = initControl("" + 69 | "" + 70 | ""); 71 | 72 | var commands = compiledControl.querySelectorAll(".win-command"); 73 | expect(commands[0].className).toContain("extraClass1"); 74 | }); 75 | 76 | it("should use the section attribute on ToolBarCommands", function () { 77 | var compiledControl = initControl("" + 78 | "" + 79 | "" + 80 | ""); 81 | 82 | var commands = compiledControl.querySelectorAll(".win-command"); 83 | expect(commands[0].winControl.section).toEqual("global"); 84 | expect(commands[1].winControl.section).toEqual("selection"); 85 | }); 86 | 87 | afterEach(function () { 88 | var controls = document.querySelectorAll(".win-toolbar"); 89 | for (var i = 0; i < controls.length; i++) { 90 | controls[i].parentNode.removeChild(controls[i]); 91 | } 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /tests/Tooltip.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corp. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. 2 | 3 | describe("Tooltip control directive tests", function () { 4 | var scope, 5 | compile; 6 | 7 | beforeEach(angular.mock.module("winjs")); 8 | beforeEach(angular.mock.inject(function ($rootScope, $compile) { 9 | scope = $rootScope.$new(); 10 | compile = $compile; 11 | })); 12 | 13 | function initControl(markup) { 14 | var element = angular.element(markup)[0]; 15 | document.body.appendChild(element); 16 | var compiledControl = compile(element)(scope)[0]; 17 | scope.$digest(); 18 | return compiledControl; 19 | } 20 | 21 | it("should initialize a simple Tooltip", function () { 22 | var compiledControl = initControl(""); 23 | 24 | expect(compiledControl.winControl).toBeDefined(); 25 | expect(compiledControl.winControl instanceof WinJS.UI.Tooltip); 26 | compiledControl.parentNode.removeChild(compiledControl); 27 | }); 28 | 29 | it("should initialize the infotip attribute", function () { 30 | var compiledControl = initControl(""); 31 | expect(compiledControl.winControl.infotip).toBeTruthy(); 32 | compiledControl.parentNode.removeChild(compiledControl); 33 | }); 34 | 35 | it("should initialize the placement attribute", function () { 36 | var compiledControl = initControl(""); 37 | expect(compiledControl.winControl.placement).toEqual("right"); 38 | compiledControl.parentNode.removeChild(compiledControl); 39 | }); 40 | }); 41 | --------------------------------------------------------------------------------