├── docs
├── library.jsx
├── brandai.json
├── package.json
├── webpack.config.js
├── gulpfile.js
└── README.md
├── .gitignore
├── examples
├── address-book
│ ├── profile.png
│ ├── README.md
│ ├── package.json
│ ├── webpack.config.js
│ ├── OtherPage.jsx
│ ├── ProfilePicture.jsx
│ ├── index.html
│ ├── main.css
│ ├── index.jsx
│ ├── FakeData.js
│ └── PeoplePage.jsx
├── showcase
│ ├── examples
│ │ ├── BackButton.jsx
│ │ ├── Tooltip.jsx
│ │ ├── Flyout.jsx
│ │ ├── DatePicker.jsx
│ │ ├── Pivot.jsx
│ │ ├── FlipView.jsx
│ │ ├── ToggleSwitch.jsx
│ │ ├── ItemContainer.jsx
│ │ ├── TimePicker.jsx
│ │ ├── Rating.jsx
│ │ ├── ContentDialog.jsx
│ │ ├── ListView.jsx
│ │ ├── Hub.jsx
│ │ ├── SplitView.jsx
│ │ ├── Menu.jsx
│ │ ├── AutoSuggestBox.jsx
│ │ ├── SemanticZoom.jsx
│ │ ├── AppBar.jsx
│ │ └── ToolBar.jsx
│ ├── README.md
│ ├── package.json
│ ├── webpack.config.js
│ ├── index.html
│ └── index.jsx
└── movies
│ ├── package.json
│ ├── README.md
│ ├── webpack.config.js
│ ├── Score.jsx
│ ├── index.html
│ ├── DetailPage.jsx
│ ├── SearchPage.jsx
│ ├── index.jsx
│ └── FakeData.js
├── bower.json
├── React.WinJS.nuspec
├── package.json
├── LICENSE.txt
├── tasks
└── check-bom.js
├── README.md
├── Gruntfile.js
└── react-winjs.js
/docs/library.jsx:
--------------------------------------------------------------------------------
1 | module.exports = require('../react-winjs.js');
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | .DS_Store
4 | browser-bundle.js
5 | npm-debug.log
6 |
--------------------------------------------------------------------------------
/examples/address-book/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/winjs/react-winjs/HEAD/examples/address-book/profile.png
--------------------------------------------------------------------------------
/docs/brandai.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs-brandai",
3 | "libraryPath": "../",
4 | "dist": "dist",
5 | "libraryObjectName": "ReactWinJS",
6 | "reactVersion": "15.0.1",
7 | "dynamicExtraction": true,
8 | "fileOrder": ["base.min.js", "ui.min.js"]
9 | }
10 |
--------------------------------------------------------------------------------
/examples/showcase/examples/BackButton.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | render: function () {
8 | return (
9 |
10 | );
11 | }
12 | });
--------------------------------------------------------------------------------
/examples/showcase/README.md:
--------------------------------------------------------------------------------
1 | # react-winjs Showcase
2 |
3 | This example demonstrates each of the `react-winjs` components. See it in action [here](http://winjs.github.io/react-winjs/examples/showcase/index.html).
4 |
5 | ## Usage
6 |
7 | ```
8 | npm install
9 | npm start
10 | ```
11 |
12 | Open `index.html` in your browser.
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs-brandai-config",
3 | "version": "0.0.0",
4 | "description": "Configuration for brand.ai component documentation",
5 | "author": "",
6 | "license": "",
7 | "dependencies": {},
8 | "devDependencies": {
9 | "gulp": "^3.9.0",
10 | "gulp-util": "^3.0.6",
11 | "jsx-loader": "^0.13.2",
12 | "webpack": "^1.12.2",
13 | "winjs": "^4.4.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/movies/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs-movies",
3 | "version": "0.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack --progress --colors --watch",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "",
12 | "devDependencies": {
13 | "jsx-loader": "^0.13.2",
14 | "webpack": "^1.9.4"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/address-book/README.md:
--------------------------------------------------------------------------------
1 | # react-winjs Address Book
2 |
3 | This example demonstrates using `react-winjs` components to build an adaptive app for managing an address book. It works well at mobile, tablet, and desktop screen sizes. See it in action [here](http://winjs.github.io/react-winjs/examples/address-book/index.html).
4 |
5 | ## Usage
6 |
7 | ```
8 | npm install
9 | npm start
10 | ```
11 |
12 | Open `index.html` in your browser.
--------------------------------------------------------------------------------
/examples/showcase/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs-showcase",
3 | "version": "0.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack --progress --colors --watch",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "",
12 | "devDependencies": {
13 | "jsx-loader": "^0.13.2",
14 | "webpack": "^1.9.4"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/address-book/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs-address-book",
3 | "version": "0.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack --progress --colors --watch",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "",
12 | "devDependencies": {
13 | "jsx-loader": "^0.13.2",
14 | "webpack": "^1.9.4"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/movies/README.md:
--------------------------------------------------------------------------------
1 | # react-winjs Movies
2 |
3 | This example demonstrates a couple of `react-winjs` components in a small app for looking up movies. See it in action [here](http://winjs.github.io/react-winjs/examples/movies/index.html).
4 |
5 | It is inspired by the [react-native movies example](https://github.com/facebook/react-native/tree/master/Examples/Movies).
6 |
7 | ## Usage
8 |
9 | ```
10 | npm install
11 | npm start
12 | ```
13 |
14 | Open `index.html` in your browser.
--------------------------------------------------------------------------------
/docs/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | /*
3 | Export react-winjs as a library object (a ReactWinJS var).
4 | */
5 | module.exports = {
6 | entry: './library.jsx',
7 | output: {
8 | filename: 'dist/browser-bundle.js',
9 | library: 'ReactWinJS',
10 | libraryTarget: 'var'
11 | },
12 | module: {
13 | loaders: [
14 | {test: /\.jsx/, loader: 'jsx-loader'}
15 | ]
16 | },
17 | externals: {
18 | 'react': 'React',
19 | 'react/addons': 'React'
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/examples/movies/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | cache: true,
5 | entry: './index.jsx',
6 | output: {
7 | filename: 'browser-bundle.js'
8 | },
9 | module: {
10 | loaders: [
11 | {test: /\.jsx/, loader: 'jsx-loader'}
12 | ]
13 | },
14 | resolve: {
15 | alias: {
16 | 'react-winjs': path.join(__dirname, '../../react-winjs')
17 | }
18 | },
19 | externals: {
20 | 'react': 'React',
21 | 'react-dom': 'ReactDOM'
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/examples/showcase/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | cache: true,
5 | entry: './index.jsx',
6 | output: {
7 | filename: 'browser-bundle.js'
8 | },
9 | module: {
10 | loaders: [
11 | {test: /\.jsx/, loader: 'jsx-loader'}
12 | ]
13 | },
14 | resolve: {
15 | alias: {
16 | 'react-winjs': path.join(__dirname, '../../react-winjs')
17 | }
18 | },
19 | externals: {
20 | 'react': 'React',
21 | 'react-dom': 'ReactDOM'
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/examples/address-book/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | cache: true,
5 | entry: './index.jsx',
6 | output: {
7 | filename: 'browser-bundle.js'
8 | },
9 | module: {
10 | loaders: [
11 | {test: /\.jsx/, loader: 'jsx-loader'}
12 | ]
13 | },
14 | resolve: {
15 | alias: {
16 | 'react-winjs': path.join(__dirname, '../../react-winjs')
17 | }
18 | },
19 | externals: {
20 | 'react': 'React',
21 | 'react-dom': 'ReactDOM'
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/examples/showcase/examples/Tooltip.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | render: function () {
8 | var contentComponent =
This can contain arbitrary content, like images
;
9 |
10 | return (
11 |
13 | This has a tooltip, hover and see...
14 |
15 | );
16 | }
17 | });
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs",
3 | "main": "react-winjs.js",
4 | "homepage": "https://github.com/winjs/react-winjs",
5 | "authors": [
6 | "Microsoft Corporation and other contributors"
7 | ],
8 | "description": "React wrapper around WinJS's controls",
9 | "keywords": [
10 | "winjs",
11 | "react"
12 | ],
13 | "license": "MIT",
14 | "ignore": [
15 | "**/.*",
16 | "node_modules",
17 | "bower_components",
18 | "test",
19 | "tests",
20 | "examples",
21 | "package.json",
22 | "*.nuspec",
23 | "Gruntfile.js"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/examples/address-book/OtherPage.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 |
5 | var urlToContent = {
6 | "new": "What's New",
7 | groups: "Groups",
8 | settings: "Settings"
9 | };
10 |
11 | var OtherPage = React.createClass({
12 | propTypes: {
13 | location: React.PropTypes.array.isRequired
14 | },
15 | render: function () {
16 | var title = urlToContent[this.props.location] || "Other";
17 | return {title}
18 | }
19 | });
20 |
21 | module.exports = OtherPage;
22 |
--------------------------------------------------------------------------------
/examples/movies/Score.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | function formattedScore(score) {
4 | return score >= 0 ? score + "%" : "N/A";
5 | }
6 |
7 | var maxColor = 200;
8 | function colorForScore(score) {
9 | if (score >= 0) {
10 | var scoreAsColor = Math.round(score / 100 * maxColor);
11 | return "rgb(" + [maxColor - scoreAsColor, scoreAsColor, 0].join(",") + ")";
12 | } else {
13 | return "rgb(0, 0, 0)";
14 | }
15 |
16 | }
17 |
18 | function textColoredForScore(text, score) {
19 | return {text} ;
20 | }
21 |
22 | module.exports = {
23 | formattedScore: formattedScore,
24 | textColoredForScore: textColoredForScore
25 | };
--------------------------------------------------------------------------------
/examples/showcase/examples/Flyout.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleShow: function (eventObject) {
8 | var anchor = eventObject.currentTarget;
9 | this.refs.flyout.winControl.show(anchor);
10 | },
11 | render: function () {
12 | return (
13 |
14 |
Show Flyout
15 |
16 |
17 | This is the flyout content!!
18 |
19 |
20 | );
21 | }
22 | });
--------------------------------------------------------------------------------
/React.WinJS.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React.WinJS
5 | 1.0.0
6 | Microsoft Corporation and other contributors
7 | https://raw.githubusercontent.com/winjs/react-winjs/master/LICENSE.txt
8 | https://github.com/winjs/react-winjs
9 | false
10 | React wrapper around WinJS's controls
11 | winjs react
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require("gulp");
2 | var gutil = require("gulp-util");
3 | var webpack = require("webpack");
4 |
5 | gulp.task("build", ["build:webpack", "build:winjs"]);
6 |
7 | /*
8 | Copy over core winjs files to the dist folder
9 | */
10 | gulp.task("build:winjs", function() {
11 | return gulp.src([
12 | 'node_modules/winjs/js/base.min.js',
13 | 'node_modules/winjs/js/ui.min.js',
14 | 'node_modules/winjs/css/ui-light.min.css',
15 | 'node_modules/winjs/fonts/*'
16 | ], { base: 'node_modules/winjs' }).pipe(gulp.dest('dist'))
17 | });
18 |
19 | /*
20 | Build library
21 | */
22 | gulp.task("build:webpack", function(callback) {
23 | webpack(require('./webpack.config'), function(err, stats) {
24 | if(err) throw new gutil.PluginError("webpack", err);
25 | gutil.log("[webpack]", stats.toString());
26 | callback();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-winjs",
3 | "version": "2.5.0",
4 | "description": "React wrapper around WinJS's controls",
5 | "main": "react-winjs.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "winjs",
11 | "react"
12 | ],
13 | "author": "Microsoft Corporation and other contributors",
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/winjs/react-winjs"
17 | },
18 | "license": "MIT",
19 | "peerDependencies": {
20 | "react": "15.0.x",
21 | "react-dom": "15.0.x",
22 | "winjs": "4.4.x"
23 | },
24 | "devDependencies": {
25 | "grunt": "^0.4.5",
26 | "grunt-contrib-clean": "^0.6.0",
27 | "grunt-contrib-compress": "^0.13.0",
28 | "grunt-contrib-copy": "^0.8.0",
29 | "grunt-github-releaser": "^0.1.17",
30 | "grunt-nuget": "^0.1.4"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/examples/address-book/ProfilePicture.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 |
5 | function cssUrl(url) {
6 | return "url(" + url + ")";
7 | }
8 |
9 | var ProfilePicture = React.createClass({
10 | render: function () {
11 | var size = this.props.size;
12 | return (
13 |
23 |
24 |
25 | );
26 | }
27 | });
28 |
29 | module.exports = ProfilePicture;
30 |
--------------------------------------------------------------------------------
/examples/showcase/examples/DatePicker.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleDateChange: function (eventObject) {
8 | var datePicker = eventObject.currentTarget.winControl;
9 | this.setState({ date: datePicker.current });
10 | },
11 | getInitialState: function () {
12 | return {
13 | date: new Date()
14 | };
15 | },
16 | render: function () {
17 | return (
18 |
19 |
Date: {this.state.date.toDateString()}
20 |
25 |
26 | );
27 | }
28 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/Pivot.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | render: function () {
8 | return (
9 |
10 |
11 | Pivots are useful for varied content.
12 |
13 |
14 | This pivot is boring.
15 |
16 |
17 | Because it's only purpose is to show how to create a pivot.
18 |
19 |
20 | );
21 | }
22 | });
--------------------------------------------------------------------------------
/examples/address-book/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | react-winjs Address Book
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/examples/showcase/examples/FlipView.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | flipViewItemRenderer: ReactWinJS.reactRenderer(function (item) {
8 | return (
9 |
10 | The rating of this flip view item is: {item.data.rating}
11 |
12 | );
13 | }),
14 | getInitialState: function () {
15 | return {
16 | ratingsList: new WinJS.Binding.List([
17 | { rating: 4 },
18 | { rating: 2 }
19 | ])
20 | };
21 | },
22 | render: function () {
23 | return (
24 |
28 | );
29 | }
30 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/ToggleSwitch.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleToggle: function (eventObject) {
8 | var toggleCommand = eventObject.currentTarget.winControl;
9 | this.setState({ toggleSelected: toggleCommand.checked });
10 | },
11 | getInitialState: function () {
12 | return {
13 | toggleSelected: false
14 | };
15 | },
16 | render: function () {
17 | return (
18 |
19 |
Toggle selected: {this.state.toggleSelected.toString()}
20 |
21 |
26 |
27 | );
28 | }
29 | });
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Adam Comella
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/examples/showcase/examples/ItemContainer.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleSelectionChanged: function (eventObject) {
8 | var itemContainer = eventObject.currentTarget.winControl;
9 | this.setState({ selected: itemContainer.selected });
10 | },
11 | getInitialState: function () {
12 | return {
13 | selected: true
14 | };
15 | },
16 | render: function () {
17 | return (
18 |
23 |
24 |
Marvelous Mint
25 | Gelato
26 | Selected: {this.state.selected.toString()}
27 |
28 |
29 | );
30 | }
31 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/TimePicker.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | function formattedTime(time) {
7 | var rawHours = time.getHours();
8 | var amPM = rawHours < 12 ? "AM" : "PM";
9 | var hours = rawHours < 12 ? rawHours : (rawHours - 12);
10 | hours = hours === 0 ? 12 : hours;
11 | var rawMinutes = time.getMinutes();
12 | var minutes = (rawMinutes < 10 ? "0" : "") + rawMinutes;
13 |
14 | return hours + ":" + minutes + " " + amPM;
15 | }
16 |
17 | module.exports = React.createClass({
18 | handleTimeChange: function (eventObject) {
19 | var timePicker = eventObject.currentTarget.winControl;
20 | this.setState({ time: timePicker.current });
21 | },
22 | getInitialState: function () {
23 | return {
24 | time: new Date()
25 | };
26 | },
27 | render: function () {
28 | return (
29 |
30 |
Time: {formattedTime(this.state.time)}
31 |
32 |
35 |
36 | );
37 | }
38 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/Rating.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleChangeRating: function (eventObject) {
8 | var ratingControl = eventObject.currentTarget.winControl;
9 | this.setState({ rating: ratingControl.userRating });
10 | },
11 | handleAddToRating: function (amount) {
12 | this.setState({ rating: this.state.rating + amount });
13 | },
14 | getInitialState: function () {
15 | return {
16 | rating: 0
17 | };
18 | },
19 | render: function () {
20 | return (
21 |
22 |
23 | -1
24 | +1
25 |
26 |
Current Rating: {this.state.rating}
27 |
28 |
32 |
33 | );
34 | }
35 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/ContentDialog.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleShow: function () {
8 | this.refs.dialog.winControl.show().then(function (eventObject) {
9 | this.setState({ dialogResult: eventObject.result });
10 | }.bind(this));
11 | },
12 | getInitialState: function () {
13 | return {
14 | dialogResult: null
15 | };
16 | },
17 | render: function () {
18 | return (
19 |
20 |
Dialog Result: {this.state.dialogResult || ""}
21 |
Show ContentDialog
22 |
23 |
28 |
29 | This content will appear in the body of the ContentDialog. You can put arbitrary HTML in here.
30 |
31 |
32 |
33 | );
34 | }
35 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/ListView.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | // See CSS styles for win-container in index.html
7 |
8 | module.exports = React.createClass({
9 | itemRenderer: ReactWinJS.reactRenderer(function (item) {
10 | return {item.data.title}
;
11 | }),
12 | getInitialState: function () {
13 | return {
14 | list: new WinJS.Binding.List([
15 | { title: "Apple" },
16 | { title: "Banana" },
17 | { title: "Grape" },
18 | { title: "Lemon" },
19 | { title: "Mint" },
20 | { title: "Orange" },
21 | { title: "Pineapple" },
22 | { title: "Strawberry"}
23 | ]),
24 | layout: { type: WinJS.UI.ListLayout }
25 | };
26 | },
27 | render: function () {
28 | return (
29 |
37 | );
38 | }
39 | });
--------------------------------------------------------------------------------
/examples/movies/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | react-winjs Movies
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/examples/showcase/examples/Hub.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleHeaderInvoked: function (eventObject) {
8 | if (eventObject.detail.index === 1) {
9 | this.setState({ counter: this.state.counter + 1 });
10 | }
11 | },
12 | getInitialState: function () {
13 | return {
14 | counter: 0
15 | };
16 | },
17 | render: function () {
18 | return (
19 |
22 |
26 | Hubs are useful for varied content.
27 |
28 |
29 |
30 | This section's header was clicked {this.state.counter} time(s).
31 | This hub is boring.
32 |
33 |
34 |
35 | Because it's only purpose is to show how to create a hub.
36 |
37 |
38 | );
39 | }
40 | });
--------------------------------------------------------------------------------
/examples/showcase/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | react-winjs Showcase
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-winjs
2 |
3 | A React wrapper around WinJS's controls. Implemented using the technique described on [this WinJS wiki page](https://github.com/winjs/winjs/wiki/Using-WinJS-with-React).
4 |
5 | - [Documentation](https://github.com/winjs/react-winjs/wiki/Documentation)
6 | - [Live Component Library](https://brand.ai/styleguide/WinJS)
7 |
8 | Live demos:
9 | - [Showcase](http://winjs.github.io/react-winjs/examples/showcase/index.html) ([source](https://github.com/winjs/react-winjs/tree/master/examples/showcase)): shows an example usage of each component.
10 | - [Movies](http://winjs.github.io/react-winjs/examples/movies/index.html) ([source](https://github.com/winjs/react-winjs/tree/master/examples/movies)): demonstrates a couple of react-winjs components in a small app for looking up movies.
11 | - [Address Book](http://winjs.github.io/react-winjs/examples/address-book/index.html) ([source](https://github.com/winjs/react-winjs/tree/master/examples/address-book)): demonstrates how to use react-winjs components to build an adaptive app which works well on mobile, tablet, and desktop computers.
12 |
13 | ## Installation
14 |
15 | ```
16 | npm install react-winjs --save
17 | ```
18 |
19 | ## Usage
20 |
21 | Include [WinJS 4.4](http://try.buildwinjs.com/#get) on your page. For example:
22 |
23 | ```html
24 |
25 |
26 |
27 | ```
28 |
29 | Then require `react-winjs` and use it:
30 |
31 | ```jsx
32 | var React = require('react');
33 | var ReactDOM = require('react-dom');
34 | var ReactWinJS = require('react-winjs');
35 |
36 | var App = React.createClass({
37 | render: function () {
38 | return ;
39 | }
40 | });
41 |
42 | ReactDOM.render( , document.getElementById("app"));
43 | ```
44 |
45 | See the [documentation](https://github.com/winjs/react-winjs/wiki/Documentation) and [examples](https://github.com/winjs/react-winjs/tree/master/examples) for more details.
46 |
47 | ## License
48 |
49 | MIT
50 |
--------------------------------------------------------------------------------
/examples/showcase/examples/SplitView.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | var splitViewId = "mainSplitView";
7 |
8 | module.exports = React.createClass({
9 | handleTogglePane: function () {
10 | this.setState({ paneOpened: !this.state.paneOpened });
11 | },
12 | handleAfterClose: function () {
13 | this.setState({ paneOpened: false });
14 | },
15 | handleChangeContent: function (newContent) {
16 | this.setState({
17 | content: newContent,
18 | paneOpened: false
19 | });
20 | },
21 | getInitialState: function () {
22 | return {
23 | content: "Home",
24 | paneOpened: false
25 | };
26 | },
27 | render: function () {
28 | var paneComponent = (
29 |
30 |
31 |
35 |
36 |
37 |
41 |
45 |
49 |
50 | );
51 | var contentComponent = (
52 | {this.state.content}
53 | );
54 |
55 | return (
56 |
63 | );
64 | }
65 | });
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # React-WinJS Component Documentation (see it live [here](https://brandai.com/styleguide/WinJS))
2 |
3 | This folder contains configuration required to build documentation for react-winjs using [Brand AI](https://brand.ai).
4 |
5 | ## Flow
6 | ### Build
7 | Use gulp to build a distribution folder containing:
8 | * library version of react-winjs
9 | * WinJS core scripts and stylesheets.
10 |
11 | See [webpack.config.json](https://github.com/winjs/react-winjs/blob/master/docs/webpack.config.js) and [gulpfile.json](https://github.com/winjs/react-winjs/blob/master/docs/gulpfile.js) for more info on that.
12 |
13 | ```sh
14 | $ cd react-winjs/docs
15 | $ npm install
16 | $ gulp build
17 | ```
18 |
19 | ### Deploy
20 | Deploying to Brand.ai is done through [brandai-tools](https://github.com/brandai/brandai-tools).
21 | ```sh
22 | $ npm install -g brandai-tools
23 | $ brandai login
24 | $ brandai deploy
25 | ```
26 |
27 | ### Config
28 | [brandai.json](https://github.com/brandai/react-winjs/blob/master/docs/brandai.json) contains all the component extraction and deployment information.
29 |
30 | * `name` - the component library name in Brand.ai - each documentation project is associated with one or more component libraries
31 | * `libraryPath` - relative path for the component library project root (used to read library package.json)
32 | * `dist` - name of the dist folder containing the library and its dependencies - used both for rendering examples and for dynamic analysis of components and their properties
33 | * `libraryObjectName` - name of the library on the global object (we set it to `ReactWinJS` in `webpack.config.js`.
34 | * `reactVersion` - the version of React required for running this library (automatically gets pulled when rendering the components)
35 | * `dynamicExtraction` - this tells Brand.ai to dynamically extract components - run the files in the `dist` folder and extract the required info from live components, rather than statically parse .jsx files.
36 | * `fileOrder` - when loading dependencies, file names appearing here will be loaded first (we can't load react-winjs until the winjs core files are there).
37 |
38 | #### Example package.json
39 | ```json
40 | {
41 | "name": "react-winjs",
42 | "libraryPath": "../",
43 | "dist": "dist",
44 | "libraryObjectName": "ReactWinJS",
45 | "reactVersion": "15.0.1",
46 | "dynamicExtraction": true,
47 | "fileOrder": ["base.min.js", "ui.min.js"]
48 | }
49 |
--------------------------------------------------------------------------------
/examples/showcase/examples/Menu.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleShowMenu: function (eventObject) {
8 | var anchor = eventObject.currentTarget;
9 | this.refs.menu.winControl.show(anchor);
10 | },
11 | handleUpdateResult: function (result) {
12 | this.setState({ result: result });
13 | },
14 | handleToggleMe: function (eventObject) {
15 | var toggleCommand = eventObject.currentTarget.winControl;
16 | this.setState({ toggleSelected: toggleCommand.selected });
17 | },
18 | getInitialState: function () {
19 | return {
20 | result: null,
21 | toggleSelected: true
22 | };
23 | },
24 | render: function () {
25 | var subMenu = (
26 |
27 |
31 |
35 |
36 | );
37 |
38 | return (
39 |
40 |
Show Menu
41 |
Clicked command: {this.state.result || ""}
42 |
Toggle selected: {this.state.toggleSelected.toString()}
43 |
44 |
45 |
46 |
50 |
51 |
56 |
57 |
58 |
59 |
63 |
64 |
65 |
66 | );
67 | }
68 | });
--------------------------------------------------------------------------------
/examples/movies/DetailPage.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 | var Score = require('./Score.jsx');
6 | var formattedScore = Score.formattedScore;
7 | var textColoredForScore = Score.textColoredForScore;
8 |
9 | var styles = {
10 | root: {
11 | marginLeft: "5px",
12 | marginRight: "5px"
13 | },
14 | header: {
15 | root: {
16 | display: "flex",
17 | flexDirection: "row"
18 | },
19 | backButton: {
20 | marginRight: "10px",
21 | flex: "none"
22 | },
23 | title: {
24 | marginBottom: "10px",
25 | flex: "1 1"
26 | }
27 | },
28 | detail: {
29 | root: {
30 | display: "flex"
31 | },
32 | poster: {
33 | marginRight: "10px",
34 | flex: "none",
35 | alignSelf: "center"
36 | },
37 | info: {
38 | flex: "1 1",
39 | alignSelf: "flex-start"
40 | },
41 | rating: {
42 | display: "inline-block",
43 | padding: "2px",
44 | border: "2px solid black",
45 | marginBottom: "15px",
46 | fontFamily: "Palatino",
47 | fontSize: "20px"
48 | },
49 | actors: {
50 | marginTop: "0",
51 | marginBottom: "0"
52 | }
53 | }
54 | };
55 |
56 | module.exports = React.createClass({
57 | render: function () {
58 | var movie = this.props.movie;
59 | var criticsScore = movie.ratings.critics_score;
60 | var audienceScore = movie.ratings.audience_score;
61 | var actors = movie.abridged_cast.map(function (person) {
62 | return {person.name} ;
63 | });
64 |
65 | return (
66 |
67 |
68 |
69 |
{movie.title} ({movie.year})
70 |
71 |
72 |
73 |
74 |
{movie.mpaa_rating}
75 |
Critics:
76 |
{textColoredForScore(formattedScore(criticsScore), criticsScore)}
77 |
Audience:
78 |
{textColoredForScore(formattedScore(audienceScore), audienceScore)}
79 |
80 |
81 |
82 |
{movie.synopsis}
83 |
84 |
88 |
89 | );
90 | }
91 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/AutoSuggestBox.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | var suggestionList = ["Shanghai", "Istanbul", "Karachi", "Delhi", "Mumbai", "Moscow", "Seoul", "Beijing", "Jakarta",
7 | "Tokyo", "Mexico City", "Kinshasa", "New York City", "Lagos", "London", "Lima", "Bogota", "Tehran", "Ho Chi Minh City", "Hong Kong",
8 | "Bangkok", "Dhaka", "Cairo", "Hanoi", "Rio de Janeiro", "Lahore", "Chonquing", "Bengaluru", "Tianjin", "Baghdad", "Riyadh", "Singapore",
9 | "Santiago", "Saint Petersburg", "Surat", "Chennai", "Kolkata", "Yangon", "Guangzhou", "Alexandria", "Shenyang", "Hyderabad", "Ahmedabad",
10 | "Ankara", "Johannesburg", "Wuhan", "Los Angeles", "Yokohama", "Abidjan", "Busan", "Cape Town", "Durban", "Pune", "Jeddah", "Berlin",
11 | "Pyongyang", "Kanpur", "Madrid", "Jaipur", "Nairobi", "Chicago", "Houston", "Philadelphia", "Phoenix", "San Antonio", "San Diego",
12 | "Dallas", "San Jose", "Jacksonville", "Indianapolis", "San Francisco", "Austin", "Columbus", "Fort Worth", "Charlotte", "Detroit",
13 | "El Paso", "Memphis", "Baltimore", "Boston", "Seattle Washington", "Nashville", "Denver", "Louisville", "Milwaukee", "Portland",
14 | "Las Vegas", "Oklahoma City", "Albuquerque", "Tucson", "Fresno", "Sacramento", "Long Beach", "Kansas City", "Mesa", "Virginia Beach",
15 | "Atlanta", "Colorado Springs", "Omaha", "Raleigh", "Miami", "Cleveland", "Tulsa", "Oakland", "Minneapolis", "Wichita", "Arlington",
16 | "Bakersfield", "New Orleans", "Honolulu", "Anaheim", "Tampa", "Aurora", "Santa Ana", "St. Louis", "Pittsburgh", "Corpus Christi",
17 | "Riverside", "Cincinnati", "Lexington", "Anchorage", "Stockton", "Toledo", "St. Paul", "Newark", "Greensboro", "Buffalo", "Plano",
18 | "Lincoln", "Henderson", "Fort Wayne", "Jersey City", "St. Petersburg", "Chula Vista", "Norfolk", "Orlando", "Chandler", "Laredo", "Madison",
19 | "Winston-Salem", "Lubbock", "Baton Rouge", "Durham", "Garland", "Glendale", "Reno", "Hialeah", "Chesapeake", "Scottsdale", "North Las Vegas",
20 | "Irving", "Fremont", "Irvine", "Birmingham", "Rochester", "San Bernardino", "Spokane", "Toronto", "Montreal", "Vancouver", "Ottawa-Gatineau",
21 | "Calgary", "Edmonton", "Quebec City", "Winnipeg", "Hamilton"];
22 |
23 | module.exports = React.createClass({
24 | handleSuggestionsRequested: function (eventObject) {
25 | var queryText = eventObject.detail.queryText,
26 | query = queryText.toLowerCase(),
27 | suggestionCollection = eventObject.detail.searchSuggestionCollection;
28 |
29 | if (queryText.length > 0) {
30 | for (var i = 0, len = suggestionList.length; i < len; i++) {
31 | if (suggestionList[i].substr(0, query.length).toLowerCase() === query) {
32 | suggestionCollection.appendQuerySuggestion(suggestionList[i]);
33 | }
34 | }
35 | }
36 | },
37 | handleQuerySubmitted: function (eventObject) {
38 | this.setState({ query: eventObject.detail.queryText });
39 | },
40 | getInitialState: function () {
41 | return {
42 | query: null
43 | };
44 | },
45 | render: function () {
46 | return (
47 |
48 |
52 |
53 | {
Submitted Query: {this.state.query || ""}
}
54 |
55 | );
56 | }
57 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/SemanticZoom.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | // See CSS styles for win-container in index.html
7 |
8 | function groupKey(item) {
9 | return item.title[0];
10 | }
11 |
12 | function groupData(item) {
13 | return { title: item.title[0] };
14 | }
15 |
16 | module.exports = React.createClass({
17 | itemRenderer: ReactWinJS.reactRenderer(function (item) {
18 | return {item.data.title}
;
19 | }),
20 | groupHeaderRenderer: ReactWinJS.reactRenderer(function (item) {
21 | return {item.data.title}
;
22 | }),
23 | handleToggleZoom: function (eventObject) {
24 | this.setState({ zoomedOut: !this.state.zoomedOut });
25 | },
26 | handleZoomChanged: function (eventObject) {
27 | this.setState({ zoomedOut: eventObject.detail });
28 | },
29 | getInitialState: function () {
30 | return {
31 | list: new WinJS.Binding.List([
32 | { title: "Aaron" },
33 | { title: "Adam" },
34 | { title: "Allison" },
35 | { title: "Barry" },
36 | { title: "Bill" },
37 | { title: "Brad" },
38 | { title: "Bridget" },
39 | { title: "Brett" },
40 | { title: "Carly" },
41 | { title: "Carol" },
42 | { title: "Charles" },
43 | { title: "Chris" },
44 | { title: "Daisy" },
45 | { title: "Dan" },
46 | { title: "Denise" },
47 | { title: "Derek" },
48 | { title: "Earl" },
49 | { title: "Emily" },
50 | { title: "Emma" },
51 | { title: "Erika" },
52 | { title: "Ethan" },
53 | { title: "Finley" },
54 | { title: "Florence" },
55 | { title: "Frank" },
56 | { title: "Fred" }
57 |
58 | ]).createGrouped(groupKey, groupData),
59 | layout: { type: WinJS.UI.ListLayout },
60 | zoomedOut: false
61 | };
62 | },
63 | render: function () {
64 | var zoomedInView = ;
73 |
74 | var zoomedOutView = ;
79 |
80 | return (
81 |
82 |
83 | Zoom {this.state.zoomedOut ? "In" : "Out"}
84 |
85 |
92 |
93 | );
94 |
95 | }
96 | });
--------------------------------------------------------------------------------
/examples/showcase/examples/AppBar.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleUpdateResult: function (result) {
8 | this.setState({ result: result });
9 | },
10 | handleToggleMe: function (eventObject) {
11 | var toggleCommand = eventObject.currentTarget.winControl;
12 | this.setState({ toggleSelected: toggleCommand.selected });
13 | },
14 | getInitialState: function () {
15 | return {
16 | toolBarIsSmall: false,
17 | result: null,
18 | toggleSelected: true
19 | };
20 | },
21 | render: function () {
22 | var subMenu = (
23 |
24 |
28 |
32 |
33 | );
34 |
35 | var appBar = (
36 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
52 |
53 |
59 |
60 |
65 |
66 |
71 |
72 |
77 |
78 |
79 | );
80 |
81 | return (
82 |
83 |
This AppBar renders at the bottom of the screen.
84 |
Resize your window. Notice how the AppBar puts commands into an
85 | overflow menu when it can't fit them in the primary area. You can
86 | control what gets overflowed first using the priority prop
87 |
88 | {this.props.appBarShown ? "Hide" : "Show"} AppBar
89 |
90 |
Clicked command: {this.state.result || ""}
91 |
Toggle selected: {this.state.toggleSelected.toString()}
92 | {this.props.appBarShown ? appBar : null}
93 |
94 | );
95 | }
96 | });
--------------------------------------------------------------------------------
/examples/address-book/main.css:
--------------------------------------------------------------------------------
1 | #app {
2 | height: 100%;
3 | }
4 |
5 | /*
6 | * BackButton
7 | * Ensure it's the same size as the SplitViewPaneToggle
8 | */
9 | #app .win-backbutton {
10 | height: 48px;
11 | width: 48px;
12 | font-size: inherit;
13 | line-height: inherit;
14 | box-sizing: border-box;
15 | }
16 | #app .win-backbutton::before {
17 | font-size: 24px;
18 | line-height: 1.333;
19 | vertical-align: baseline;
20 | }
21 |
22 | /*
23 | * People Search Pane
24 | */
25 |
26 | #app .peopleSearchPane .peopleListView .win-surface {
27 | margin-top: 0;
28 | }
29 |
30 | #app .peopleSearchPane .peopleListView .win-container {
31 | margin: 0;
32 | height: 48px;
33 | }
34 |
35 | #app .peopleSearchPane .peopleListView .win-item {
36 | height: 40px;
37 | padding-top: 8px;
38 | width: calc(100% - 12px);
39 | padding-left: 12px;
40 | }
41 |
42 | #app .peopleSearchPane .peopleListView .win-item .profilePicture {
43 | width: 34px;
44 | height: 34px;
45 | background-size: cover;
46 | -webkit-border-radius: 34px;
47 | -moz-border-radius: 34px;
48 | border-radius: 34px;
49 | display: inline-block;
50 | vertical-align: middle;
51 | margin-right: 5px;
52 | }
53 |
54 | #app .peopleSearchPane .peopleListView .win-item .name {
55 | vertical-align: middle;
56 | }
57 |
58 | #app .peopleSearchPane .peopleListView .win-groupheadercontainer {
59 | width: 32px;
60 | height: 32px;
61 | margin-top: 7px;
62 | margin-bottom: 10px;
63 | margin-left: 12px;
64 | }
65 | #app .peopleSearchPane .peopleListView .win-groupheader {
66 | font-size: 15px;
67 | width: 32px;
68 | height: 32px;
69 | padding: 0;
70 | background-color: rgb(1, 121, 216);
71 | color: white;
72 | text-align: center;
73 | line-height: 32px;
74 | }
75 |
76 | .peopleToolBar .win-toolbar-actionarea {
77 | background-color: white;
78 | }
79 |
80 | /*
81 | * Profile Pane
82 | */
83 |
84 | #app .profilePane {
85 | box-sizing: border-box;
86 | padding-left: 10px;
87 | padding-right: 10px;
88 | }
89 |
90 | #app .profilePane .profileHeader {
91 | padding-bottom: 10px;
92 | }
93 |
94 | #app .profilePane .profileHeader .name {
95 | vertical-align: top;
96 | display: inline-block;
97 | font-size: 25px;
98 | padding-top: 6px;
99 | }
100 |
101 | .profileHeader .personInfo {
102 | display: flex;
103 | }
104 |
105 | #app .profilePane .profileHeader .profilePicture {
106 | width: 100px;
107 | height: 100px;
108 | background-size: cover;
109 | display: inline-block;
110 | border-radius: 100px;
111 | -webkit-border-radius: 100px;
112 | -moz-border-radius: 100px;
113 | margin-left: 25px;
114 | margin-top:10px;
115 | }
116 |
117 | .profileHeader .personInfo .profileStatus {
118 | width: 240px;
119 | margin-left:20px;
120 | margin-top:10px;
121 | }
122 |
123 | .profileHeader .personInfo .profileStatus .message {
124 | /*color: #ffffff;*/
125 | font-size: 14px;
126 | }
127 | .profileHeader .personInfo .profileStatus .source {
128 | display:block;
129 | color: grey;
130 | font-size: 13px;
131 | }
132 |
133 | .profileContent ul {
134 | list-style:none;
135 | padding-left: 25px;
136 | padding-right: 25px;
137 | }
138 |
139 | .profileContent ul li {
140 | margin-bottom:25px;
141 | }
142 |
143 | .separator {
144 | width:100%;
145 | height:2px;
146 | background-color:rgb(205, 205, 205);
147 | }
148 |
149 | .profileContent .phoneIcon,
150 | .profileContent .callContent {
151 | display: inline-block;
152 | vertical-align: top;
153 | }
154 |
155 | .profileContent .videoCallIcon,
156 | .profileContent .emailIcon,
157 | .profileContent .messageIcon,
158 | .profileContent .phoneIcon,
159 | .profileContent .mapIcon {
160 | margin-right: 8px;
161 | }
162 |
163 | .profileContent .videoCallIcon::before {
164 | content: "\E13B";
165 | }
166 |
167 | .profileContent .emailIcon::before {
168 | content: "\E119";
169 | }
170 |
171 | .profileContent .messageIcon::before {
172 | content: "\E15F";
173 | }
174 |
175 | .profileContent .phoneIcon::before {
176 | content: "\E13A";
177 | }
178 |
179 | .profileContent .mapIcon::before {
180 | content: "\E139";
181 | }
182 |
--------------------------------------------------------------------------------
/examples/showcase/examples/ToolBar.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 |
6 | module.exports = React.createClass({
7 | handleToggleToolBarSize: function () {
8 | this.setState({ toolBarIsSmall: !this.state.toolBarIsSmall });
9 | },
10 | handleUpdateResult: function (result) {
11 | this.setState({ result: result });
12 | },
13 | handleToggleMe: function (eventObject) {
14 | var toggleCommand = eventObject.currentTarget.winControl;
15 | this.setState({ toggleSelected: toggleCommand.selected });
16 | },
17 | getInitialState: function () {
18 | return {
19 | toolBarIsSmall: false,
20 | result: null,
21 | toggleSelected: true
22 | };
23 | },
24 | componentDidUpdate: function (prevProps, prevState) {
25 | if (this.state.toolBarIsSmall !== prevState.toolBarIsSmall) {
26 | // Notify the ToolBar that is has been resized.
27 | this.refs.toolBar.winControl.forceLayout();
28 | }
29 | },
30 | render: function () {
31 | var subMenu = (
32 |
33 |
37 |
41 |
42 | );
43 |
44 | return (
45 |
46 |
Notice how the ToolBar puts commands into an overflow menu when it can't fit
47 | them in the primary area. You can control what gets overflowed first using
48 | the priority prop
49 |
50 | Make ToolBar {this.state.toolBarIsSmall ? "Bigger" : "Smaller"}
51 |
52 |
Clicked command: {this.state.result || ""}
53 |
Toggle selected: {this.state.toggleSelected.toString()}
54 |
55 |
58 |
59 |
63 |
64 |
65 |
66 |
67 |
68 |
73 |
74 |
80 |
81 |
86 |
87 |
92 |
93 |
98 |
99 |
100 |
101 | );
102 | }
103 | });
--------------------------------------------------------------------------------
/examples/movies/SearchPage.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 | var Score = require('./Score.jsx');
6 | var formattedScore = Score.formattedScore;
7 | var textColoredForScore = Score.textColoredForScore;
8 |
9 | // For best performance, .win-container should be sized in CSS.
10 | // See index.html for its style.
11 | var styles = {
12 | item: {
13 | root: {
14 | height: "100%",
15 | display: "flex"
16 | },
17 | poster: {
18 | marginRight: "10px",
19 | flex: "none"
20 | },
21 | info: {
22 | root: {
23 | flex: "1 1",
24 | display: "flex",
25 | flexDirection: "column"
26 | },
27 | title: {
28 | flex: "0 1 auto",
29 | overflow: "hidden"
30 | },
31 | yearAndScore: {
32 | flex: "none"
33 | }
34 | }
35 | },
36 | root: {
37 | height: "100%"
38 | },
39 | listView: {
40 | height: "calc(100% - 50px)"
41 | },
42 | footer: {
43 | height: "91px",
44 | lineHeight: "91px",
45 | textAlign: "center"
46 | }
47 | };
48 |
49 | module.exports = React.createClass({
50 | itemRenderer: ReactWinJS.reactRenderer(function (item) {
51 | var score = item.data.ratings.critics_score;
52 | var scoreComponent = textColoredForScore("Critics " + formattedScore(score), score);
53 | return (
54 |
55 |
56 |
57 |
{item.data.title}
58 |
59 | {item.data.year} {"\u2022"} {scoreComponent}
60 |
61 |
62 |
63 | );
64 | }),
65 | handleQueryChange: function (eventObject) {
66 | var queryText = eventObject.currentTarget.value;
67 | this.setState({ queryText: queryText });
68 |
69 | this.pendingQueryId && clearTimeout(this.pendingQueryId);
70 | this.pendingQueryId = setTimeout(function () {
71 | this.props.onFetchFirstPage(queryText);
72 | }.bind(this), 300);
73 | },
74 | handleMovieSelected: function (eventObject) {
75 | WinJS.Navigation.navigate("/movie", {
76 | movie: this.props.movies.getAt(eventObject.detail.itemIndex)
77 | });
78 | },
79 | handleFooterVisibilityChanged: function (eventObject) {
80 | if (eventObject.detail.visible) {
81 | this.props.onFetchNextPage();
82 | }
83 | },
84 | getInitialState: function () {
85 | return {
86 | queryText: this.props.queryText,
87 | layout: { type: WinJS.UI.ListLayout }
88 | };
89 | },
90 | render: function() {
91 | var resultsComponent;
92 | if (!this.props.movies) {
93 | resultsComponent = Loading...
;
94 | } else if (this.props.movies.length === 0) {
95 | resultsComponent = No movies found for "{this.props.queryText}".
;
96 | } else {
97 | var footerComponent = !this.props.hasMore ? null : (
98 |
99 | Loading...
100 |
101 | );
102 |
103 | resultsComponent = (
104 |
113 | );
114 | }
115 |
116 | return (
117 |
118 |
119 | {resultsComponent}
120 |
121 | );
122 | }
123 | });
--------------------------------------------------------------------------------
/examples/showcase/index.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactDOM = require('react-dom');
5 | var ReactWinJS = require('react-winjs');
6 |
7 | // title is:
8 | // - Displayed as the title of the sample
9 | // - Used as the anchor ID of the sample
10 | // - Used to find the path to the source code of the sample. Specifically:
11 | // './examples/.jsx'
12 | var examples = [
13 | { title: "AppBar", componenent: require('./examples/AppBar.jsx') },
14 | { title: "AutoSuggestBox", componenent: require('./examples/AutoSuggestBox.jsx') },
15 | { title: "BackButton", componenent: require('./examples/BackButton.jsx') },
16 | { title: "ContentDialog", componenent: require('./examples/ContentDialog.jsx') },
17 | { title: "DatePicker", componenent: require('./examples/DatePicker.jsx') },
18 | { title: "FlipView", componenent: require('./examples/FlipView.jsx') },
19 | { title: "Flyout", componenent: require('./examples/Flyout.jsx') },
20 | { title: "Hub", componenent: require('./examples/Hub.jsx') },
21 | { title: "ItemContainer", componenent: require('./examples/ItemContainer.jsx') },
22 | { title: "ListView", componenent: require('./examples/ListView.jsx') },
23 | { title: "Menu", componenent: require('./examples/Menu.jsx') },
24 | { title: "Pivot", componenent: require('./examples/Pivot.jsx') },
25 | { title: "Rating", componenent: require('./examples/Rating.jsx') },
26 | { title: "SemanticZoom", componenent: require('./examples/SemanticZoom.jsx') },
27 | { title: "SplitView", componenent: require('./examples/SplitView.jsx') },
28 | { title: "TimePicker", componenent: require('./examples/TimePicker.jsx') },
29 | { title: "ToggleSwitch", componenent: require('./examples/ToggleSwitch.jsx') },
30 | { title: "ToolBar", componenent: require('./examples/ToolBar.jsx') },
31 | { title: "Tooltip", componenent: require('./examples/Tooltip.jsx') }
32 | ];
33 |
34 | var baseSourceUrl = "https://github.com/winjs/react-winjs/tree/master/examples/" +
35 | "showcase/examples/";
36 | var styles = {
37 | viewport: { height: "100%", overflow: "auto" },
38 | surface: { paddingBottom: 96 + 10 }, // Leave room for bottom AppBar
39 | example: { paddingBottom: 30 },
40 | exampleTitle: { paddingBottom: 10 },
41 | sourceLink: { paddingLeft: 5 }
42 | };
43 |
44 | var App = React.createClass({
45 | handleToggleAppBar: function (exampleTitle) {
46 | this.setState({
47 | exampleWithAppBar: this.state.exampleWithAppBar === exampleTitle ? null : exampleTitle
48 | });
49 | },
50 | getInitialState: function () {
51 | return {
52 | // To prevent AppBars from occluding each other, only one example
53 | // should show an AppBar at a time.
54 | exampleWithAppBar: null
55 | };
56 | },
57 | render: function() {
58 | var tableOfContents = examples.map(function (example) {
59 | return {example.title} ;
60 | });
61 |
62 | var exampleMarkup = examples.map(function (example) {
63 | var sourceUrl = baseSourceUrl + example.title + ".jsx";
64 |
65 | return (
66 |
81 | );
82 | }, this);
83 |
84 | return (
85 |
86 |
87 |
88 |
89 |
Table of Contents
90 |
91 |
92 | {exampleMarkup}
93 |
94 |
95 | );
96 | }
97 | });
98 |
99 | ReactDOM.render( , document.getElementById("app"));
100 |
--------------------------------------------------------------------------------
/examples/movies/index.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactDOM = require('react-dom');
5 | var ReactWinJS = require('react-winjs');
6 | var FakeData = require('./FakeData');
7 | var Data = FakeData;
8 | var SearchPage = require('./SearchPage.jsx');
9 | var DetailPage = require('./DetailPage.jsx');
10 |
11 | // TODO: Preserve the scroll position when navigating back to search page.
12 | // TODO: Use a loading spinner instead of the text "Loading..."
13 |
14 | // Manages fetching of movie data. *fetchFirst* and *fetchNext* start fetches and the when the
15 | // resuts are ready, *dataHandler* is called.
16 | var MovieFetcher = function (dataHandler) {
17 | this._dataHandler = dataHandler;
18 | this._outstandingFetch = null;
19 |
20 | this.queryText = "";
21 | this.nextPage = 1;
22 | this.receivedCount = 0;
23 | this.totalCount = 0;
24 |
25 | };
26 | // Fetches the first page of results of *queryText*. If that fetch is already in
27 | // progress, this function is a no op.
28 | MovieFetcher.prototype.fetchFirst = function (queryText) {
29 | this.queryText = queryText;
30 | this.nextPage = 1;
31 | this.receivedCount = 0;
32 | this.totalCount = 0;
33 |
34 | this._doFetch();
35 | };
36 | // Fetches the next page of results for whatever *queryText* was passed to the most
37 | // recent call to *fetchFirst*. If a fetch is already in progress, this function is a no op.
38 | MovieFetcher.prototype.fetchNext = function () {
39 | this._doFetch();
40 | };
41 | // Cancels whatever fetch is currently in progress.
42 | MovieFetcher.prototype.stop = function () {
43 | var currFetch = this._outstandingFetch;
44 | this._outstandingFetch = null;
45 | currFetch && currFetch.promise.cancel();
46 | };
47 | MovieFetcher.prototype._doFetch = function () {
48 | var handleResults = function (response) {
49 | this._outstandingFetch = null;
50 |
51 | this.nextPage++;
52 | this.receivedCount += response.movies.length;
53 | this.totalCount = response.total;
54 |
55 | this._dataHandler({
56 | queryText: queryText,
57 | page: page,
58 | movies: response.movies,
59 | hasMore: this.receivedCount < this.totalCount
60 |
61 | });
62 | }.bind(this);
63 |
64 | var queryText = this.queryText;
65 | var page = this.nextPage;
66 |
67 | var hasMore = page === 1 || this.receivedCount < this.totalCount;
68 | var currFetch = this._outstandingFetch;
69 | if (!hasMore || currFetch && currFetch.queryText === queryText && currFetch.page === page) {
70 | // No more data or the fetch is already in progress.
71 | return;
72 | }
73 |
74 | this._outstandingFetch = null;
75 | currFetch && currFetch.promise.cancel();
76 |
77 | var fetchPromise = queryText ? Data.getSearchResults(queryText, page) : Data.getInTheaters(page);
78 | fetchPromise = fetchPromise.then(
79 | handleResults,
80 | function (error) {
81 | console.log("Query error: ");
82 | console.log(" Query: '" + queryText + "'");
83 | console.log(" Page: " + page);
84 | console.log(" Error: " + JSON.stringify(error));
85 | }
86 | );
87 |
88 | this._outstandingFetch = {
89 | promise: fetchPromise,
90 | queryText: queryText,
91 | page: page
92 | };
93 | };
94 |
95 | var App = React.createClass({
96 | handleFetchResults: function (results) {
97 | var newMovies = results.movies;
98 | var currentMovies;
99 | if (results.page === 1) {
100 | currentMovies = new WinJS.Binding.List(newMovies);
101 | } else {
102 | currentMovies = this.state.movies;
103 | currentMovies.push.apply(currentMovies, newMovies);
104 | }
105 |
106 | this.setState({
107 | movies: currentMovies,
108 | queryText: results.queryText,
109 | hasMore: results.hasMore
110 | });
111 | },
112 | handleFetchFirstPage: function (queryText) {
113 | this.fetcher.fetchFirst(queryText);
114 | },
115 | handleFetchNextPage: function () {
116 | this.fetcher.fetchNext();
117 | },
118 | handleNavigated: function (eventObject) {
119 | this.setState({
120 | nav: {
121 | location: eventObject.detail.location,
122 | state: eventObject.detail.state
123 | }
124 | });
125 | },
126 | getInitialState: function () {
127 | return {
128 | movies: null,
129 | queryText: "",
130 | hasMore: true,
131 | nav: {
132 | location: WinJS.Navigation.location,
133 | state: WinJS.Navigation.state
134 | }
135 | };
136 | },
137 | componentWillMount: function () {
138 | this.fetcher = new MovieFetcher(this.handleFetchResults);
139 | WinJS.Navigation.addEventListener("navigated", this.handleNavigated);
140 | WinJS.Navigation.navigate("/");
141 | this.handleFetchNextPage();
142 | },
143 | componentWillUnmount: function () {
144 | WinJS.Navigation.removeEventListener("navigated", this.handleNavigated);
145 | this.fetcher.stop();
146 | },
147 | render: function () {
148 | var nav = this.state.nav;
149 | if (nav.location === "/movie") {
150 | return (
151 |
153 | );
154 | } else {
155 | return (
156 |
162 | );
163 | }
164 | }
165 | });
166 |
167 | ReactDOM.render( , document.getElementById("app"));
168 |
--------------------------------------------------------------------------------
/examples/address-book/index.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactDOM = require('react-dom');
5 | var ReactWinJS = require('react-winjs');
6 | var PeoplePage = require('./PeoplePage.jsx');
7 | var OtherPage = require('./OtherPage.jsx');
8 | var ProfilePicture = require('./ProfilePicture.jsx');
9 | var Data = require('./FakeData.js');
10 |
11 | var splitViewId = "rootSplitView";
12 |
13 | var splitViewConfigs = {
14 | small: {
15 | closedDisplayMode: "none",
16 | openedDisplayMode: "overlay"
17 | },
18 | medium: {
19 | closedDisplayMode: "inline",
20 | openedDisplayMode: "overlay"
21 | },
22 | large: {
23 | closedDisplayMode: "inline",
24 | openedDisplayMode: "inline"
25 | }
26 | };
27 |
28 | function merge(/* objs */) {
29 | var result = {};
30 | for (var i = 0, len = arguments.length; i < len; i++) {
31 | var obj = arguments[i];
32 | if (obj) {
33 | for (k in obj) { result[k] = obj[k]; }
34 | }
35 | }
36 | return result;
37 | }
38 |
39 | function getMode() {
40 | return (
41 | window.innerWidth >= 1366 ? "large" :
42 | window.innerWidth >= 800 ? "medium" :
43 | "small"
44 | );
45 | }
46 |
47 | var App = React.createClass({
48 | getSplitViewConfig: function () {
49 | return splitViewConfigs[this.state.mode];
50 | },
51 | handlePeopleChanged: function (newPeople) {
52 | this.setState({
53 | people: newPeople
54 | });
55 | },
56 | handleNavigation: function (newLocation) {
57 | this.setState({
58 | location: newLocation
59 | });
60 | },
61 | handleBack: function () {
62 | var location = this.state.location;
63 | location.pop();
64 | this.handleNavigation(location);
65 | },
66 | handleResize: function () {
67 | var prevMode = this.state.mode;
68 | var nextMode = getMode();
69 |
70 | if (prevMode !== nextMode) {
71 | this.setState({ mode: nextMode });
72 | }
73 | },
74 | handleCommandInvoked: function (newLocation) {
75 | this.setState({
76 | location: newLocation,
77 | paneOpened: this.getSplitViewConfig().openedDisplayMode === "overlay" ? false : this.state.paneOpened
78 | });
79 | },
80 | handleTogglePane: function () {
81 | this.setState({ paneOpened: !this.state.paneOpened });
82 | },
83 | handleAfterClose: function () {
84 | this.setState({ paneOpened: false });
85 | },
86 | getInitialState: function () {
87 | var mode = getMode();
88 |
89 | var groupKey = function (data) {
90 | return data.name[0].toUpperCase();
91 | };
92 |
93 | var groupData = function (data) {
94 | return { title: groupKey(data) };
95 | };
96 |
97 | var sorter = function (a, b) {
98 | if (a.name < b.name) {
99 | return -1;
100 | } else if (a.name > b.name) {
101 | return 1;
102 | } else {
103 | return 0;
104 | }
105 | };
106 |
107 | var data = new WinJS.Binding.List(Data.people)
108 | .createSorted(sorter)
109 | .createGrouped(groupKey, groupData);
110 |
111 | return {
112 | people: data,
113 | mode: mode,
114 | location: ["people"]
115 | };
116 | },
117 | componentWillMount: function () {
118 | window.addEventListener("resize", this.handleResize);
119 | },
120 | componentWillUnmount: function () {
121 | window.removeEventListener("resize", this.handleResize);
122 | },
123 | renderPeoplePage: function () {
124 | return (
125 |
131 | );
132 | },
133 | renderOtherPage: function () {
134 | return
135 | },
136 | renderContent: function () {
137 | if (this.state.location.length === 0 || this.state.location[0] === "people") {
138 | return this.renderPeoplePage();
139 | } else {
140 | return this.renderOtherPage();
141 | }
142 | },
143 | renderBackButton: function () {
144 | var canGoBack = this.state.location.length > 1;
145 | var shouldShowBackButton = canGoBack && this.state.mode === "small";
146 | return shouldShowBackButton ?
147 | :
148 | null;
149 | },
150 | render: function () {
151 | var paneComponent = (
152 |
153 |
157 |
161 |
165 |
166 |
171 |
172 | );
173 |
174 | var contentComponent = this.renderContent();
175 |
176 | return (
177 |
178 |
179 |
184 | {this.renderBackButton()}
185 |
Address Book
186 |
187 |
195 |
196 | );
197 | }
198 | });
199 |
200 | ReactDOM.render( , document.getElementById("app"));
201 |
--------------------------------------------------------------------------------
/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.peerDependencies.winjs;
17 | if (!fullWinjsVersion) {
18 | grunt.fail.fatal('Unable to determine WinJS version required by react-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 | 'react-winjs.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 + 'react-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 | src: "react-winjs.js",
67 | expand: true,
68 | nocase: true
69 | }, {
70 | cwd: publishRoot,
71 | src: bomGlob,
72 | expand: true,
73 | nocase: true
74 | }]
75 | }
76 | },
77 |
78 | nugetpack: {
79 | publish: {
80 | src: 'React.WinJS.nuspec',
81 | dest: publishRoot,
82 | options: {
83 | version: '<%= pkg.version %>'
84 | }
85 | }
86 | },
87 |
88 | // Publishes nuget package
89 | nugetpush: {
90 | // Requires NuGet API key to be set. You can do this with:
91 | // grunt nugetkey --key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
92 | publish: {
93 | src: publishRoot + '*.nupkg',
94 | }
95 | },
96 |
97 | // Publishes GitHub release and bower package (bower consumes GitHub tags/releases)
98 | 'github-release': {
99 | // Requires this environment variable to be set: GITHUB_ACCESS_TOKEN
100 | // GITHUB_ACCESS_TOKEN can be generated from https://help.github.com/articles/creating-an-access-token-for-command-line-use/
101 | publish: {
102 | options: {
103 | repository: 'winjs/react-winjs',
104 | auth: {
105 | user: process.env.GITHUB_ACCESS_TOKEN
106 | },
107 | release: {
108 | tag_name: 'v<%= pkg.version %>', // Must follow semver syntax in order for bower to pick it up
109 | target_commitish: currentGitCommitHash,
110 | name: '<%= pkg.version %>',
111 | body:
112 | 'Release of react-winjs <%= pkg.version %>.\n' +
113 | '\n' +
114 | 'Compatible with WinJS ' + winjsVersion + '.\n'
115 | }
116 | },
117 | files: {
118 | src: [publishRoot + 'react-winjs.zip']
119 | }
120 | }
121 | }
122 | });
123 |
124 | grunt.loadTasks('tasks/');
125 |
126 | var plugins = [
127 | 'grunt-contrib-clean',
128 | 'grunt-contrib-compress',
129 | 'grunt-contrib-copy',
130 | 'grunt-nuget',
131 | 'grunt-github-releaser'
132 | ];
133 | plugins.forEach(function (plugin) {
134 | grunt.loadNpmTasks(plugin);
135 | });
136 |
137 | // Publishes npm package
138 | grunt.registerTask('npm-release', function (mode) {
139 | var done = this.async();
140 | var cmd = 'npm publish ' + npmPublishRoot;
141 |
142 | exec(cmd, function (err, stdout) {
143 | if (err) {
144 | grunt.fatal('npm publish failed using command: ' + cmd);
145 | }
146 | done();
147 | });
148 | });
149 |
150 | // Sets up all of the state necessary to do a publish but doesn't actually publish
151 | // to any of the package managers.
152 | grunt.registerTask('prepare-publish', [
153 | 'clean:publish',
154 | 'copy:publish',
155 | 'compress:publish',
156 | 'nugetpack:publish',
157 | 'check-bom:publish',
158 | ]);
159 |
160 | grunt.registerTask('finished-publish', function (mode) {
161 | grunt.log.writeln('');
162 | grunt.log.writeln('Publish complete. Hand tweak the GitHub release description if necessary (https://github.com/winjs/react-winjs/releases)');
163 | grunt.log.writeln('');
164 | });
165 |
166 | //
167 | // Public tasks designed to be run from the command line
168 | //
169 |
170 | // Populates the 'dist' folder and then uses it to:
171 | // - Create a GitHub release
172 | // - Publish to npm
173 | // - Publish to bower
174 | // - Publish to NuGet
175 | // When debugging publish, it's helpful to run just the 'prepare-publish'
176 | // task which puts all of the publication data into the 'dist' folder but
177 | // doesn't actually send the data to the package managers.
178 | grunt.registerTask('publish', function (mode) {
179 | if (!process.env.GITHUB_ACCESS_TOKEN) {
180 | grunt.fail.fatal('The GITHUB_ACCESS_TOKEN environment variable must be set in order to create GitHub releases');
181 | }
182 |
183 | if (!mode) {
184 | grunt.log.writeln('');
185 | grunt.log.writeln('Will publish version ' + pkg.version + ' of react-winjs to npm, NuGet, etc. Double check that:');
186 | grunt.log.writeln(' * You are on the branch you\'d like to publish');
187 | grunt.log.writeln(' * The branch has been pushed to GitHub');
188 | grunt.log.writeln(' * You don\'t have any local edits');
189 | grunt.log.writeln('');
190 | grunt.log.writeln('If everything is in order, run "grunt publish:force" to proceed');
191 | } else if (mode === 'force') {
192 | grunt.task.run([
193 | 'prepare-publish',
194 | 'nugetpush:publish',
195 | 'github-release:publish',
196 | 'npm-release',
197 | 'finished-publish',
198 | ]);
199 | }
200 | });
201 | };
202 |
--------------------------------------------------------------------------------
/examples/movies/FakeData.js:
--------------------------------------------------------------------------------
1 | var nextMovieId = 0;
2 | var ratings = ["Unrated", "G", "PG", "PG-13", "R"];
3 | var firstNames = ["Charlsie", "Ofelia", "Jerome", "Leana", "Harlan", "Annalisa", "Leida", "Dessie", "Valrie", "Sharen", "Sergio", "Mitzie", "Celia", "Debbra", "Florida", "Kara", "Jacquie", "Sherley", "Carson", "Staci", "Paula", "Dann", "Linette", "Meri", "Almeta", "Detra", "Lupe", "Neville", "Marivel", "Carmine", "Carina", "Laureen", "Lourdes", "Laverne", "Verona", "Gertha", "Jene", "Joslyn", "Jone", "Latoya", "Margurite", "Emmett", "Wallace", "Elana", "Xiomara", "Sabra", "Ouida", "Kenton", "Norene", "Raul"];
4 | var lastNames = ["Avey", "Crofoot", "Flor", "Barletta", "Zoller", "Rosson", "Coomes", "Wilken", "Withey", "Ojeda", "Mennella", "Gauer", "Puccio", "Zimmerer", "Cottrell", "Bridgman", "Gershman", "Tinoco", "Ayoub", "Fournier", "Marcella", "Melrose", "Lafontaine", "Cathcart", "Cioffi", "Sands", "Lei", "Cardoso", "Dela", "Metcalfe", "Ethridge", "Fryer", "Warden", "Madson", "Gonsales", "Tobey", "Knecht", "Gallion", "Thibault", "Brockington", "Baney", "Haddox", "Kang", "Galyean", "Riccio", "Lake", "Mirabella", "Frechette", "Rearick", "Carmouche"];
5 | var loremIpsum = [
6 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum",
7 | "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur",
8 | "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?",
9 | "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",
10 | "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains.",
11 | ];
12 | var words = loremIpsum.join(" ").replace(/,|!|\?|\./g, "").replace(/-/g, " ").split(" ");
13 |
14 | var posterWidth = 153;
15 | var posterHeight = 243;
16 | var _canvas;
17 | function makePoster(color) {
18 | if (!_canvas) {
19 | _canvas = document.createElement("canvas");
20 | _canvas.width = posterWidth;
21 | _canvas.height = posterHeight;
22 | }
23 | var ctxt = _canvas.getContext("2d");
24 | ctxt.fillStyle = color;
25 | ctxt.fillRect(0, 0, posterWidth, posterHeight);
26 | return _canvas.toDataURL();
27 | }
28 |
29 | var posterColors = [
30 | [68, 34, 87], [100, 66, 119], [132, 98, 151],
31 | [164, 162, 165], [196, 194, 197], [228, 226, 229]
32 | ];
33 | var posters = posterColors.map(function (color) {
34 | return makePoster("rgb(" + color.join(", ") + ")");
35 | });
36 |
37 | function randomInt(first, last) {
38 | return Math.round(Math.random() * (last - first)) + first;
39 | }
40 |
41 | function randomElement(array) {
42 | return array[randomInt(0, array.length - 1)];
43 | }
44 |
45 | function genArray(minLength, maxLength, genElement) {
46 | var len = randomInt(minLength, maxLength);
47 | var result = new Array(len);
48 | for (var i = 0; i < len; i++) {
49 | result[i] = genElement();
50 | }
51 | return result;
52 | }
53 |
54 | function genActor() {
55 | return { name: randomElement(firstNames) + " " + randomElement(lastNames) };
56 | }
57 |
58 | function genTitleWord() {
59 | var word = randomElement(words).toLowerCase();
60 | return word[0].toUpperCase() + word.substr(1);
61 | }
62 |
63 | function genMovie() {
64 | return {
65 | id: nextMovieId++,
66 | title: (nextMovieId - 1 + " ") + genArray(1, 5, genTitleWord).join(" "),
67 | year: randomInt(1950, 2015),
68 | mpaa_rating: randomElement(ratings),
69 | synopsis: randomElement(loremIpsum),
70 | posters: {
71 | detailed: randomElement(posters)
72 | },
73 | ratings: {
74 | critics_score: randomInt(0, 100),
75 | audience_score: randomInt(0, 100)
76 | },
77 | abridged_cast: genArray(1, 8, genActor)
78 | };
79 | }
80 |
81 | var movieCount = 1000;
82 | var movies = genArray(movieCount, movieCount, genMovie);
83 | var moviesPerPage = 20;
84 | var fetchDelay = 500;
85 |
86 | function getSearchResults(query, page) {
87 | query = query.toLowerCase();
88 | var start = (page - 1) * moviesPerPage;
89 | var results = movies.filter(function (m) {
90 | return m.title.toLowerCase().indexOf(query) !== -1;
91 | });
92 | return WinJS.Promise.timeout(fetchDelay).then(function () {
93 | return {
94 | movies: results.slice(start, start + moviesPerPage),
95 | total: results.length
96 | };
97 | });
98 | }
99 |
100 | function getInTheaters(page) {
101 | var start = (page - 1) * moviesPerPage;
102 | return WinJS.Promise.timeout(fetchDelay).then(function () {
103 | return {
104 | movies: movies.slice(start, start + moviesPerPage),
105 | total: movies.length
106 | };
107 | });
108 | }
109 |
110 | module.exports = {
111 | getSearchResults: getSearchResults,
112 | getInTheaters: getInTheaters
113 | };
--------------------------------------------------------------------------------
/examples/address-book/FakeData.js:
--------------------------------------------------------------------------------
1 | var nextPersonId = 0;
2 | var firstNames = ["Aaliyah","Aaron","Abigail","Adam","Addison","Adrian","Aiden","Alexa","Alexandra","Alexis","Alice","Allison","Alyssa","Amelia","Andrew","Angel","Anna","Annabelle","Anthony","Aria","Ariana","Arianna","Asher","Ashley","Aubree","Aubrey","Audrey","Austin","Autumn","Ava","Avery","Ayden","Bella","Benjamin","Bentley","Blake","Brandon","Brayden","Brianna","Brody","Brooklyn","Caleb","Camden","Cameron","Camila","Caroline","Carson","Carter","Charles","Charlotte","Chase","Chloe","Christian","Christopher","Claire","Colton","Connor","Cooper","Daniel","David","Dominic","Dylan","Easton","Eleanor","Eli","Elijah","Elizabeth","Ella","Ellie","Emily","Emma","Eva","Evan","Evelyn","Faith","Gabriel","Gabriella","Gavin","Genesis","Gianna","Grace","Grayson","Hadley","Hailey","Hannah","Harper","Henry","Hudson","Hunter","Ian","Isaac","Isabella","Isabelle","Isaiah","Jace","Jack","Jackson","Jasmine","Jason","Jaxon","Jaxson","Jayden","Jeremiah","John","Jonathan","Jordan","Jose","Joseph","Joshua","Josiah","Juan","Julia","Julian","Justin","Katherine","Kayden","Kaylee","Kennedy","Kevin","Khloe","Kylie","Landon","Lauren","Layla","Leah","Leo","Levi","Lillian","Lily","Lincoln","Logan","London","Lucas","Lucy","Luis","Luke","Lydia","Mackenzie","Madeline","Madelyn","Madison","Matthew","Maya","Melanie","Mia","Mila","Naomi","Natalie","Nathan","Nathaniel","Nevaeh","Nicholas","Nolan","Nora","Oliver","Olivia","Owen","Paisley","Parker","Penelope","Peyton","Piper","Riley","Robert","Ruby","Ryan","Ryder","Sadie","Samantha","Samuel","Sarah","Savannah","Scarlett","Sebastian","Serenity","Skylar","Sofia","Sophia","Sophie","Stella","Taylor","Thomas","Tristan","Tyler","Victoria","Violet","Vivian","Wyatt","Xavier","Zachary","Zoe","Zoey"];
3 | var lastNames = ["Avey", "Crofoot", "Flor", "Barletta", "Zoller", "Rosson", "Coomes", "Wilken", "Withey", "Ojeda", "Mennella", "Gauer", "Puccio", "Zimmerer", "Cottrell", "Bridgman", "Gershman", "Tinoco", "Ayoub", "Fournier", "Marcella", "Melrose", "Lafontaine", "Cathcart", "Cioffi", "Sands", "Lei", "Cardoso", "Dela", "Metcalfe", "Ethridge", "Fryer", "Warden", "Madson", "Gonsales", "Tobey", "Knecht", "Gallion", "Thibault", "Brockington", "Baney", "Haddox", "Kang", "Galyean", "Riccio", "Lake", "Mirabella", "Frechette", "Rearick", "Carmouche"];
4 | var loremIpsum = [
5 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum",
6 | "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur",
7 | "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?",
8 | "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",
9 | "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains.",
10 | ];
11 | var statuses = [
12 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim.",
13 | "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo.",
14 | "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account.",
15 | "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas.",
16 | "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the."
17 | ];
18 |
19 | var posterWidth = 400;
20 | var posterHeight = 400;
21 | var _canvas;
22 | function makePoster(color) {
23 | if (!_canvas) {
24 | _canvas = document.createElement("canvas");
25 | _canvas.width = posterWidth;
26 | _canvas.height = posterHeight;
27 | }
28 | var ctxt = _canvas.getContext("2d");
29 | ctxt.fillStyle = color;
30 | ctxt.fillRect(0, 0, posterWidth, posterHeight);
31 | return _canvas.toDataURL();
32 | }
33 |
34 | var posterColors = [
35 | [68, 34, 87], [100, 66, 119], [132, 98, 151],
36 | [164, 162, 165], [196, 194, 197], [228, 226, 229],
37 | [220, 77, 6], [252, 109, 38], [255, 141, 70]
38 | ];
39 | var posters = posterColors.map(function (color) {
40 | return makePoster("rgb(" + color.join(", ") + ")");
41 | });
42 |
43 | function randomInt(first, last) {
44 | return Math.round(Math.random() * (last - first)) + first;
45 | }
46 |
47 | function randomElement(array) {
48 | return array[randomInt(0, array.length - 1)];
49 | }
50 |
51 | function genArray(minLength, maxLength, genElement) {
52 | var len = randomInt(minLength, maxLength);
53 | var result = new Array(len);
54 | for (var i = 0; i < len; i++) {
55 | result[i] = genElement();
56 | }
57 | return result;
58 | }
59 |
60 | function genName() {
61 | return randomElement(firstNames) + " " + randomElement(lastNames);
62 | }
63 |
64 | function genPhoneNumber() {
65 | return "555-0" + randomInt(100, 199);
66 | }
67 |
68 | function genPerson() {
69 | return {
70 | id: nextPersonId++,
71 | name: genName(),
72 | status: randomElement(statuses),
73 | statusHoursAgo: randomElement([2, 3, 4, 5, 6, 7, 8, 9]),
74 | picture: randomElement(posters),
75 | mobilePhone: genPhoneNumber(),
76 | workPhone: genPhoneNumber()
77 | };
78 | }
79 |
80 | var personCount = 50;
81 | var people = genArray(personCount, personCount, genPerson);
82 |
83 | module.exports = {
84 | people: people
85 | };
--------------------------------------------------------------------------------
/examples/address-book/PeoplePage.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var ReactWinJS = require('react-winjs');
5 | var ProfilePicture = require('./ProfilePicture.jsx');
6 |
7 | function calc100PercentMinus(n) {
8 | return n === 0 ?
9 | "100%" :
10 | "calc(100% - " + (n + "px") + ")";
11 | }
12 |
13 | var PeoplePage = React.createClass({
14 | handleToggleSelectionMode: function () {
15 | this.setState({
16 | selectionMode: !this.state.selectionMode
17 | });
18 | this.props.onNavigate(["people"]);
19 | this.refs.listView.winControl.selection.clear();
20 | },
21 | handleSelectionChanged: function (eventObject) {
22 | var listView = eventObject.currentTarget.winControl;
23 | var indices = listView.selection.getIndices();
24 | // Post to avoid navigating while in the middle of the event handler
25 | setTimeout(function () {
26 | this.setState({ selectedPeople: indices });
27 | this.props.onNavigate(indices.length === 1 && !this.state.selectionMode ? ["people", indices[0]] : ["people"]);
28 | }.bind(this), 0);
29 | },
30 | handleDelete: function () {
31 | var people = this.props.people;
32 | var indices = this.state.selectedPeople;
33 | indices.sort();
34 | indices.reverse();
35 | indices.forEach(function (i) {
36 | people.splice(i, 1);
37 | });
38 | this.setState({
39 | selectedPeople: [],
40 | selectionMode: false
41 | });
42 | this.props.onPeopleChanged(people);
43 | },
44 | handleContentAnimating: function (eventObject) {
45 | // Disable ListView's entrance animation
46 | if (eventObject.detail.type === "entrance") {
47 | eventObject.preventDefault();
48 | }
49 | },
50 | personRenderer: ReactWinJS.reactRenderer(function (person) {
51 | return (
52 |
53 |
54 |
{person.data.name}
55 |
56 | );
57 | }),
58 | groupHeaderRenderer: ReactWinJS.reactRenderer(function (item) {
59 | return (
60 | {item.data.title}
61 | );
62 | }),
63 | renderPeoplePane: function (peoplePaneWidth) {
64 | var deleteCommand = (
65 |
71 | );
72 |
73 | return (
74 |
75 |
76 |
81 |
86 |
91 |
96 |
97 |
102 | {this.state.selectionMode ? deleteCommand : null}
103 |
110 |
111 |
112 |
125 |
126 | );
127 | },
128 | renderProfilePane: function (selectedIndex, peoplePaneWidth) {
129 | if (selectedIndex === null) {
130 | return (
131 |
132 |
133 |
No Selection
134 |
135 |
136 | );
137 | } else {
138 | var selectedPerson = this.props.people.getAt(selectedIndex);
139 | return (
140 |
141 |
142 |
{selectedPerson.name}
143 |
144 |
145 |
146 |
147 | {selectedPerson.status}
148 |
149 | {selectedPerson.statusHoursAgo} hours ago
150 |
151 |
152 |
153 |
154 |
155 |
156 | Message
157 |
158 |
159 |
160 |
Call Mobile
161 |
{selectedPerson.mobilePhone}
162 |
163 |
164 |
165 |
166 |
167 |
Call Work
168 |
{selectedPerson.workPhone}
169 |
170 |
171 | Call using an app
172 | Video call
173 | Email work
174 | Map home
175 |
176 |
177 |
178 | );
179 | }
180 | },
181 | propTypes: {
182 | mode: React.PropTypes.oneOf(["small", "medium", "large"]).isRequired,
183 | people: React.PropTypes.object.isRequired,
184 | location: React.PropTypes.array.isRequired,
185 | onNavigate: React.PropTypes.func.isRequired,
186 | onPeopleChanged: React.PropTypes.func.isRequired
187 | },
188 | getInitialState: function () {
189 | return {
190 | layout: { type: WinJS.UI.ListLayout },
191 | selectedPeople: [],
192 | selectionMode: false
193 | };
194 | },
195 | render: function () {
196 | var selectedIndex = this.props.location.length >= 2 ? this.props.location[1] : null;
197 |
198 | if (this.props.mode === "small") {
199 | if (selectedIndex === null) {
200 | return this.renderPeoplePane("100%");
201 | } else {
202 | return this.renderProfilePane(selectedIndex, 0);
203 | }
204 | } else {
205 | var peoplePaneWidth = 320;
206 | return (
207 |
208 | {this.renderPeoplePane(peoplePaneWidth)}
209 | {this.renderProfilePane(selectedIndex, peoplePaneWidth)}
210 |
211 | );
212 | }
213 | }
214 | });
215 |
216 | module.exports = PeoplePage;
217 |
--------------------------------------------------------------------------------
/react-winjs.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactDOM = require('react-dom');
3 | var ReactDOMServer = require('react-dom/server');
4 | var WinJS = require("winjs");
5 |
6 | //
7 | // Implementation Overview
8 | //
9 | // react-winjs is organized around the concept of prop handlers. A prop handler describes
10 | // how a react-winjs prop affects the underlying WinJS control. Prop handlers come from 3 sources:
11 | // 1. Handwritten common to all controls. These are defined in a variable called
12 | // *defaultPropHandlers*. These are prop handlers which appear on every react-winjs component.
13 | // 2. WinJS's d.ts file. Most of the prop handlers for each react-winjs component are
14 | // automatically generated from WinJS's d.ts file. Information from the d.ts file is stored in
15 | // a variable called *RawControlApis*. *RawControlApis* is generated by running the d.ts file
16 | // through this tool: https://github.com/winjs/winjs-control-apis
17 | // 3. Handwritten control-specific. These are defined in a variable called *ControlApis*. When
18 | // a react-winjs component has a prop that needs to be defined manually, this is where it
19 | // should be defined. There are a number of types of builtin prop handlers defined in the
20 | // *PropHandlers* variable which can be used here.
21 | //
22 | // When react-winjs builds the list of prop handlers for a component, it gathers them from the above
23 | // list of sources. If multiple sources define a prop handler with the same name, the one from the
24 | // source which appears closest to the bottom of the list above wins.
25 | //
26 | // There's a particular category of WinJS controls that host content that proved to be particularly
27 | // challenging to wrap as React components. More specifically, the controls in this category:
28 | // - host content
29 | // - move the hosted content around in the DOM
30 | // - store the hosted content in a Binding.List
31 | //
32 | // Controls that fall into this category of hosting content include:
33 | // - AppBar/ToolBar
34 | // - Hub
35 | // - Pivot
36 | //
37 | // And the controls that get hosted include (these are the ones that end up being created
38 | // through WinJSChildComponent, described below):
39 | // - AppBarCommand
40 | // - HubSection
41 | // - PivotItem
42 | //
43 | // What made this challenging to solve is that there are some features that aren't achievable in
44 | // a straight forward way through the React APIs. To solve this, you want to be able to:
45 | // - Render a React component *onto* an existing element. ReactDOM.render can only render *into* an
46 | // existing element. For example, when creating a HubSection you want to be able to control
47 | // attributes of the win-hub-section element such as its *class* and *style*. With ReactDOM.render,
48 | // you'd only be able to render into the win-hub-section element so the React component wouldn't
49 | // be able to control any attributes of the win-hub-section element.
50 | // - Hold onto a rendered component and inspect its *type* and *key* prop later. This information
51 | // comes in handy when diffing an array of components from a previous render pass with an array
52 | // of components for the current render pass. The diff information is used to mutate a
53 | // Binding.List to get it into the desired state.
54 | //
55 | // The WinJSChildComponent class provides a convenient API for solving both of these problems. When the
56 | // constructor receives a component, it creates the element (e.g. win-hub-section) that the component
57 | // is rendered *onto*. The owning control (e.g. WinJS.UI.Hub) is free to manage that element and move
58 | // it around the DOM. WinJSChildComponent provides the following APIs:
59 | // - update: Updates the element based on the component description that is passed in.
60 | // - dispose: Disposes the react-winjs component and its associated WinJS control.
61 | // - key: Returns the React key associated with the component.
62 | // - type: Returns the React type associated with the component.
63 | //
64 |
65 | // Generated from https://github.com/winjs/winjs-control-apis
66 | var RawControlApis = {
67 | AppBar: {
68 | closedDisplayMode: {
69 | type: "enum",
70 | values: [
71 | "compact",
72 | "full",
73 | "minimal",
74 | "none"
75 | ]
76 | },
77 | data: {
78 | name: "WinJS.Binding.List",
79 | type: "reference",
80 | typeArguments: [
81 | {
82 | name: "WinJS.UI.ICommand",
83 | type: "reference",
84 | typeArguments: []
85 | }
86 | ]
87 | },
88 | element: {
89 | name: "HTMLElement",
90 | type: "reference",
91 | typeArguments: []
92 | },
93 | onAfterClose: {
94 | name: "Function",
95 | type: "reference",
96 | typeArguments: []
97 | },
98 | onAfterOpen: {
99 | name: "Function",
100 | type: "reference",
101 | typeArguments: []
102 | },
103 | onBeforeClose: {
104 | name: "Function",
105 | type: "reference",
106 | typeArguments: []
107 | },
108 | onBeforeOpen: {
109 | name: "Function",
110 | type: "reference",
111 | typeArguments: []
112 | },
113 | opened: {
114 | type: "boolean"
115 | },
116 | placement: {
117 | type: "enum",
118 | values: [
119 | "bottom",
120 | "top"
121 | ]
122 | }
123 | },
124 | AppBarCommand: {
125 | disabled: {
126 | type: "boolean"
127 | },
128 | element: {
129 | name: "HTMLElement",
130 | type: "reference",
131 | typeArguments: []
132 | },
133 | extraClass: {
134 | type: "string"
135 | },
136 | firstElementFocus: {
137 | name: "HTMLElement",
138 | type: "reference",
139 | typeArguments: []
140 | },
141 | flyout: {
142 | name: "WinJS.UI.Flyout",
143 | type: "reference",
144 | typeArguments: []
145 | },
146 | hidden: {
147 | type: "boolean"
148 | },
149 | icon: {
150 | type: "string"
151 | },
152 | id: {
153 | type: "string"
154 | },
155 | label: {
156 | type: "string"
157 | },
158 | lastElementFocus: {
159 | name: "HTMLElement",
160 | type: "reference",
161 | typeArguments: []
162 | },
163 | onClick: {
164 | name: "Function",
165 | type: "reference",
166 | typeArguments: []
167 | },
168 | priority: {
169 | type: "number"
170 | },
171 | section: {
172 | type: "string"
173 | },
174 | selected: {
175 | type: "boolean"
176 | },
177 | tooltip: {
178 | type: "string"
179 | },
180 | type: {
181 | type: "string"
182 | }
183 | },
184 | AutoSuggestBox: {
185 | chooseSuggestionOnEnter: {
186 | type: "boolean"
187 | },
188 | disabled: {
189 | type: "boolean"
190 | },
191 | element: {
192 | name: "HTMLElement",
193 | type: "reference",
194 | typeArguments: []
195 | },
196 | onQueryChanged: {
197 | name: "Function",
198 | type: "reference",
199 | typeArguments: []
200 | },
201 | onQuerySubmitted: {
202 | name: "Function",
203 | type: "reference",
204 | typeArguments: []
205 | },
206 | onResultSuggestionChosen: {
207 | name: "Function",
208 | type: "reference",
209 | typeArguments: []
210 | },
211 | onSuggestionsRequested: {
212 | name: "Function",
213 | type: "reference",
214 | typeArguments: []
215 | },
216 | placeholderText: {
217 | type: "string"
218 | },
219 | queryText: {
220 | type: "string"
221 | },
222 | searchHistoryContext: {
223 | type: "string"
224 | },
225 | searchHistoryDisabled: {
226 | type: "boolean"
227 | }
228 | },
229 | BackButton: {
230 | element: {
231 | name: "HTMLElement",
232 | type: "reference",
233 | typeArguments: []
234 | }
235 | },
236 | CellSpanningLayout: {
237 | groupHeaderPosition: {
238 | type: "enum",
239 | values: [
240 | "left",
241 | "top"
242 | ]
243 | },
244 | groupInfo: {
245 | name: "Function",
246 | type: "reference",
247 | typeArguments: []
248 | },
249 | itemInfo: {
250 | name: "Function",
251 | type: "reference",
252 | typeArguments: []
253 | },
254 | maximumRowsOrColumns: {
255 | type: "number"
256 | },
257 | numberOfItemsPerItemsBlock: {
258 | type: "any"
259 | },
260 | orientation: {
261 | type: "enum",
262 | values: [
263 | "horizontal",
264 | "vertical"
265 | ]
266 | }
267 | },
268 | Command: {
269 | disabled: {
270 | type: "boolean"
271 | },
272 | element: {
273 | name: "HTMLElement",
274 | type: "reference",
275 | typeArguments: []
276 | },
277 | extraClass: {
278 | type: "string"
279 | },
280 | firstElementFocus: {
281 | name: "HTMLElement",
282 | type: "reference",
283 | typeArguments: []
284 | },
285 | flyout: {
286 | name: "WinJS.UI.Flyout",
287 | type: "reference",
288 | typeArguments: []
289 | },
290 | hidden: {
291 | type: "boolean"
292 | },
293 | icon: {
294 | type: "string"
295 | },
296 | id: {
297 | type: "string"
298 | },
299 | label: {
300 | type: "string"
301 | },
302 | lastElementFocus: {
303 | name: "HTMLElement",
304 | type: "reference",
305 | typeArguments: []
306 | },
307 | onClick: {
308 | name: "Function",
309 | type: "reference",
310 | typeArguments: []
311 | },
312 | priority: {
313 | type: "number"
314 | },
315 | section: {
316 | type: "string"
317 | },
318 | selected: {
319 | type: "boolean"
320 | },
321 | tooltip: {
322 | type: "string"
323 | },
324 | type: {
325 | type: "string"
326 | }
327 | },
328 | ContentDialog: {
329 | element: {
330 | name: "HTMLElement",
331 | type: "reference",
332 | typeArguments: []
333 | },
334 | hidden: {
335 | type: "boolean"
336 | },
337 | onAfterHide: {
338 | name: "Function",
339 | type: "reference",
340 | typeArguments: []
341 | },
342 | onAfterShow: {
343 | name: "Function",
344 | type: "reference",
345 | typeArguments: []
346 | },
347 | onBeforeHide: {
348 | name: "Function",
349 | type: "reference",
350 | typeArguments: []
351 | },
352 | onBeforeShow: {
353 | name: "Function",
354 | type: "reference",
355 | typeArguments: []
356 | },
357 | primaryCommandDisabled: {
358 | type: "boolean"
359 | },
360 | primaryCommandText: {
361 | type: "string"
362 | },
363 | secondaryCommandDisabled: {
364 | type: "boolean"
365 | },
366 | secondaryCommandText: {
367 | type: "string"
368 | },
369 | title: {
370 | type: "string"
371 | }
372 | },
373 | DatePicker: {
374 | calendar: {
375 | type: "string"
376 | },
377 | current: {
378 | name: "Date",
379 | type: "reference",
380 | typeArguments: []
381 | },
382 | datePattern: {
383 | type: "string"
384 | },
385 | disabled: {
386 | type: "boolean"
387 | },
388 | element: {
389 | name: "HTMLElement",
390 | type: "reference",
391 | typeArguments: []
392 | },
393 | maxYear: {
394 | type: "number"
395 | },
396 | minYear: {
397 | type: "number"
398 | },
399 | monthPattern: {
400 | type: "string"
401 | },
402 | onChange: {
403 | name: "Function",
404 | type: "reference",
405 | typeArguments: []
406 | },
407 | yearPattern: {
408 | type: "string"
409 | }
410 | },
411 | FlipView: {
412 | currentPage: {
413 | type: "number"
414 | },
415 | element: {
416 | name: "HTMLElement",
417 | type: "reference",
418 | typeArguments: []
419 | },
420 | itemDataSource: {
421 | name: "WinJS.UI.IListDataSource",
422 | type: "reference",
423 | typeArguments: [
424 | {
425 | name: "T",
426 | type: "type-param"
427 | }
428 | ]
429 | },
430 | itemSpacing: {
431 | type: "number"
432 | },
433 | itemTemplate: {
434 | type: "any"
435 | },
436 | onDataSourceCountChanged: {
437 | name: "Function",
438 | type: "reference",
439 | typeArguments: []
440 | },
441 | onPageCompleted: {
442 | name: "Function",
443 | type: "reference",
444 | typeArguments: []
445 | },
446 | onPageSelected: {
447 | name: "Function",
448 | type: "reference",
449 | typeArguments: []
450 | },
451 | onPageVisibilityChanged: {
452 | name: "Function",
453 | type: "reference",
454 | typeArguments: []
455 | },
456 | orientation: {
457 | type: "string"
458 | }
459 | },
460 | Flyout: {
461 | alignment: {
462 | type: "string"
463 | },
464 | anchor: {
465 | name: "HTMLElement",
466 | type: "reference",
467 | typeArguments: []
468 | },
469 | disabled: {
470 | type: "boolean"
471 | },
472 | element: {
473 | name: "HTMLElement",
474 | type: "reference",
475 | typeArguments: []
476 | },
477 | hidden: {
478 | type: "boolean"
479 | },
480 | onAfterHide: {
481 | name: "Function",
482 | type: "reference",
483 | typeArguments: []
484 | },
485 | onAfterShow: {
486 | name: "Function",
487 | type: "reference",
488 | typeArguments: []
489 | },
490 | onBeforeHide: {
491 | name: "Function",
492 | type: "reference",
493 | typeArguments: []
494 | },
495 | onBeforeShow: {
496 | name: "Function",
497 | type: "reference",
498 | typeArguments: []
499 | },
500 | placement: {
501 | type: "string"
502 | }
503 | },
504 | GridLayout: {
505 | backdropColor: {
506 | type: "string"
507 | },
508 | disableBackdrop: {
509 | type: "boolean"
510 | },
511 | groupHeaderPosition: {
512 | type: "enum",
513 | values: [
514 | "left",
515 | "top"
516 | ]
517 | },
518 | groupInfo: {
519 | name: "Function",
520 | type: "reference",
521 | typeArguments: []
522 | },
523 | itemInfo: {
524 | name: "Function",
525 | type: "reference",
526 | typeArguments: []
527 | },
528 | maxRows: {
529 | type: "number"
530 | },
531 | maximumRowsOrColumns: {
532 | type: "number"
533 | },
534 | numberOfItemsPerItemsBlock: {
535 | type: "any"
536 | },
537 | orientation: {
538 | type: "enum",
539 | values: [
540 | "horizontal",
541 | "vertical"
542 | ]
543 | }
544 | },
545 | Hub: {
546 | element: {
547 | name: "HTMLElement",
548 | type: "reference",
549 | typeArguments: []
550 | },
551 | headerTemplate: {
552 | type: "any"
553 | },
554 | indexOfFirstVisible: {
555 | type: "number"
556 | },
557 | indexOfLastVisible: {
558 | type: "number"
559 | },
560 | loadingState: {
561 | type: "enum",
562 | values: [
563 | "complete",
564 | "loading"
565 | ]
566 | },
567 | onContentAnimating: {
568 | name: "Function",
569 | type: "reference",
570 | typeArguments: []
571 | },
572 | onHeaderInvoked: {
573 | name: "Function",
574 | type: "reference",
575 | typeArguments: []
576 | },
577 | onLoadingStateChanged: {
578 | name: "Function",
579 | type: "reference",
580 | typeArguments: []
581 | },
582 | orientation: {
583 | type: "enum",
584 | values: [
585 | "horizontal",
586 | "vertical"
587 | ]
588 | },
589 | scrollPosition: {
590 | type: "number"
591 | },
592 | sectionOnScreen: {
593 | type: "number"
594 | },
595 | sections: {
596 | name: "WinJS.Binding.List",
597 | type: "reference",
598 | typeArguments: [
599 | {
600 | name: "WinJS.UI.HubSection",
601 | type: "reference",
602 | typeArguments: []
603 | }
604 | ]
605 | },
606 | zoomableView: {
607 | name: "WinJS.UI.IZoomableView",
608 | type: "reference",
609 | typeArguments: [
610 | {
611 | type: "any"
612 | }
613 | ]
614 | }
615 | },
616 | HubSection: {
617 | contentElement: {
618 | name: "HTMLElement",
619 | type: "reference",
620 | typeArguments: []
621 | },
622 | element: {
623 | name: "HTMLElement",
624 | type: "reference",
625 | typeArguments: []
626 | },
627 | header: {
628 | type: "string"
629 | },
630 | isHeaderStatic: {
631 | type: "boolean"
632 | }
633 | },
634 | ItemContainer: {
635 | draggable: {
636 | type: "boolean"
637 | },
638 | element: {
639 | name: "HTMLElement",
640 | type: "reference",
641 | typeArguments: []
642 | },
643 | onInvoked: {
644 | name: "Function",
645 | type: "reference",
646 | typeArguments: []
647 | },
648 | onSelectionChanged: {
649 | name: "Function",
650 | type: "reference",
651 | typeArguments: []
652 | },
653 | onSelectionChanging: {
654 | name: "Function",
655 | type: "reference",
656 | typeArguments: []
657 | },
658 | selected: {
659 | type: "boolean"
660 | },
661 | selectionDisabled: {
662 | type: "boolean"
663 | },
664 | swipeBehavior: {
665 | type: "enum",
666 | values: [
667 | "none",
668 | "select"
669 | ]
670 | },
671 | swipeOrientation: {
672 | type: "enum",
673 | values: [
674 | "horizontal",
675 | "vertical"
676 | ]
677 | },
678 | tapBehavior: {
679 | type: "enum",
680 | values: [
681 | "directSelect",
682 | "invokeOnly",
683 | "none",
684 | "toggleSelect"
685 | ]
686 | }
687 | },
688 | ListLayout: {
689 | backdropColor: {
690 | type: "string"
691 | },
692 | disableBackdrop: {
693 | type: "boolean"
694 | },
695 | groupHeaderPosition: {
696 | type: "enum",
697 | values: [
698 | "left",
699 | "top"
700 | ]
701 | },
702 | numberOfItemsPerItemsBlock: {
703 | type: "any"
704 | },
705 | orientation: {
706 | type: "enum",
707 | values: [
708 | "horizontal",
709 | "vertical"
710 | ]
711 | }
712 | },
713 | ListView: {
714 | automaticallyLoadPages: {
715 | type: "boolean"
716 | },
717 | currentItem: {
718 | name: "WinJS.UI.IListViewItem",
719 | type: "reference",
720 | typeArguments: []
721 | },
722 | element: {
723 | name: "HTMLElement",
724 | type: "reference",
725 | typeArguments: []
726 | },
727 | footer: {
728 | name: "HTMLElement",
729 | type: "reference",
730 | typeArguments: []
731 | },
732 | groupDataSource: {
733 | name: "WinJS.UI.IListDataSource",
734 | type: "reference",
735 | typeArguments: [
736 | {
737 | name: "T",
738 | type: "type-param"
739 | }
740 | ]
741 | },
742 | groupHeaderTapBehavior: {
743 | type: "enum",
744 | values: [
745 | "invoke",
746 | "none"
747 | ]
748 | },
749 | groupHeaderTemplate: {
750 | type: "any"
751 | },
752 | header: {
753 | name: "HTMLElement",
754 | type: "reference",
755 | typeArguments: []
756 | },
757 | indexOfFirstVisible: {
758 | type: "number"
759 | },
760 | indexOfLastVisible: {
761 | type: "number"
762 | },
763 | itemDataSource: {
764 | name: "WinJS.UI.IListDataSource",
765 | type: "reference",
766 | typeArguments: [
767 | {
768 | name: "T",
769 | type: "type-param"
770 | }
771 | ]
772 | },
773 | itemTemplate: {
774 | type: "any"
775 | },
776 | itemsDraggable: {
777 | type: "boolean"
778 | },
779 | itemsReorderable: {
780 | type: "boolean"
781 | },
782 | layout: {
783 | name: "WinJS.UI.ILayout2",
784 | type: "reference",
785 | typeArguments: []
786 | },
787 | loadingBehavior: {
788 | type: "string"
789 | },
790 | loadingState: {
791 | type: "string"
792 | },
793 | maxDeferredItemCleanup: {
794 | type: "number"
795 | },
796 | maxLeadingPages: {
797 | type: "number"
798 | },
799 | maxTrailingPages: {
800 | type: "number"
801 | },
802 | onAccessibilityAnnotationComplete: {
803 | name: "Function",
804 | type: "reference",
805 | typeArguments: []
806 | },
807 | onContentAnimating: {
808 | name: "Function",
809 | type: "reference",
810 | typeArguments: []
811 | },
812 | onFooterVisibilityChanged: {
813 | name: "Function",
814 | type: "reference",
815 | typeArguments: []
816 | },
817 | onGroupHeaderInvoked: {
818 | name: "Function",
819 | type: "reference",
820 | typeArguments: []
821 | },
822 | onHeaderVisibilityChanged: {
823 | name: "Function",
824 | type: "reference",
825 | typeArguments: []
826 | },
827 | onItemDragBetween: {
828 | name: "Function",
829 | type: "reference",
830 | typeArguments: []
831 | },
832 | onItemDragChanged: {
833 | name: "Function",
834 | type: "reference",
835 | typeArguments: []
836 | },
837 | onItemDragDrop: {
838 | name: "Function",
839 | type: "reference",
840 | typeArguments: []
841 | },
842 | onItemDragEnd: {
843 | name: "Function",
844 | type: "reference",
845 | typeArguments: []
846 | },
847 | onItemDragEnter: {
848 | name: "Function",
849 | type: "reference",
850 | typeArguments: []
851 | },
852 | onItemDragLeave: {
853 | name: "Function",
854 | type: "reference",
855 | typeArguments: []
856 | },
857 | onItemDragStart: {
858 | name: "Function",
859 | type: "reference",
860 | typeArguments: []
861 | },
862 | onItemInvoked: {
863 | name: "Function",
864 | type: "reference",
865 | typeArguments: []
866 | },
867 | onKeyboardNavigating: {
868 | name: "Function",
869 | type: "reference",
870 | typeArguments: []
871 | },
872 | onLoadingStateChanged: {
873 | name: "Function",
874 | type: "reference",
875 | typeArguments: []
876 | },
877 | onSelectionChanged: {
878 | name: "Function",
879 | type: "reference",
880 | typeArguments: []
881 | },
882 | onSelectionChanging: {
883 | name: "Function",
884 | type: "reference",
885 | typeArguments: []
886 | },
887 | pagesToLoad: {
888 | type: "number"
889 | },
890 | pagesToLoadThreshold: {
891 | type: "number"
892 | },
893 | scrollPosition: {
894 | type: "number"
895 | },
896 | selection: {
897 | name: "WinJS.UI.ISelection",
898 | type: "reference",
899 | typeArguments: [
900 | {
901 | name: "T",
902 | type: "type-param"
903 | }
904 | ]
905 | },
906 | selectionMode: {
907 | type: "enum",
908 | values: [
909 | "multi",
910 | "none",
911 | "single"
912 | ]
913 | },
914 | swipeBehavior: {
915 | type: "enum",
916 | values: [
917 | "none",
918 | "select"
919 | ]
920 | },
921 | tapBehavior: {
922 | type: "enum",
923 | values: [
924 | "directSelect",
925 | "invokeOnly",
926 | "none",
927 | "toggleSelect"
928 | ]
929 | },
930 | zoomableView: {
931 | name: "WinJS.UI.IZoomableView",
932 | type: "reference",
933 | typeArguments: [
934 | {
935 | name: "WinJS.UI.ListView",
936 | type: "reference",
937 | typeArguments: [
938 | {
939 | name: "T",
940 | type: "type-param"
941 | }
942 | ]
943 | }
944 | ]
945 | }
946 | },
947 | Menu: {
948 | alignment: {
949 | type: "string"
950 | },
951 | anchor: {
952 | name: "HTMLElement",
953 | type: "reference",
954 | typeArguments: []
955 | },
956 | commands: {
957 | name: "Array",
958 | type: "reference",
959 | typeArguments: [
960 | {
961 | name: "WinJS.UI.MenuCommand",
962 | type: "reference",
963 | typeArguments: []
964 | }
965 | ]
966 | },
967 | disabled: {
968 | type: "boolean"
969 | },
970 | element: {
971 | name: "HTMLElement",
972 | type: "reference",
973 | typeArguments: []
974 | },
975 | hidden: {
976 | type: "boolean"
977 | },
978 | onAfterHide: {
979 | name: "Function",
980 | type: "reference",
981 | typeArguments: []
982 | },
983 | onAfterShow: {
984 | name: "Function",
985 | type: "reference",
986 | typeArguments: []
987 | },
988 | onBeforeHide: {
989 | name: "Function",
990 | type: "reference",
991 | typeArguments: []
992 | },
993 | onBeforeShow: {
994 | name: "Function",
995 | type: "reference",
996 | typeArguments: []
997 | },
998 | placement: {
999 | type: "string"
1000 | }
1001 | },
1002 | MenuCommand: {
1003 | disabled: {
1004 | type: "boolean"
1005 | },
1006 | element: {
1007 | name: "HTMLElement",
1008 | type: "reference",
1009 | typeArguments: []
1010 | },
1011 | extraClass: {
1012 | type: "string"
1013 | },
1014 | flyout: {
1015 | name: "WinJS.UI.Flyout",
1016 | type: "reference",
1017 | typeArguments: []
1018 | },
1019 | hidden: {
1020 | type: "boolean"
1021 | },
1022 | id: {
1023 | type: "string"
1024 | },
1025 | label: {
1026 | type: "string"
1027 | },
1028 | onClick: {
1029 | name: "Function",
1030 | type: "reference",
1031 | typeArguments: []
1032 | },
1033 | selected: {
1034 | type: "boolean"
1035 | },
1036 | type: {
1037 | type: "string"
1038 | }
1039 | },
1040 | NavBar: {
1041 | closedDisplayMode: {
1042 | type: "string"
1043 | },
1044 | commands: {
1045 | name: "WinJS.UI.AppBarCommand",
1046 | type: "reference",
1047 | typeArguments: []
1048 | },
1049 | element: {
1050 | name: "HTMLElement",
1051 | type: "reference",
1052 | typeArguments: []
1053 | },
1054 | hidden: {
1055 | type: "boolean"
1056 | },
1057 | onAfterClose: {
1058 | name: "Function",
1059 | type: "reference",
1060 | typeArguments: []
1061 | },
1062 | onAfterOpen: {
1063 | name: "Function",
1064 | type: "reference",
1065 | typeArguments: []
1066 | },
1067 | onBeforeClose: {
1068 | name: "Function",
1069 | type: "reference",
1070 | typeArguments: []
1071 | },
1072 | onBeforeOpen: {
1073 | name: "Function",
1074 | type: "reference",
1075 | typeArguments: []
1076 | },
1077 | onChildrenProcessed: {
1078 | name: "Function",
1079 | type: "reference",
1080 | typeArguments: []
1081 | },
1082 | opened: {
1083 | type: "boolean"
1084 | },
1085 | placement: {
1086 | type: "string"
1087 | }
1088 | },
1089 | NavBarCommand: {
1090 | element: {
1091 | name: "HTMLElement",
1092 | type: "reference",
1093 | typeArguments: []
1094 | },
1095 | icon: {
1096 | type: "string"
1097 | },
1098 | label: {
1099 | type: "string"
1100 | },
1101 | location: {
1102 | type: "any"
1103 | },
1104 | onInvoked: {
1105 | name: "Function",
1106 | type: "reference",
1107 | typeArguments: []
1108 | },
1109 | splitButton: {
1110 | type: "boolean"
1111 | },
1112 | splitOpened: {
1113 | type: "boolean"
1114 | },
1115 | state: {
1116 | type: "any"
1117 | },
1118 | tooltip: {
1119 | type: "string"
1120 | }
1121 | },
1122 | NavBarContainer: {
1123 | currentIndex: {
1124 | type: "number"
1125 | },
1126 | data: {
1127 | name: "WinJS.Binding.List",
1128 | type: "reference",
1129 | typeArguments: [
1130 | {
1131 | name: "WinJS.UI.NavBarCommand",
1132 | type: "reference",
1133 | typeArguments: []
1134 | }
1135 | ]
1136 | },
1137 | element: {
1138 | name: "HTMLElement",
1139 | type: "reference",
1140 | typeArguments: []
1141 | },
1142 | fixedSize: {
1143 | type: "boolean"
1144 | },
1145 | layout: {
1146 | type: "enum",
1147 | values: [
1148 | "horizontal",
1149 | "vertical"
1150 | ]
1151 | },
1152 | maxRows: {
1153 | type: "number"
1154 | },
1155 | onInvoked: {
1156 | name: "Function",
1157 | type: "reference",
1158 | typeArguments: []
1159 | },
1160 | onSplitToggle: {
1161 | name: "Function",
1162 | type: "reference",
1163 | typeArguments: []
1164 | },
1165 | template: {
1166 | name: "WinJS.Binding.Template",
1167 | type: "reference",
1168 | typeArguments: []
1169 | }
1170 | },
1171 | Pivot: {
1172 | customLeftHeader: {
1173 | name: "HTMLElement",
1174 | type: "reference",
1175 | typeArguments: []
1176 | },
1177 | customRightHeader: {
1178 | name: "HTMLElement",
1179 | type: "reference",
1180 | typeArguments: []
1181 | },
1182 | element: {
1183 | name: "HTMLElement",
1184 | type: "reference",
1185 | typeArguments: []
1186 | },
1187 | items: {
1188 | name: "WinJS.Binding.List",
1189 | type: "reference",
1190 | typeArguments: [
1191 | {
1192 | name: "WinJS.UI.PivotItem",
1193 | type: "reference",
1194 | typeArguments: []
1195 | }
1196 | ]
1197 | },
1198 | locked: {
1199 | type: "boolean"
1200 | },
1201 | onItemAnimationEnd: {
1202 | name: "Function",
1203 | type: "reference",
1204 | typeArguments: []
1205 | },
1206 | onItemAnimationStart: {
1207 | name: "Function",
1208 | type: "reference",
1209 | typeArguments: []
1210 | },
1211 | onSelectionChanged: {
1212 | name: "Function",
1213 | type: "reference",
1214 | typeArguments: []
1215 | },
1216 | selectedIndex: {
1217 | type: "number"
1218 | },
1219 | selectedItem: {
1220 | name: "WinJS.UI.PivotItem",
1221 | type: "reference",
1222 | typeArguments: []
1223 | },
1224 | title: {
1225 | type: "string"
1226 | }
1227 | },
1228 | PivotItem: {
1229 | contentElement: {
1230 | name: "HTMLElement",
1231 | type: "reference",
1232 | typeArguments: []
1233 | },
1234 | element: {
1235 | name: "HTMLElement",
1236 | type: "reference",
1237 | typeArguments: []
1238 | },
1239 | header: {
1240 | type: "string"
1241 | }
1242 | },
1243 | Rating: {
1244 | averageRating: {
1245 | type: "number"
1246 | },
1247 | disabled: {
1248 | type: "boolean"
1249 | },
1250 | element: {
1251 | name: "HTMLElement",
1252 | type: "reference",
1253 | typeArguments: []
1254 | },
1255 | enableClear: {
1256 | type: "boolean"
1257 | },
1258 | maxRating: {
1259 | type: "number"
1260 | },
1261 | onCancel: {
1262 | name: "Function",
1263 | type: "reference",
1264 | typeArguments: []
1265 | },
1266 | onChange: {
1267 | name: "Function",
1268 | type: "reference",
1269 | typeArguments: []
1270 | },
1271 | onPreviewChange: {
1272 | name: "Function",
1273 | type: "reference",
1274 | typeArguments: []
1275 | },
1276 | tooltipStrings: {
1277 | name: "Array",
1278 | type: "reference",
1279 | typeArguments: [
1280 | {
1281 | type: "string"
1282 | }
1283 | ]
1284 | },
1285 | userRating: {
1286 | type: "number"
1287 | }
1288 | },
1289 | SearchBox: {
1290 | chooseSuggestionOnEnter: {
1291 | type: "boolean"
1292 | },
1293 | disabled: {
1294 | type: "boolean"
1295 | },
1296 | element: {
1297 | name: "HTMLElement",
1298 | type: "reference",
1299 | typeArguments: []
1300 | },
1301 | focusOnKeyboardInput: {
1302 | type: "boolean"
1303 | },
1304 | onQueryChanged: {
1305 | name: "Function",
1306 | type: "reference",
1307 | typeArguments: []
1308 | },
1309 | onQuerySubmitted: {
1310 | name: "Function",
1311 | type: "reference",
1312 | typeArguments: []
1313 | },
1314 | onResultSuggestionChosen: {
1315 | name: "Function",
1316 | type: "reference",
1317 | typeArguments: []
1318 | },
1319 | onSuggestionsRequested: {
1320 | name: "Function",
1321 | type: "reference",
1322 | typeArguments: []
1323 | },
1324 | placeholderText: {
1325 | type: "string"
1326 | },
1327 | queryText: {
1328 | type: "string"
1329 | },
1330 | searchHistoryContext: {
1331 | type: "string"
1332 | },
1333 | searchHistoryDisabled: {
1334 | type: "boolean"
1335 | }
1336 | },
1337 | SemanticZoom: {
1338 | element: {
1339 | name: "HTMLElement",
1340 | type: "reference",
1341 | typeArguments: []
1342 | },
1343 | enableButton: {
1344 | type: "boolean"
1345 | },
1346 | locked: {
1347 | type: "boolean"
1348 | },
1349 | onZoomChanged: {
1350 | name: "Function",
1351 | type: "reference",
1352 | typeArguments: []
1353 | },
1354 | zoomFactor: {
1355 | type: "number"
1356 | },
1357 | zoomedOut: {
1358 | type: "boolean"
1359 | }
1360 | },
1361 | SplitView: {
1362 | closedDisplayMode: {
1363 | type: "enum",
1364 | values: [
1365 | "inline",
1366 | "none"
1367 | ]
1368 | },
1369 | contentElement: {
1370 | name: "HTMLElement",
1371 | type: "reference",
1372 | typeArguments: []
1373 | },
1374 | element: {
1375 | name: "HTMLElement",
1376 | type: "reference",
1377 | typeArguments: []
1378 | },
1379 | onAfterClose: {
1380 | name: "Function",
1381 | type: "reference",
1382 | typeArguments: []
1383 | },
1384 | onAfterOpen: {
1385 | name: "Function",
1386 | type: "reference",
1387 | typeArguments: []
1388 | },
1389 | onBeforeClose: {
1390 | name: "Function",
1391 | type: "reference",
1392 | typeArguments: []
1393 | },
1394 | onBeforeOpen: {
1395 | name: "Function",
1396 | type: "reference",
1397 | typeArguments: []
1398 | },
1399 | openedDisplayMode: {
1400 | type: "enum",
1401 | values: [
1402 | "inline",
1403 | "overlay"
1404 | ]
1405 | },
1406 | paneElement: {
1407 | name: "HTMLElement",
1408 | type: "reference",
1409 | typeArguments: []
1410 | },
1411 | paneOpened: {
1412 | type: "boolean"
1413 | },
1414 | panePlacement: {
1415 | type: "enum",
1416 | values: [
1417 | "bottom",
1418 | "left",
1419 | "right",
1420 | "top"
1421 | ]
1422 | }
1423 | },
1424 | SplitViewCommand: {
1425 | element: {
1426 | name: "HTMLElement",
1427 | type: "reference",
1428 | typeArguments: []
1429 | },
1430 | icon: {
1431 | type: "string"
1432 | },
1433 | label: {
1434 | type: "string"
1435 | },
1436 | onInvoked: {
1437 | name: "Function",
1438 | type: "reference",
1439 | typeArguments: []
1440 | },
1441 | tooltip: {
1442 | type: "string"
1443 | }
1444 | },
1445 | SplitViewPaneToggle: {
1446 | element: {
1447 | name: "HTMLButtonElement",
1448 | type: "reference",
1449 | typeArguments: []
1450 | },
1451 | onInvoked: {
1452 | name: "Function",
1453 | type: "reference",
1454 | typeArguments: []
1455 | },
1456 | splitView: {
1457 | name: "HTMLElement",
1458 | type: "reference",
1459 | typeArguments: []
1460 | }
1461 | },
1462 | TimePicker: {
1463 | clock: {
1464 | type: "string"
1465 | },
1466 | current: {
1467 | name: "Date",
1468 | type: "reference",
1469 | typeArguments: []
1470 | },
1471 | disabled: {
1472 | type: "boolean"
1473 | },
1474 | element: {
1475 | name: "HTMLElement",
1476 | type: "reference",
1477 | typeArguments: []
1478 | },
1479 | hourPattern: {
1480 | type: "string"
1481 | },
1482 | minuteIncrement: {
1483 | type: "number"
1484 | },
1485 | minutePattern: {
1486 | type: "string"
1487 | },
1488 | onChange: {
1489 | name: "Function",
1490 | type: "reference",
1491 | typeArguments: []
1492 | },
1493 | periodPattern: {
1494 | type: "string"
1495 | }
1496 | },
1497 | ToggleSwitch: {
1498 | checked: {
1499 | type: "boolean"
1500 | },
1501 | disabled: {
1502 | type: "boolean"
1503 | },
1504 | element: {
1505 | name: "HTMLElement",
1506 | type: "reference",
1507 | typeArguments: []
1508 | },
1509 | labelOff: {
1510 | type: "string"
1511 | },
1512 | labelOn: {
1513 | type: "string"
1514 | },
1515 | onChange: {
1516 | name: "Function",
1517 | type: "reference",
1518 | typeArguments: []
1519 | },
1520 | title: {
1521 | type: "string"
1522 | }
1523 | },
1524 | ToolBar: {
1525 | closedDisplayMode: {
1526 | type: "enum",
1527 | values: [
1528 | "compact",
1529 | "full"
1530 | ]
1531 | },
1532 | data: {
1533 | name: "WinJS.Binding.List",
1534 | type: "reference",
1535 | typeArguments: [
1536 | {
1537 | name: "WinJS.UI.ICommand",
1538 | type: "reference",
1539 | typeArguments: []
1540 | }
1541 | ]
1542 | },
1543 | element: {
1544 | name: "HTMLElement",
1545 | type: "reference",
1546 | typeArguments: []
1547 | },
1548 | onAfterClose: {
1549 | name: "Function",
1550 | type: "reference",
1551 | typeArguments: []
1552 | },
1553 | onAfterOpen: {
1554 | name: "Function",
1555 | type: "reference",
1556 | typeArguments: []
1557 | },
1558 | onBeforeClose: {
1559 | name: "Function",
1560 | type: "reference",
1561 | typeArguments: []
1562 | },
1563 | onBeforeOpen: {
1564 | name: "Function",
1565 | type: "reference",
1566 | typeArguments: []
1567 | },
1568 | opened: {
1569 | type: "boolean"
1570 | }
1571 | },
1572 | Tooltip: {
1573 | contentElement: {
1574 | name: "HTMLElement",
1575 | type: "reference",
1576 | typeArguments: []
1577 | },
1578 | element: {
1579 | name: "HTMLElement",
1580 | type: "reference",
1581 | typeArguments: []
1582 | },
1583 | extraClass: {
1584 | type: "string"
1585 | },
1586 | infotip: {
1587 | type: "boolean"
1588 | },
1589 | innerHTML: {
1590 | type: "string"
1591 | },
1592 | onBeforeClose: {
1593 | name: "Function",
1594 | type: "reference",
1595 | typeArguments: []
1596 | },
1597 | onBeforeOpen: {
1598 | name: "Function",
1599 | type: "reference",
1600 | typeArguments: []
1601 | },
1602 | onClosed: {
1603 | name: "Function",
1604 | type: "reference",
1605 | typeArguments: []
1606 | },
1607 | onOpened: {
1608 | name: "Function",
1609 | type: "reference",
1610 | typeArguments: []
1611 | },
1612 | placement: {
1613 | type: "string"
1614 | }
1615 | }
1616 | };
1617 |
1618 | var setImmediate;
1619 | var clearImmediate;
1620 | if (window.setImmediate && window.clearImmediate) {
1621 | setImmediate = window.setImmediate;
1622 | clearImmediate = window.clearImmediate;
1623 | } else {
1624 | setImmediate = function (callback) {
1625 | return setTimeout(callback, 0);
1626 | };
1627 | clearImmediate = window.clearTimeout;
1628 | }
1629 |
1630 | function isEvent(propName) {
1631 | return propName[0] === "o" && propName[1] === "n";
1632 | }
1633 |
1634 | function mapObject(obj, callback) {
1635 | var result = {};
1636 | Object.keys(obj).forEach(function (key) {
1637 | var value = callback(key, obj[key]);
1638 | if (value !== undefined) {
1639 | result[key] = value;
1640 | }
1641 | });
1642 | return result;
1643 | }
1644 |
1645 | function cloneObject(obj) {
1646 | var result = {};
1647 | for (var k in obj) { result[k] = obj[k]; }
1648 | return result;
1649 | }
1650 |
1651 | function merge(/* objs */) {
1652 | var result = {};
1653 | for (var i = 0, len = arguments.length; i < len; i++) {
1654 | var obj = arguments[i];
1655 | if (obj) {
1656 | for (var k in obj) { result[k] = obj[k]; }
1657 | }
1658 | }
1659 | return result;
1660 | }
1661 |
1662 | function endsWith(s, suffix) {
1663 | return s.length >= suffix.length && s.substr(-suffix.length) === suffix;
1664 | }
1665 |
1666 | function arraysShallowEqual(a, b) {
1667 | if (a === b) {
1668 | return true;
1669 | } else if (a.length !== b.length) {
1670 | return false;
1671 | } else {
1672 | for (var i = 0, len = a.length; i < len; i++) {
1673 | if (a[i] !== b[i]) {
1674 | return false;
1675 | }
1676 | }
1677 | return true;
1678 | }
1679 | }
1680 |
1681 | function nestedSet(obj, path, value) {
1682 | var parts = path.split(".");
1683 | var allButLast = parts.slice(0, parts.length - 1);
1684 | var last = parts[parts.length - 1];
1685 | var finalObj = allButLast.reduce(function (current, key) {
1686 | return current[key];
1687 | }, obj);
1688 | finalObj[last] = value;
1689 | }
1690 |
1691 | function deparent(element) {
1692 | var parent = element.parentNode;
1693 | parent && parent.removeChild(element);
1694 | }
1695 |
1696 | function fireEvent(element, eventName) {
1697 | var eventObject = document.createEvent("CustomEvent");
1698 | eventObject.initCustomEvent(
1699 | eventName,
1700 | true, // bubbles
1701 | false, // cancelable
1702 | null // detail
1703 | );
1704 | element.dispatchEvent(eventObject);
1705 | }
1706 |
1707 | function makeClassSet(className) {
1708 | var classSet = {};
1709 | className && className.split(" ").forEach(function (aClass) {
1710 | if (aClass) {
1711 | classSet[aClass] = true;
1712 | }
1713 | });
1714 | return classSet;
1715 | }
1716 |
1717 | function getIn(object, path) {
1718 | var parts = path.split(".");
1719 | return parts.reduce(function (current, name) {
1720 | return current && current[name];
1721 | }, object);
1722 | }
1723 |
1724 | // Given a type from RawControlApis returns a React propType.
1725 | function typeToPropType(typeInfo) {
1726 | if (typeInfo.type === "string") {
1727 | return React.PropTypes.string;
1728 | } else if (typeInfo.type === "boolean") {
1729 | return React.PropTypes.bool;
1730 | } else if (typeInfo.type === "number") {
1731 | return React.PropTypes.number;
1732 | } else if (typeInfo.type === "enum") {
1733 | return React.PropTypes.oneOf(typeInfo.values);
1734 | } else if (typeInfo.type === "any") {
1735 | return React.PropTypes.any;
1736 | } else if (typeInfo.type === "reference") {
1737 | if (typeInfo.name === "Function") {
1738 | return React.PropTypes.func;
1739 | } else if (typeInfo.name === "Array") {
1740 | var itemPropType = typeToPropType(typeInfo.typeArguments[0]);
1741 | return itemPropType ? React.PropTypes.arrayOf(itemPropType) : React.PropTypes.array;
1742 | } else if (getIn(window, typeInfo.name)) {
1743 | var instance = getIn(window, typeInfo.name);
1744 | return React.PropTypes.instanceOf(instance);
1745 | }
1746 | } else {
1747 | console.warn("react-winjs typeToPropType: unable to find propType for type: " + JSON.stringify(typeInfo, null, 2));
1748 | }
1749 | }
1750 |
1751 | // TODO: Revisit all of this diffing stuff:
1752 | // - Make it more efficient
1753 | // - It's currently hard to understand because it makes aggressive
1754 | // assumptions (e.g. each item has a key and each item has a winControl)
1755 | // - Is it correct?
1756 | // - Should we just sync an array with a binding list instead of computing
1757 | // edits based on 2 arrays and then applying them to a binding list?
1758 | function buildIndex(array) {
1759 | var index = {};
1760 | array.forEach(function (item, i) {
1761 | index[item.key] = i;
1762 | });
1763 | return index;
1764 | }
1765 | function indexOfKey(array, key) {
1766 | for (var i = 0; i < array.length; i++) {
1767 | if (array[i].key === key) {
1768 | return i;
1769 | }
1770 | }
1771 | return -1;
1772 | }
1773 | function diffArraysByKey(old, latest) {
1774 | old = old.slice(0);
1775 | var oldIndex = buildIndex(old);
1776 | var latestIndex = buildIndex(latest);
1777 | var edits = [];
1778 |
1779 | // Handle removals
1780 | for (var i = old.length - 1; i >= 0; i--) {
1781 | var item = old[i];
1782 | if (!latestIndex.hasOwnProperty(item.key)) {
1783 | edits.push({ type: "delete", index: i });
1784 | old.splice(i, 1);
1785 | }
1786 | }
1787 |
1788 | // Handle insertions and moves
1789 | for (var i = 0; i < latest.length; i++) {
1790 | var item = latest[i];
1791 | if (!oldIndex.hasOwnProperty(item.key)) {
1792 | // Insertion
1793 | edits.push({ type: "insert", index: i, value: item });
1794 | old.splice(i, 0, item);
1795 | } else if (old[i].key !== item.key) {
1796 | // Move
1797 | //edits.push({ type: "move", from: oldIndex[item.key], to: i });
1798 | //old.splice(oldIndex[item.key], 1);
1799 |
1800 | var fromIndex = indexOfKey(old, item.key);
1801 | edits.push({ type: "move", from: fromIndex, to: i });
1802 | old.splice(fromIndex, 1);
1803 | old.splice(i, 0, item);
1804 | }
1805 | }
1806 |
1807 | return edits;
1808 | }
1809 | function applyEditsToBindingList(list, edits) {
1810 | edits.forEach(function (edit) {
1811 | if (edit.type === "delete") {
1812 | list.splice(edit.index, 1);
1813 | } else if (edit.type === "insert") {
1814 | list.splice(edit.index, 0, edit.value.winControl);
1815 | } else if (edit.type === "move") {
1816 | list.move(edit.from, edit.to);
1817 | } else {
1818 | throw "Unsupported edit type: " + edit.type;
1819 | }
1820 | }, this);
1821 | }
1822 |
1823 | // interface IWinJSComponent {
1824 | // winControl
1825 | // element
1826 | // data
1827 | // displayName
1828 | // }
1829 |
1830 | // interface IWinJSChildComponent extends IWinJSComponent {
1831 | // key
1832 | // type
1833 | // }
1834 |
1835 | // Returns a WinJSChildComponent for each component in *children*. Reuses
1836 | // WinJSChildComponents from *childComponentsMap* when possible. Disposes members of
1837 | // *childComponentsMap* if they are no longer needed.
1838 | function processChildren(componentDisplayName, children, childComponentsMap) {
1839 | var newChildComponents = [];
1840 | var newChildComponentsMap = {};
1841 |
1842 | // A component's *key* represents its identity. If a component in *children* and a
1843 | // component in *childComponentsMap* have the same *key*, then they are assumed to
1844 | // represent the same component.
1845 |
1846 | React.Children.forEach(children, function (component) {
1847 | if (component) {
1848 | if (component.ref) {
1849 | console.warn(
1850 | "ref prop (" + component.ref + ") will not work on " +
1851 | component.type.displayName + " component because it is inside " +
1852 | "of a " + componentDisplayName + " component"
1853 | );
1854 | }
1855 |
1856 | if (component.key === null) {
1857 | console.error(
1858 | component.type.displayName + " component requires a key " +
1859 | "when inside of a " + componentDisplayName + " component"
1860 | );
1861 | } else {
1862 | var winjsChildComponent = childComponentsMap[component.key];
1863 | if (winjsChildComponent) {
1864 | if (winjsChildComponent.type === component.type) {
1865 | winjsChildComponent.update(component);
1866 | } else {
1867 | // If a component's *type* has changed then the component must be
1868 | // recreated from scratch rather than updated. The reason is that
1869 | // the tagName of the underlying DOM element may have changed. The
1870 | // only way to change the tagName of the underlying DOM element is
1871 | // to instantiate a new react-winjs component.
1872 | winjsChildComponent.dispose();
1873 | winjsChildComponent = new WinJSChildComponent(component);
1874 | }
1875 | } else {
1876 | winjsChildComponent = new WinJSChildComponent(component);
1877 | }
1878 | newChildComponents.push(winjsChildComponent);
1879 | newChildComponentsMap[component.key] = winjsChildComponent;
1880 | }
1881 | }
1882 | });
1883 |
1884 | Object.keys(childComponentsMap).forEach(function (key) {
1885 | if (!newChildComponentsMap.hasOwnProperty(key)) {
1886 | childComponentsMap[key].dispose();
1887 | }
1888 | });
1889 |
1890 | return {
1891 | childComponents: newChildComponents,
1892 | childComponentsMap: newChildComponentsMap
1893 | };
1894 | }
1895 |
1896 | function prefixedProperty(prefix, property) {
1897 | return prefix + property[0].toUpperCase() + property.substr(1);
1898 | }
1899 |
1900 | var isUnitlessProperty = {
1901 | flex: true,
1902 | flexGrow: true,
1903 | flexPositive: true,
1904 | flexShrink: true,
1905 | flexNegative: true,
1906 | fontWeight: true,
1907 | lineClamp: true,
1908 | lineHeight: true,
1909 | opacity: true,
1910 | order: true,
1911 | orphans: true,
1912 | widows: true,
1913 | zIndex: true,
1914 | zoom: true
1915 | };
1916 | var vendorPrefixes = ["Moz", "ms", "Webkit"];
1917 | Object.keys(isUnitlessProperty).forEach(function (property) {
1918 | vendorPrefixes.forEach(function (prefix) {
1919 | isUnitlessProperty[prefixedProperty(prefix, property)] = true;
1920 | });
1921 | });
1922 |
1923 | // Converts the value of a CSS attribute to a string. When certain attributes
1924 | // (e.g. width, height) are specified as numbers, this means adding "px" to the
1925 | // end of the string value.
1926 | function resolveStyleValue(cssProperty, value) {
1927 | if (typeof value === "number") {
1928 | return isUnitlessProperty[cssProperty] || value === 0 ?
1929 | ("" + value) :
1930 | (value + "px");
1931 | } else {
1932 | return value ? ("" + value) : "";
1933 | }
1934 | }
1935 |
1936 | var PropHandlers = {
1937 | // Maps to a property on the winControl.
1938 | property: function (propType) {
1939 | return {
1940 | propType: propType,
1941 | preCtorInit: function property_preCtorInit(element, options, data, displayName, propName, value) {
1942 | options[propName] = value;
1943 | },
1944 | update: function property_update(winjsComponent, propName, oldValue, newValue) {
1945 | if (oldValue !== newValue) {
1946 | winjsComponent.winControl[propName] = newValue;
1947 | }
1948 | }
1949 | };
1950 | },
1951 |
1952 | // Maps to a property on the winControl which involves setting focus. Such properties
1953 | // are set outside of componentWillReceiveProps to prevent React from undoing the
1954 | // focus move.
1955 | focusProperty: function (propType) {
1956 | return {
1957 | propType: propType,
1958 | preCtorInit: function focusProperty_preCtorInit(element, options, data, displayName, propName, value) {
1959 | options[propName] = value;
1960 | },
1961 | update: function focusProperty_update(winjsComponent, propName, oldValue, newValue) {
1962 | if (oldValue !== newValue) {
1963 | var asyncToken = winjsComponent.data[propName];
1964 | asyncToken && clearImmediate(asyncToken);
1965 | asyncToken = setImmediate(function () {
1966 | winjsComponent.data[propName] = null;
1967 | winjsComponent.winControl[propName] = newValue;
1968 | });
1969 | }
1970 | },
1971 | dispose: function focusProperty_dispose(winjsComponent, propName) {
1972 | var asyncToken = winjsComponent.data[propName];
1973 | asyncToken && clearImmediate(asyncToken);
1974 | }
1975 | };
1976 | },
1977 |
1978 | // Maps to a property on the winControl's element.
1979 | domProperty: function (propType) {
1980 | return {
1981 | propType: propType,
1982 | preCtorInit: function domProperty_preCtorInit(element, options, data, displayName, propName, value) {
1983 | element[propName] = value;
1984 | },
1985 | update: function domProperty_update(winjsComponent, propName, oldValue, newValue) {
1986 | if (oldValue !== newValue) {
1987 | winjsComponent.element[propName] = newValue;
1988 | }
1989 | }
1990 | };
1991 | },
1992 |
1993 | // Maps to an attribute on the winControl's element.
1994 | domAttribute: function (propType) {
1995 | return {
1996 | propType: propType,
1997 | update: function domAttribute_update(winjsComponent, propName, oldValue, newValue) {
1998 | if (oldValue !== newValue) {
1999 | if (newValue !== null && newValue !== undefined) {
2000 | winjsComponent.element.setAttribute(propName, "" + newValue);
2001 | } else {
2002 | winjsComponent.element.removeAttribute(propName);
2003 | }
2004 | }
2005 | }
2006 | };
2007 | },
2008 |
2009 | // Maps to an event on the winControl.
2010 | event: {
2011 | propType: React.PropTypes.func,
2012 | // Can't set options in preCtorInit for events. The problem is WinJS control options
2013 | // use a different code path to hook up events than the event property setters.
2014 | // Consequently, setting an event property will not automatically unhook the event
2015 | // listener that was specified in the options during initialization. To avoid this
2016 | // problem, always go thru the event property setters.
2017 | update: function event_update(winjsComponent, propName, oldValue, newValue) {
2018 | if (oldValue !== newValue) {
2019 | winjsComponent.winControl[propName.toLowerCase()] = newValue;
2020 | }
2021 | }
2022 | },
2023 |
2024 | // Maps to an event on the winControl's element.
2025 | domEvent: {
2026 | propType: React.PropTypes.func,
2027 | preCtorInit: function domEvent_preCtorInit(element, options, data, displayName, propName, value) {
2028 | element[propName.toLowerCase()] = value;
2029 | },
2030 | update: function domEvent_update(winjsComponent, propName, oldValue, newValue) {
2031 | if (oldValue !== newValue) {
2032 | winjsComponent.element[propName.toLowerCase()] = newValue;
2033 | }
2034 | }
2035 | },
2036 |
2037 | // Enable the addition and removal of CSS classes on the root of the winControl
2038 | // but don't clobber whatever CSS classes the underlying control may have added
2039 | // (e.g. don't clobber win-listview).
2040 | winControlClassName: {
2041 | propType: React.PropTypes.string,
2042 | preCtorInit: function winControlClassName_preCtorInit(element, options, data, displayName, propName, value) {
2043 | if (value) {
2044 | element.className = value;
2045 | }
2046 | data[propName] = makeClassSet(value);
2047 | },
2048 | update: function winControlClassName_update(winjsComponent, propName, oldValue, newValue) {
2049 | if (oldValue !== newValue) {
2050 | var oldClassSet = winjsComponent.data[propName] || {};
2051 | var newClassSet = makeClassSet(newValue);
2052 | var elementClassList = winjsComponent.winControl.element.classList;
2053 | for (var className in oldClassSet) {
2054 | if (!newClassSet[className]) {
2055 | elementClassList.remove(className);
2056 | }
2057 | }
2058 | for (var className in newClassSet) {
2059 | if (!oldClassSet[className]) {
2060 | elementClassList.add(className);
2061 | }
2062 | }
2063 | winjsComponent.data[propName] = newClassSet;
2064 | }
2065 | }
2066 | },
2067 |
2068 | // Enable the addition and removal of inline styles on the root of the winControl
2069 | // but don't clobber whatever inline styles the underlying control may have added.
2070 | winControlStyle: {
2071 | propType: React.PropTypes.object,
2072 | preCtorInit: function winControlStyle_preCtorInit(element, options, data, displayName, propName, value) {
2073 | var elementStyle = element.style;
2074 | value = value || {};
2075 | for (var cssProperty in value) {
2076 | elementStyle[cssProperty] = resolveStyleValue(cssProperty, value[cssProperty]);
2077 | }
2078 | },
2079 | update: function winControlStyle_update(winjsComponent, propName, oldValue, newValue) {
2080 | if (oldValue !== newValue) {
2081 | oldValue = oldValue || {};
2082 | newValue = newValue || {};
2083 | if(winjsComponent.winControl && winjsComponent.winControl.element) {
2084 | var elementStyle = winjsComponent.winControl.element.style;
2085 | for (var cssProperty in oldValue) {
2086 | if (!newValue.hasOwnProperty(cssProperty)) {
2087 | elementStyle[cssProperty] = "";
2088 | }
2089 | }
2090 | for (var cssProperty in newValue) {
2091 | if (oldValue[cssProperty] !== newValue[cssProperty]) {
2092 | elementStyle[cssProperty] = resolveStyleValue(cssProperty, newValue[cssProperty]);
2093 | }
2094 | }
2095 | }
2096 | }
2097 | }
2098 | },
2099 |
2100 | // Emits a warning to the console whenever prop gets used.
2101 | warn: function PropHandlers_warn(warnMessage) {
2102 | return {
2103 | // Don't need preCtorInit because this prop handler doesn't have any side
2104 | // effects on the WinJS control. update also runs during initialization so
2105 | // update is just as good as preCtorInit for our use case.
2106 | update: function warn_update(winjsComponent, propName, oldValue, newValue) {
2107 | console.warn(winjsComponent.displayName + ": " + warnMessage);
2108 | }
2109 | };
2110 | },
2111 |
2112 | // Creates a DOM element and mounts a React component on it. Gives this DOM
2113 | // element to the *winControlProperty* property of the winControl.
2114 | propertyWithMount: function PropHandlers_propertyWithMount(winControlProperty) {
2115 | return {
2116 | propType: React.PropTypes.element,
2117 | preCtorInit: function propertyWithMount_preCtorInit(element, options, data, displayName, propName, value) {
2118 | if (value) {
2119 | data[propName] = document.createElement("div");
2120 | ReactDOM.render(value, data[propName]);
2121 | options[winControlProperty] = data[propName];
2122 | }
2123 | },
2124 | update: function propertyWithMount_update(winjsComponent, propName, oldValue, newValue) {
2125 | var winControl = winjsComponent.winControl;
2126 | var element = winjsComponent.data[propName];
2127 | if (newValue) {
2128 | if (!element) {
2129 | element = document.createElement("div");
2130 | winjsComponent.data[propName] = element;
2131 | }
2132 | ReactDOM.render(newValue, element);
2133 | if (winControl[winControlProperty] !== element) {
2134 | winControl[winControlProperty] = element;
2135 | }
2136 | } else if (oldValue) {
2137 | element && ReactDOM.unmountComponentAtNode(element);
2138 | winControl[winControlProperty] = null;
2139 | }
2140 | },
2141 | dispose: function propertyWithMount_dispose(winjsComponent, propName) {
2142 | var element = winjsComponent.data[propName];
2143 | element && ReactDOM.unmountComponentAtNode(element);
2144 | }
2145 | };
2146 | },
2147 |
2148 |
2149 | // Mounts a React component on whatever element gets returned by getMountPoint.
2150 | mountTo: function PropHandlers_mountTo(getMountPoint) {
2151 | return {
2152 | propType: React.PropTypes.element,
2153 | // Can't use preCtorInit because the mount point may not exist until the
2154 | // constructor has run.
2155 | update: function mountTo_update(winjsComponent, propName, oldValue, newValue) {
2156 | var data = winjsComponent.data[propName] || {};
2157 | var version = (data.version || 0) + 1;
2158 | winjsComponent.data[propName] = {
2159 | // *mountComponent* may run asynchronously and we may queue it multiple
2160 | // times before it runs. *version* allows us to ensure only the latest
2161 | // version runs and the others are no ops.
2162 | version: version,
2163 | // *element* is the element to which we last mounted the component.
2164 | element: data.element
2165 | };
2166 |
2167 | var mountComponent = function () {
2168 | if (version === winjsComponent.data[propName].version) {
2169 | var oldElement = winjsComponent.data[propName].element;
2170 |
2171 | if (newValue) {
2172 | var newElement = getMountPoint(winjsComponent);
2173 | if (oldElement && oldElement !== newElement) {
2174 | ReactDOM.unmountComponentAtNode(oldElement);
2175 | }
2176 |
2177 | ReactDOM.render(newValue, newElement);
2178 | winjsComponent.data[propName].element = newElement;
2179 | } else if (oldValue) {
2180 | oldElement && ReactDOM.unmountComponentAtNode(oldElement);
2181 | winjsComponent.data[propName].element = null;
2182 | }
2183 | }
2184 | };
2185 |
2186 | // *isDeclarativeControlContainer* is a hook some WinJS controls provide
2187 | // (e.g. HubSection, PivotItem) to ensure that processing runs on the
2188 | // control only when the control is ready for it. This enables lazy loading
2189 | // of HubSections/PivotItems (e.g. load off screen items asynchronously in
2190 | // batches). Additionally, doing processing thru this hook guarantees that
2191 | // the processing won't run until the control is in the DOM.
2192 | var winControl = winjsComponent.winControl;
2193 | var queueProcessing = winControl.constructor.isDeclarativeControlContainer;
2194 | if (queueProcessing && typeof queueProcessing === "function") {
2195 | queueProcessing(winControl, mountComponent);
2196 | } else {
2197 | mountComponent();
2198 | }
2199 | },
2200 | dispose: function mountTo_dispose(winjsComponent, propName) {
2201 | var data = winjsComponent.data[propName] || {};
2202 | var element = data.element;
2203 | element && ReactDOM.unmountComponentAtNode(element);
2204 | }
2205 | };
2206 | },
2207 |
2208 | // Uses the Binding.List's editing APIs to make it match the children prop. Does this to
2209 | // the Binding.List stored in the winControl's property called bindingListName.
2210 | syncChildrenWithBindingList: function PropHandlers_syncChildrenWithBindingList(bindingListName) {
2211 | return {
2212 | preCtorInit: function syncChildrenWithBindingList_preCtorInit(element, options, data, displayName, propName, value) {
2213 | var latest = processChildren(displayName, value, {});
2214 | data[propName] = {
2215 | winjsChildComponents: latest.childComponents,
2216 | winjsChildComponentsMap: latest.childComponentsMap
2217 | };
2218 |
2219 | options[bindingListName] = new WinJS.Binding.List(
2220 | latest.childComponents.map(function (winjsChildComponent) {
2221 | return winjsChildComponent.winControl;
2222 | })
2223 | );
2224 | },
2225 | update: function syncChildrenWithBindingList_update(winjsComponent, propName, oldValue, newValue) {
2226 | var data = winjsComponent.data[propName] || {};
2227 | var oldChildComponents = data.winjsChildComponents || [];
2228 | var oldChildComponentsMap = data.winjsChildComponentsMap || {};
2229 | var latest = processChildren(winjsComponent.displayName, newValue, oldChildComponentsMap);
2230 |
2231 | var bindingList = winjsComponent.winControl[bindingListName];
2232 | if (bindingList) {
2233 | applyEditsToBindingList(
2234 | bindingList,
2235 | diffArraysByKey(oldChildComponents, latest.childComponents)
2236 | );
2237 | } else {
2238 | winjsComponent.winControl[bindingListName] = new WinJS.Binding.List(latest.childComponents.map(function (winjsChildComponent) {
2239 | return winjsChildComponent.winControl;
2240 | }));
2241 | }
2242 |
2243 | winjsComponent.data[propName] = {
2244 | winjsChildComponents: latest.childComponents,
2245 | winjsChildComponentsMap: latest.childComponentsMap
2246 | };
2247 | },
2248 | dispose: function syncChildrenWithBindingList_dispose(winjsComponent, propName) {
2249 | var data = winjsComponent.data[propName] || {};
2250 | var childComponents = data.winjsChildComponents || [];
2251 | childComponents.forEach(function (winjsChildComponent) {
2252 | winjsChildComponent.dispose();
2253 | });
2254 | }
2255 | }
2256 | }
2257 | };
2258 |
2259 | function defineControl(options) {
2260 | // Required
2261 | var winjsControl = options.winjsControl;
2262 |
2263 | // Optional
2264 | var winControlOptions = options.winControlOptions || {};
2265 | var preCtorInit = options.preCtorInit || function () { };
2266 | var propHandlers = options.propHandlers || {};
2267 | var render = options.render || function (component) {
2268 | return React.DOM.div();
2269 | };
2270 | var displayName = options.displayName;
2271 |
2272 | function initWinJSComponent(winjsComponent, element, props) {
2273 | winjsComponent.data = {};
2274 | winjsComponent.displayName = displayName;
2275 | winjsComponent.element = element;
2276 |
2277 | // Give propHandlers that implement preCtorInit the opportunity to run before
2278 | // instantiating the winControl.
2279 | var options = cloneObject(winControlOptions);
2280 | preCtorInit(element, options, winjsComponent.data, displayName);
2281 | Object.keys(props).forEach(function (propName) {
2282 | var handler = propHandlers[propName];
2283 | if (handler && handler.preCtorInit) {
2284 | handler.preCtorInit(element, options, winjsComponent.data, displayName, propName, props[propName]);
2285 | }
2286 | });
2287 | winjsComponent.winControl = new winjsControl(element, options);
2288 |
2289 | // Process propHandlers that don't implement preCtorInit.
2290 | Object.keys(props).forEach(function (propName) {
2291 | var handler = propHandlers[propName];
2292 | if (handler && !handler.preCtorInit) {
2293 | handler.update(winjsComponent, propName, undefined, props[propName]);
2294 | }
2295 | });
2296 | }
2297 |
2298 | function updateWinJSComponent(winjsComponent, prevProps, nextProps) {
2299 | // Handle props that were added or changed
2300 | Object.keys(nextProps).forEach(function (propName) {
2301 | var handler = propHandlers[propName];
2302 | if (handler) {
2303 | handler.update(winjsComponent, propName, prevProps[propName], nextProps[propName]);
2304 | }
2305 | });
2306 |
2307 | // Handle props that were removed
2308 | Object.keys(prevProps).forEach(function (propName) {
2309 | if (!nextProps.hasOwnProperty(propName)) {
2310 | var handler = propHandlers[propName];
2311 | if (handler) {
2312 | handler.update(winjsComponent, propName, prevProps[propName], undefined);
2313 | }
2314 | }
2315 | });
2316 | }
2317 |
2318 | function disposeWinJSComponent(winjsComponent) {
2319 | winjsComponent.winControl.dispose && winjsComponent.winControl.dispose();
2320 | Object.keys(propHandlers).forEach(function (propName) {
2321 | var handler = propHandlers[propName];
2322 | handler.dispose && handler.dispose(winjsComponent, propName);
2323 | })
2324 | }
2325 |
2326 | return React.createClass({
2327 | displayName: displayName,
2328 | statics: {
2329 | initWinJSComponent: initWinJSComponent,
2330 | updateWinJSComponent: updateWinJSComponent,
2331 | disposeWinJSComponent: disposeWinJSComponent
2332 | },
2333 | propTypes: mapObject(propHandlers, function (propName, propHandler) {
2334 | return propHandler.propType;
2335 | }),
2336 | shouldComponentUpdate: function () {
2337 | return false;
2338 | },
2339 | // If choosing to implement componentWillMount, be aware that componentWillMount
2340 | // will run when WinJSChildComponent renders the component to a string via
2341 | // renderRootlessComponent.
2342 | componentDidMount: function () {
2343 | initWinJSComponent(this, ReactDOM.findDOMNode(this), this.props);
2344 | },
2345 | componentWillUnmount: function () {
2346 | disposeWinJSComponent(this);
2347 | },
2348 | componentWillReceiveProps: function (nextProps) {
2349 | updateWinJSComponent(this, this.props, nextProps);
2350 | },
2351 | render: function() {
2352 | return render(this);
2353 | }
2354 | });
2355 | }
2356 |
2357 | var hostEl = document.createElement("div");
2358 | function renderRootlessComponent(component) {
2359 | var html = ReactDOMServer.renderToStaticMarkup(component);
2360 | hostEl.innerHTML = html;
2361 | var element = hostEl.firstElementChild;
2362 | hostEl.removeChild(element);
2363 | return element;
2364 | }
2365 |
2366 | // TODO: Is there a better way to solve this problem that WinJSChildComponent solves?
2367 | // TODO: Because we're not going thru React's lifecycle, we're missing out on
2368 | // validation of propTypes.
2369 | // TODO: ref doesn't work on WinJSChildComponents. The reason is that during updates, we
2370 | // don't call ReactDOM.render. Because of this, refs would go stale and only reflect the
2371 | // state of the component after its first render. Consequently, we clone the component
2372 | // during its first render so it never shows up in refs. This should make it clearer
2373 | // that refs don't work than generating stale refs.
2374 | function WinJSChildComponent(component) { // implements IWinJSChildComponent
2375 | // Clone the component so a ref isn't generated.
2376 | var clonedComponent = React.cloneElement(component, { ref: null });
2377 | var element = renderRootlessComponent(clonedComponent);
2378 | component.type.initWinJSComponent(this, element, component.props);
2379 | this.key = component.key;
2380 | this.type = component.type;
2381 | this._props = component.props;
2382 | this._disposeWinJSComponent = component.type.disposeWinJSComponent;
2383 | };
2384 | WinJSChildComponent.prototype.update = function (component) {
2385 | component.type.updateWinJSComponent(this, this._props, component.props);
2386 | this._props = component.props;
2387 | };
2388 | WinJSChildComponent.prototype.dispose = function () {
2389 | this._disposeWinJSComponent(this);
2390 | };
2391 |
2392 |
2393 | // Prop handlers that are common to every WinJS control.
2394 | var defaultPropHandlers = {
2395 | className: PropHandlers.winControlClassName,
2396 | style: PropHandlers.winControlStyle,
2397 |
2398 | // TODO: Instead of special casing these, support DOM attributes
2399 | // more generically.
2400 | id: PropHandlers.domProperty(React.PropTypes.string),
2401 | "aria-controls": PropHandlers.domAttribute(React.PropTypes.any),
2402 | "aria-expanded": PropHandlers.domAttribute(React.PropTypes.any)
2403 | };
2404 |
2405 | // Control-specific prop handlers derived from RawControlApis
2406 | var DefaultControlPropHandlers = (function processRawApis() {
2407 | var keepProperty = function keepProperty(propertyName) {
2408 | return !endsWith(propertyName.toLowerCase(), "element");
2409 | };
2410 |
2411 | return mapObject(RawControlApis, function (controlName, controlApis) {
2412 | var propHandlers = {};
2413 | Object.keys(controlApis).forEach(function (propName) {
2414 | if (isEvent(propName)) {
2415 | propHandlers[propName] = PropHandlers.event;
2416 | } else if (keepProperty(propName)) {
2417 | var typeInfo = controlApis[propName];
2418 | var propType = typeToPropType(typeInfo);
2419 | propHandlers[propName] = PropHandlers.property(propType);
2420 | }
2421 | });
2422 | return propHandlers;
2423 | });
2424 | })();
2425 |
2426 | // Each entry in controlApis has the same format as the argument to defineControl except
2427 | // updateWithDefaults automatically provides:
2428 | // - winjsControl
2429 | // - displayName
2430 | // - propHandlers
2431 | // and updateWithDefaults implements an extra option:
2432 | // - underlyingControlName
2433 | // By default, winjsControl, displayName, and propHanders are inferred from the entry's key
2434 | // in controlApis. If underlyingControlName is provided, they will instead be inferred from
2435 | // that name.
2436 | function updateWithDefaults(controlApis) {
2437 | Object.keys(controlApis).forEach(function (controlName) {
2438 | var spec = controlApis[controlName];
2439 | var winjsControlName = spec.underlyingControlName || controlName;
2440 | spec.winjsControl = spec.winjsControl || WinJS.UI[winjsControlName];
2441 | spec.displayName = spec.displayName || winjsControlName;
2442 | spec.propHandlers = merge(
2443 | defaultPropHandlers, // Common to all WinJS controls
2444 | DefaultControlPropHandlers[winjsControlName], // Control-specific derived from RawControlApis
2445 | spec.propHandlers // Control-specific handwritten
2446 | );
2447 | });
2448 | return controlApis;
2449 | }
2450 |
2451 | var typeWarnPropHandler = PropHandlers.warn("Invalid prop 'type'. Instead, the command type is" +
2452 | " determined by the component: Button, Toggle, Separator, ContentCommand, FlyoutCommand.");
2453 | var CommandSpecs = {
2454 | Button: {
2455 | underlyingControlName: "AppBarCommand",
2456 | winControlOptions: { type: "button" },
2457 | render: function (component) {
2458 | return React.DOM.button();
2459 | },
2460 | propHandlers: {
2461 | type: typeWarnPropHandler,
2462 | }
2463 | },
2464 | Toggle: {
2465 | underlyingControlName: "AppBarCommand",
2466 | winControlOptions: { type: "toggle" },
2467 | render: function (component) {
2468 | return React.DOM.button();
2469 | },
2470 | propHandlers: {
2471 | type: typeWarnPropHandler
2472 | }
2473 | },
2474 | Separator: {
2475 | underlyingControlName: "AppBarCommand",
2476 | winControlOptions: { type: "separator" },
2477 | render: function (component) {
2478 | return React.DOM.hr();
2479 | },
2480 | propHandlers: {
2481 | type: typeWarnPropHandler
2482 | }
2483 | },
2484 | ContentCommand: {
2485 | underlyingControlName: "AppBarCommand",
2486 | winControlOptions: { type: "content" },
2487 | propHandlers: {
2488 | type: typeWarnPropHandler,
2489 | children: PropHandlers.mountTo(function (winjsComponent) {
2490 | return winjsComponent.winControl.element;
2491 | })
2492 | }
2493 | },
2494 | FlyoutCommand: {
2495 | underlyingControlName: "AppBarCommand",
2496 | winControlOptions: { type: "flyout" },
2497 | render: function (component) {
2498 | return React.DOM.button();
2499 | },
2500 | propHandlers: {
2501 | type: typeWarnPropHandler,
2502 | flyoutComponent: {
2503 | propType: React.PropTypes.element,
2504 | update: function FlyoutCommand_flyoutComponent_update(winjsComponent, propName, oldValue, newValue) {
2505 | var data = winjsComponent.data[propName];
2506 | if (!data) {
2507 | var flyoutHost = document.createElement("div");
2508 | flyoutHost.className = "win-react-flyout-host";
2509 | document.body.appendChild(flyoutHost);
2510 | winjsComponent.data[propName] = data = {
2511 | flyoutHost: flyoutHost,
2512 | flyoutComponent: null
2513 | };
2514 | }
2515 | var oldWinControl = data.flyoutComponent && data.flyoutComponent.winControl;
2516 | var instance = ReactDOM.render(newValue, data.flyoutHost);
2517 | if (oldWinControl !== instance.winControl) {
2518 | winjsComponent.winControl.flyout = instance.winControl;
2519 | }
2520 | winjsComponent.data[propName].flyoutComponent = instance;
2521 | },
2522 | dispose: function FlyoutCommand_flyoutComponent_dispose(winjsComponent, propName) {
2523 | var data = winjsComponent.data[propName];
2524 | if (data && data.flyoutHost) {
2525 | ReactDOM.unmountComponentAtNode(data.flyoutHost);
2526 | deparent(data.flyoutHost);
2527 | }
2528 | }
2529 | }
2530 | }
2531 | }
2532 | };
2533 |
2534 | var ControlApis = updateWithDefaults({
2535 | AppBar: {
2536 | propHandlers: {
2537 | opened: PropHandlers.focusProperty(React.PropTypes.bool),
2538 | children: PropHandlers.syncChildrenWithBindingList("data")
2539 | }
2540 | },
2541 | "AppBar.Button": CommandSpecs.Button,
2542 | "AppBar.Toggle": CommandSpecs.Toggle,
2543 | "AppBar.Separator": CommandSpecs.Separator,
2544 | "AppBar.ContentCommand": CommandSpecs.ContentCommand,
2545 | "AppBar.FlyoutCommand": CommandSpecs.FlyoutCommand,
2546 | AutoSuggestBox: {},
2547 | BackButton: {
2548 | preCtorInit: function (element, options, data, displayName) {
2549 | element.addEventListener("click", function (eventObject) {
2550 | // Prevent React from seeing the "click" event to workaround this React
2551 | // bug: https://github.com/facebook/react/issues/3790
2552 | eventObject.stopPropagation();
2553 | });
2554 | },
2555 | render: function (component) {
2556 | return React.DOM.button();
2557 | }
2558 | },
2559 | // CellSpanningLayout: Not a component so just use off of WinJS.UI?
2560 | ContentDialog: {
2561 | propHandlers: {
2562 | hidden: PropHandlers.focusProperty(React.PropTypes.bool),
2563 | children: PropHandlers.mountTo(function (winjsComponent) {
2564 | return winjsComponent.winControl.element.querySelector(".win-contentdialog-content");
2565 | })
2566 | }
2567 | },
2568 | DatePicker: {},
2569 | FlipView: {},
2570 | Flyout: {
2571 | // The WinJS Flyout control doesn't come with a good mount point.
2572 | // App content and control content are siblings in Flyout.element.
2573 | // Consequently, if React rendered to Flyout.element, it would destroy
2574 | // some of Flyout's elements. To fix this, we give Flyout a div
2575 | // (className="win-react-flyout-mount-point") which will contain only
2576 | // app content. The React component renders into this div so it doesn't
2577 | // destroy any control content.
2578 | render: function (component) {
2579 | return React.DOM.div(null, React.DOM.div({ className: "win-react-flyout-mount-point" }));
2580 | },
2581 | propHandlers: {
2582 | hidden: PropHandlers.focusProperty(React.PropTypes.bool),
2583 | children: PropHandlers.mountTo(function (winjsComponent) {
2584 | return winjsComponent.winControl.element.querySelector(".win-react-flyout-mount-point");
2585 | })
2586 | }
2587 | },
2588 | // GridLayout: Not a component so just use off of WinJS.UI?
2589 | Hub: {
2590 | propHandlers: {
2591 | children: PropHandlers.syncChildrenWithBindingList("sections")
2592 | }
2593 | },
2594 | "Hub.Section": {
2595 | underlyingControlName: "HubSection",
2596 | propHandlers: {
2597 | children: PropHandlers.mountTo(function (winjsComponent) {
2598 | return winjsComponent.winControl.contentElement;
2599 | })
2600 | }
2601 | },
2602 | ItemContainer: {
2603 | propHandlers: {
2604 | children: PropHandlers.mountTo(function (winjsComponent) {
2605 | return winjsComponent.winControl.element.querySelector(".win-item");
2606 | })
2607 | }
2608 | },
2609 | // ListLayout: Not a component so just use off of WinJS.UI?
2610 | ListView: {
2611 | propHandlers: {
2612 | currentItem: PropHandlers.focusProperty(React.PropTypes.any),
2613 | headerComponent: PropHandlers.propertyWithMount("header"),
2614 | footerComponent: PropHandlers.propertyWithMount("footer"),
2615 | }
2616 | },
2617 | // TODO: Keyboarding doesn't work in Menu probably because MenuCommands are not direct
2618 | // children of the Menu.
2619 | Menu: {
2620 | propHandlers: {
2621 | hidden: PropHandlers.focusProperty(React.PropTypes.bool),
2622 | children: {
2623 | // children propHandler looks like this rather than using mountTo on
2624 | // winControl.element because this enables props.children to have
2625 | // multiple components whereas the other technique restricts it to one.
2626 | update: function (winjsComponent, propName, oldValue, newValue) {
2627 | // TODO: dispose
2628 | ReactDOM.render(React.DOM.div(null, newValue), winjsComponent.winControl.element);
2629 | }
2630 | }
2631 | }
2632 | },
2633 | "Menu.Button": merge(CommandSpecs.Button, {
2634 | underlyingControlName: "MenuCommand"
2635 | }),
2636 | "Menu.Toggle": merge(CommandSpecs.Toggle, {
2637 | underlyingControlName: "MenuCommand"
2638 | }),
2639 | "Menu.Separator": merge(CommandSpecs.Separator, {
2640 | underlyingControlName: "MenuCommand"
2641 | }),
2642 | "Menu.FlyoutCommand": merge(CommandSpecs.FlyoutCommand, {
2643 | underlyingControlName: "MenuCommand"
2644 | }),
2645 | Pivot: {
2646 | propHandlers: {
2647 | children: PropHandlers.syncChildrenWithBindingList("items"),
2648 | customLeftHeaderComponent: PropHandlers.propertyWithMount("customLeftHeader"),
2649 | customRightHeaderComponent: PropHandlers.propertyWithMount("customRightHeader")
2650 | }
2651 | },
2652 | "Pivot.Item": {
2653 | underlyingControlName: "PivotItem",
2654 | propHandlers: {
2655 | children: PropHandlers.mountTo(function (winjsComponent) {
2656 | return winjsComponent.winControl.contentElement;
2657 | })
2658 | }
2659 | },
2660 | Rating: {},
2661 | SemanticZoom: {
2662 | propHandlers: {
2663 | zoomedInComponent: {
2664 | propType: React.PropTypes.element,
2665 | preCtorInit: function zoomedInComponent_preCtorInit(element, options, data, displayName, propName, value) {
2666 | var child = new WinJSChildComponent(value);
2667 | // Zoomed in component should be the first child.
2668 | element.insertBefore(child.winControl.element, element.firstElementChild);
2669 | data[propName] = child;
2670 | },
2671 | update: function zoomedInComponent_update(winjsComponent, propName, oldValue, newValue) {
2672 | var child = winjsComponent.data[propName];
2673 | if (child.type === newValue.type) {
2674 | child.update(newValue);
2675 | } else {
2676 | console.warn("SemanticZoom: zoomedInComponent's component type can't change");
2677 | }
2678 | },
2679 | dispose: function zoomedInComponent_dispose(winjsComponent, propName) {
2680 | var child = winjsComponent.data[propName];
2681 | child && child.dispose();
2682 | }
2683 | },
2684 | zoomedOutComponent: {
2685 | propType: React.PropTypes.element,
2686 | preCtorInit: function zoomedOutComponent_preCtorInit(element, options, data, displayName, propName, value) {
2687 | var child = new WinJSChildComponent(value);
2688 | // Zoomed out component should be the second child.
2689 | element.appendChild(child.winControl.element);
2690 | data[propName] = child;
2691 | },
2692 | update: function zoomedOutComponent_update(winjsComponent, propName, oldValue, newValue) {
2693 | var child = winjsComponent.data[propName];
2694 | if (child.type === newValue.type) {
2695 | child.update(newValue);
2696 | } else {
2697 | console.warn("SemanticZoom: zoomedOutComponent's component type can't change");
2698 | }
2699 | },
2700 | dispose: function zoomedOutComponent_dispose(winjsComponent, propName) {
2701 | var child = winjsComponent.data[propName];
2702 | child && child.dispose();
2703 | }
2704 | }
2705 | }
2706 | },
2707 | SplitView: {
2708 | propHandlers: {
2709 | paneOpened: PropHandlers.focusProperty(React.PropTypes.bool),
2710 | paneComponent: PropHandlers.mountTo(function (winjsComponent) {
2711 | return winjsComponent.winControl.paneElement;
2712 | }),
2713 | contentComponent: PropHandlers.mountTo(function (winjsComponent) {
2714 | return winjsComponent.winControl.contentElement;
2715 | })
2716 | }
2717 | },
2718 | "SplitView.Command": {
2719 | underlyingControlName: "SplitViewCommand",
2720 | },
2721 | SplitViewPaneToggle: {
2722 | render: function (component) {
2723 | return React.DOM.button();
2724 | },
2725 | propHandlers: {
2726 | // paneOpened provides a React-friendly interface for making the SplitViewPaneToggle accessible.
2727 | // When paneOpened is specified, is not undefined, and is not null, it:
2728 | // - Sets SplitViewPaneToggle's aria-expanded attribute to match paneOpened
2729 | // - Fires SplitViewPaneToggle's "invoked" event when aria-expanded is mutated
2730 | paneOpened: {
2731 | propType: React.PropTypes.bool,
2732 | update: function paneOpened_update(winjsComponent, propName, oldValue, newValue) {
2733 | var data = winjsComponent.data[propName];
2734 | if (!data) {
2735 | data = {
2736 | // WinJS.UI.SplitViewPaneToggle depends on WinJS.Utilities._MutationObserver so it
2737 | // is safe to use it here.
2738 | ariaExpandedMutationObserver: new WinJS.Utilities._MutationObserver(function () {
2739 | var element = winjsComponent.element;
2740 | var ariaExpanded = (element.getAttribute("aria-expanded") === "true");
2741 | if (ariaExpanded !== winjsComponent.data[propName].value) {
2742 | fireEvent(element, "invoked"); // Fire WinJS.UI.SplitViewPaneToggle's invoked event
2743 | }
2744 | }),
2745 | observing: false,
2746 | value: newValue
2747 | };
2748 | winjsComponent.data[propName] = data;
2749 | }
2750 |
2751 | if (oldValue !== newValue) {
2752 | if (newValue !== null && newValue !== undefined) {
2753 | winjsComponent.element.setAttribute("aria-expanded", newValue ? "true" : "false");
2754 | if (!data.observing) {
2755 | data.observing = true;
2756 | data.ariaExpandedMutationObserver.observe(winjsComponent.element, {
2757 | attributes: true,
2758 | attributeFilter: ["aria-expanded"]
2759 | });
2760 | }
2761 | } else {
2762 | winjsComponent.element.removeAttribute("aria-expanded");
2763 | if (data.observing) {
2764 | data.observing = false;
2765 | data.ariaExpandedMutationObserver.disconnect();
2766 | }
2767 | }
2768 | }
2769 |
2770 | data.value = newValue;
2771 | },
2772 | dispose: function paneOpened_dispose(winjsComponent, propName) {
2773 | var data = winjsComponent.data[propName];
2774 | if (data && data.observing) {
2775 | data.ariaExpandedMutationObserver.disconnect();
2776 | }
2777 | }
2778 | }
2779 | }
2780 | },
2781 | TimePicker: {},
2782 | ToggleSwitch: {},
2783 | ToolBar: {
2784 | propHandlers: {
2785 | opened: PropHandlers.focusProperty(React.PropTypes.bool),
2786 | children: PropHandlers.syncChildrenWithBindingList("data")
2787 | }
2788 | },
2789 | "ToolBar.Button": CommandSpecs.Button,
2790 | "ToolBar.Toggle": CommandSpecs.Toggle,
2791 | "ToolBar.Separator": CommandSpecs.Separator,
2792 | "ToolBar.ContentCommand": CommandSpecs.ContentCommand,
2793 | "ToolBar.FlyoutCommand": CommandSpecs.FlyoutCommand,
2794 | Tooltip: {
2795 | propHandlers: {
2796 | children: PropHandlers.mountTo(function (winjsComponent) {
2797 | return winjsComponent.winControl.element;
2798 | }),
2799 | contentComponent: PropHandlers.propertyWithMount("contentElement")
2800 | }
2801 | }
2802 | });
2803 |
2804 | //
2805 | // Publish
2806 | //
2807 |
2808 | var ReactWinJS = {};
2809 |
2810 | // Controls
2811 | //
2812 |
2813 | // Sort to ensure that controls come before their subcontrols
2814 | // (e.g. AppBar comes before AppBar.Toggle).
2815 | Object.keys(ControlApis).sort().forEach(function (controlName) {
2816 | nestedSet(ReactWinJS, controlName, defineControl(ControlApis[controlName]));
2817 | });
2818 |
2819 | // Utilites
2820 | //
2821 |
2822 | // Given a function that returns a React component,
2823 | // returns an item renderer function that can be used
2824 | // with WinJS controls. Useful for describing FlipView
2825 | // and ListView item templates as React components.
2826 | ReactWinJS.reactRenderer = function reactRenderer(componentFunction) {
2827 | var componentFunctionBound;
2828 | var renderItem = function renderItem(item) {
2829 | var element = document.createElement("div");
2830 | element.className = "win-react-renderer-host";
2831 | ReactDOM.render(componentFunctionBound(item), element);
2832 | WinJS.Utilities.markDisposable(element, function () {
2833 | ReactDOM.unmountComponentAtNode(element);
2834 | });
2835 | return element;
2836 | };
2837 |
2838 | return function itemRenderer(itemOrItemPromise) {
2839 | if (!componentFunctionBound) {
2840 | componentFunctionBound = componentFunction.bind(this);
2841 | }
2842 |
2843 | return WinJS.Promise.is(itemOrItemPromise) ?
2844 | itemOrItemPromise.then(renderItem) :
2845 | renderItem(itemOrItemPromise);
2846 | }
2847 | };
2848 |
2849 |
2850 | // Low-level utilities for wrapping custom WinJS-style controls
2851 | //
2852 |
2853 | ReactWinJS.defineControl = defineControl;
2854 | ReactWinJS.PropHandlers = PropHandlers;
2855 | ReactWinJS.defaultPropHandlers = defaultPropHandlers;
2856 |
2857 | module.exports = ReactWinJS;
2858 |
--------------------------------------------------------------------------------