Compare commits
	
		
			15 Commits
		
	
	
		
			version-1.
			...
			api-tutori
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d475d767d5 | ||
|   | a63e053399 | ||
|   | 5de7a96ccc | ||
|   | 09a833f524 | ||
|   | 9c4e17bfab | ||
|   | d3e5d95d6b | ||
|   | c70793ac2d | ||
|   | a6ef1d3423 | ||
|   | c4fec1af6a | ||
|   | a6996df3df | ||
|   | 0c660238f2 | ||
|   | b73b824e55 | ||
|   | 1954d98628 | ||
|   | 7aa034ce23 | ||
|   | 385dc5d298 | 
| @@ -18,6 +18,8 @@ | ||||
|     "node-uuid": "^1.4.7", | ||||
|     "comma-separated-values": "^3.6.4", | ||||
|     "FileSaver.js": "^0.0.2", | ||||
|     "zepto": "^1.1.6" | ||||
|     "zepto": "^1.1.6", | ||||
|     "eventemitter3": "^1.2.0", | ||||
|     "lodash": "3.10.1" | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								index.html
									
									
									
									
									
								
							| @@ -31,10 +31,17 @@ | ||||
|     <script type="text/javascript"> | ||||
|         require(['main'], function (mct) { | ||||
|             require([ | ||||
|                 './tutorials/grootprovider/groots', | ||||
|                 './tutorials/todo/todo', | ||||
|                 './tutorials/todo/bundle', | ||||
|                 './example/imagery/bundle', | ||||
|                 './example/eventGenerator/bundle', | ||||
|                 './example/generator/bundle' | ||||
|             ], mct.run.bind(mct)); | ||||
|                 './example/generator/bundle', | ||||
|             ], function (grootify, todoPlugin) { | ||||
|                 grootify(mct); | ||||
|                 todoPlugin(mct); | ||||
|                 mct.start(); | ||||
|             }) | ||||
|         }); | ||||
|     </script> | ||||
|     <link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css"> | ||||
|   | ||||
							
								
								
									
										25
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								main.js
									
									
									
									
									
								
							| @@ -28,13 +28,15 @@ requirejs.config({ | ||||
|         "angular-route": "bower_components/angular-route/angular-route.min", | ||||
|         "csv": "bower_components/comma-separated-values/csv.min", | ||||
|         "es6-promise": "bower_components/es6-promise/promise.min", | ||||
|         "EventEmitter": "bower_components/eventemitter3/index", | ||||
|         "moment": "bower_components/moment/moment", | ||||
|         "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", | ||||
|         "saveAs": "bower_components/FileSaver.js/FileSaver.min", | ||||
|         "screenfull": "bower_components/screenfull/dist/screenfull.min", | ||||
|         "text": "bower_components/text/text", | ||||
|         "uuid": "bower_components/node-uuid/uuid", | ||||
|         "zepto": "bower_components/zepto/zepto.min" | ||||
|         "zepto": "bower_components/zepto/zepto.min", | ||||
|         "lodash": "bower_components/lodash/lodash" | ||||
|     }, | ||||
|     "shim": { | ||||
|         "angular": { | ||||
| @@ -43,6 +45,9 @@ requirejs.config({ | ||||
|         "angular-route": { | ||||
|             "deps": ["angular"] | ||||
|         }, | ||||
|         "EventEmitter": { | ||||
|             "exports": "EventEmitter" | ||||
|         }, | ||||
|         "moment-duration-format": { | ||||
|             "deps": ["moment"] | ||||
|         }, | ||||
| @@ -58,6 +63,7 @@ requirejs.config({ | ||||
| define([ | ||||
|     './platform/framework/src/Main', | ||||
|     'legacyRegistry', | ||||
|     './src/MCT', | ||||
|  | ||||
|     './platform/framework/bundle', | ||||
|     './platform/core/bundle', | ||||
| @@ -93,11 +99,14 @@ define([ | ||||
|     './platform/search/bundle', | ||||
|     './platform/status/bundle', | ||||
|     './platform/commonUI/regions/bundle' | ||||
| ], function (Main, legacyRegistry) { | ||||
|     return { | ||||
|         legacyRegistry: legacyRegistry, | ||||
|         run: function () { | ||||
|             return new Main().run(legacyRegistry); | ||||
|         } | ||||
|     }; | ||||
| ], function (Main, legacyRegistry, MCT) { | ||||
|     var mct = new MCT(); | ||||
|  | ||||
|     mct.legacyRegistry = legacyRegistry; | ||||
|     mct.run = mct.start; | ||||
|     mct.on('start', function () { | ||||
|         return new Main().run(legacyRegistry); | ||||
|     }); | ||||
|  | ||||
|     return mct; | ||||
| }); | ||||
|   | ||||
							
								
								
									
										36
									
								
								src/MCT.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/MCT.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| define([ | ||||
|     'EventEmitter', | ||||
|     'legacyRegistry', | ||||
|     './api/api', | ||||
|     './api/objects/bundle' | ||||
| ], function ( | ||||
|     EventEmitter, | ||||
|     legacyRegistry, | ||||
|     api | ||||
| ) { | ||||
|     function MCT() { | ||||
|         EventEmitter.call(this); | ||||
|         this.legacyBundle = { extensions: {} }; | ||||
|     } | ||||
|  | ||||
|     MCT.prototype = Object.create(EventEmitter.prototype); | ||||
|  | ||||
|     Object.keys(api).forEach(function (k) { | ||||
|         MCT.prototype[k] = api[k]; | ||||
|     }); | ||||
|  | ||||
|     MCT.prototype.type = function (key, type) { | ||||
|         var legacyDef = type.toLegacyDefinition(); | ||||
|         legacyDef.key = key; | ||||
|         this.legacyBundle.extensions.types = | ||||
|             this.legacyBundle.extensions.types || []; | ||||
|         this.legacyBundle.extensions.types.push(legacyDef); | ||||
|     }; | ||||
|  | ||||
|     MCT.prototype.start = function () { | ||||
|         legacyRegistry.register('adapter', this.legacyBundle); | ||||
|         this.emit('start'); | ||||
|     }; | ||||
|  | ||||
|     return MCT; | ||||
| }); | ||||
							
								
								
									
										43
									
								
								src/api/Type.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/api/Type.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| define(function () { | ||||
|     /** | ||||
|      * @typedef TypeDefinition | ||||
|      * @property {Metadata} metadata displayable metadata about this type | ||||
|      * @property {function (object)} [initialize] a function which initializes | ||||
|      *           the model for new domain objects of this type | ||||
|      * @property {boolean} [creatable] true if users should be allowed to | ||||
|      *           create this type (default: false) | ||||
|      */ | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      * @param {TypeDefinition} definition | ||||
|      * @constructor | ||||
|      */ | ||||
|     function Type(definition) { | ||||
|         this.definition = definition; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a definition for this type that can be registered using the | ||||
|      * legacy bundle format. | ||||
|      * @private | ||||
|      */ | ||||
|     Type.prototype.toLegacyDefinition = function () { | ||||
|         var def = {}; | ||||
|         def.name = this.definition.metadata.label; | ||||
|         def.glyph = this.definition.metadata.glyph; | ||||
|         def.description = this.definition.metadata.description; | ||||
|  | ||||
|         if (this.definition.initialize) { | ||||
|             def.model = {}; | ||||
|             this.definition.initialize(def.model); | ||||
|         } | ||||
|  | ||||
|         if (this.definition.creatable) { | ||||
|             def.features = ['creation']; | ||||
|         } | ||||
|         return def; | ||||
|     }; | ||||
|  | ||||
|     return Type; | ||||
| }); | ||||
							
								
								
									
										12
									
								
								src/api/api.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/api/api.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| define([ | ||||
|     './Type', | ||||
|     './objects/ObjectAPI' | ||||
| ], function ( | ||||
|     Type, | ||||
|     ObjectAPI | ||||
| ) { | ||||
|     return { | ||||
|         Type: Type, | ||||
|         Objects: ObjectAPI | ||||
|     }; | ||||
| }); | ||||
							
								
								
									
										70
									
								
								src/api/objects/LegacyObjectAPIInterceptor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/api/objects/LegacyObjectAPIInterceptor.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| define([ | ||||
|     './object-utils', | ||||
|     './ObjectAPI' | ||||
| ], function ( | ||||
|     utils, | ||||
|     ObjectAPI | ||||
| ) { | ||||
|     function ObjectServiceProvider(objectService, instantiate) { | ||||
|         this.objectService = objectService; | ||||
|         this.instantiate = instantiate; | ||||
|     } | ||||
|  | ||||
|     ObjectServiceProvider.prototype.save = function (object) { | ||||
|         var key = object.key, | ||||
|             keyString = utils.makeKeyString(key), | ||||
|             newObject = this.instantiate(utils.toOldFormat(object), keyString); | ||||
|  | ||||
|         return object.getCapability('persistence') | ||||
|                 .persist() | ||||
|                 .then(function () { | ||||
|                     return utils.toNewFormat(object, key); | ||||
|                 }); | ||||
|     }; | ||||
|  | ||||
|     ObjectServiceProvider.prototype.delete = function (object) { | ||||
|         // TODO! | ||||
|     }; | ||||
|  | ||||
|     ObjectServiceProvider.prototype.get = function (key) { | ||||
|         var keyString = utils.makeKeyString(key); | ||||
|         return this.objectService.getObjects([keyString]) | ||||
|             .then(function (results) { | ||||
|                 var model = JSON.parse(JSON.stringify(results[keyString].getModel())); | ||||
|                 return utils.toNewFormat(model, key); | ||||
|             }); | ||||
|     }; | ||||
|  | ||||
|     // Injects new object API as a decorator so that it hijacks all requests. | ||||
|     // Object providers implemented on new API should just work, old API should just work, many things may break. | ||||
|     function LegacyObjectAPIInterceptor(ROOTS, instantiate, objectService) { | ||||
|         this.getObjects = function (keys) { | ||||
|             var results = {}, | ||||
|                 promises = keys.map(function (keyString) { | ||||
|                     var key = utils.parseKeyString(keyString); | ||||
|                     return ObjectAPI.get(key) | ||||
|                         .then(function (object) { | ||||
|                             object = utils.toOldFormat(object) | ||||
|                             results[keyString] = instantiate(object, keyString); | ||||
|                         }); | ||||
|                 }); | ||||
|  | ||||
|             return Promise.all(promises) | ||||
|                 .then(function () { | ||||
|                     return results; | ||||
|                 }); | ||||
|         }; | ||||
|  | ||||
|         ObjectAPI._supersecretSetFallbackProvider( | ||||
|             new ObjectServiceProvider(objectService, instantiate) | ||||
|         ); | ||||
|  | ||||
|         ROOTS.forEach(function (r) { | ||||
|             ObjectAPI.addRoot(utils.parseKeyString(r.id)); | ||||
|         }); | ||||
|  | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     return LegacyObjectAPIInterceptor; | ||||
| }); | ||||
							
								
								
									
										92
									
								
								src/api/objects/ObjectAPI.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/api/objects/ObjectAPI.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| define([ | ||||
|     'lodash', | ||||
|     './object-utils' | ||||
| ], function ( | ||||
|     _, | ||||
|     utils | ||||
| ) { | ||||
|  | ||||
|     /** | ||||
|         Object API.  Intercepts the existing object API while also exposing | ||||
|         A new Object API. | ||||
|  | ||||
|         MCT.objects.get('mine') | ||||
|             .then(function (root) { | ||||
|                 console.log(root); | ||||
|                 MCT.objects.getComposition(root) | ||||
|                     .then(function (composition) { | ||||
|                         console.log(composition) | ||||
|                     }) | ||||
|             }); | ||||
|     */ | ||||
|  | ||||
|     var Objects = {}, | ||||
|         ROOT_REGISTRY = [], | ||||
|         PROVIDER_REGISTRY = {}, | ||||
|         FALLBACK_PROVIDER; | ||||
|  | ||||
|     Objects._supersecretSetFallbackProvider = function (p) { | ||||
|         FALLBACK_PROVIDER = p; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Root provider is hardcoded in; can't be skipped. | ||||
|     var RootProvider = { | ||||
|         'get': function () { | ||||
|             return Promise.resolve({ | ||||
|                 name: 'The root object', | ||||
|                 type: 'root', | ||||
|                 composition: ROOT_REGISTRY | ||||
|             }); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     // Retrieve the provider for a given key. | ||||
|     function getProvider(key) { | ||||
|         if (key.identifier === 'ROOT') { | ||||
|             return RootProvider; | ||||
|         } | ||||
|         return PROVIDER_REGISTRY[key.namespace] || FALLBACK_PROVIDER; | ||||
|     }; | ||||
|  | ||||
|     Objects.addProvider = function (namespace, provider) { | ||||
|         PROVIDER_REGISTRY[namespace] = provider; | ||||
|     }; | ||||
|  | ||||
|     [ | ||||
|         'save', | ||||
|         'delete', | ||||
|         'get' | ||||
|     ].forEach(function (method) { | ||||
|         Objects[method] = function () { | ||||
|             var key = arguments[0], | ||||
|                 provider = getProvider(key); | ||||
|  | ||||
|             if (!provider) { | ||||
|                 throw new Error('No Provider Matched'); | ||||
|             } | ||||
|  | ||||
|             if (!provider[method]) { | ||||
|                 throw new Error('Provider does not support [' + method + '].'); | ||||
|             } | ||||
|  | ||||
|             return provider[method].apply(provider, arguments); | ||||
|         }; | ||||
|     }); | ||||
|  | ||||
|     Objects.addRoot = function (key) { | ||||
|         ROOT_REGISTRY.unshift(key); | ||||
|     }; | ||||
|  | ||||
|     Objects.removeRoot = function (key) { | ||||
|         ROOT_REGISTRY = ROOT_REGISTRY.filter(function (k) { | ||||
|             return ( | ||||
|                 k.identifier !== key.identifier || | ||||
|                 k.namespace !== key.namespace | ||||
|             ); | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     return Objects; | ||||
| }); | ||||
							
								
								
									
										100
									
								
								src/api/objects/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/api/objects/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| # Object API - Overview | ||||
|  | ||||
| The object API provides methods for fetching domain objects. | ||||
|  | ||||
| # Keys | ||||
| Keys are a composite identifier that is used to create and persist objects.  Ex: | ||||
| ```javascript | ||||
| { | ||||
|     namespace: 'elastic', | ||||
|     identifier: 'myIdentifier' | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In old MCT days, we called this an "id", and we encoded it in a single string.   | ||||
| The above key would encode into the identifier, `elastic:myIdentifier`. | ||||
|  | ||||
| When interacting with the API you will be dealing with key objects. | ||||
|  | ||||
| # Configuring the Object API | ||||
|  | ||||
| The following methods should be used before calling run.  They allow you to  | ||||
| configure the persistence space of MCT. | ||||
|  | ||||
| * `MCT.objects.addRoot(key)` -- add a "ROOT" to Open MCT by specifying it's  | ||||
|     key. | ||||
| * `MCT.objects.removeRoot(key)` -- Remove a "ROOT" from Open MCT by key. | ||||
| * `MCT.objects.addProvider(namespace, provider)` -- register an object provider | ||||
|     for a specific namespace.  See below for documentation on the provider  | ||||
|     interface. | ||||
|      | ||||
| # Using the object API | ||||
|  | ||||
| The object API provides methods for getting, saving, and deleting objects. | ||||
|  | ||||
| * MCT.objects.get(key) -> returns promise for an object | ||||
| * MCT.objects.save(object) -> returns promise that is resolved when object | ||||
|     has been saved | ||||
| * MCT.objects.delete(object) -> returns promise that is resolved when object has  | ||||
|     been deleted | ||||
|  | ||||
| ## Configuration Example: Adding a groot | ||||
|  | ||||
| The following example adds a new root object for groot and populates it with | ||||
| some pieces of groot. | ||||
|  | ||||
| ```javascript | ||||
|  | ||||
| var ROOT_KEY = { | ||||
|     namespace: 'groot', | ||||
|     identifier: 'groot' | ||||
| }; | ||||
|  | ||||
| var GROOT_ROOT = { | ||||
|     name: 'I am groot', | ||||
|     type: 'folder', | ||||
|     composition: [ | ||||
|         { | ||||
|             namespace: 'groot', | ||||
|             identifier: 'arms' | ||||
|         }, | ||||
|         { | ||||
|             namespace: 'groot', | ||||
|             identifier: 'legs' | ||||
|         }, | ||||
|         { | ||||
|             namespace: 'groot', | ||||
|             identifier: 'torso' | ||||
|         } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| var GrootProvider = { | ||||
|     get: function (key) { | ||||
|         if (key.identifier === 'groot') { | ||||
|             return Promise.resolve(GROOT_ROOT); | ||||
|         } | ||||
|         return Promise.resolve({ | ||||
|             name: 'Groot\'s ' + key.identifier | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| mct.Objects.addRoot(ROOT_KEY); | ||||
|  | ||||
| mct.Objects.addProvider('groot', GrootProvider); | ||||
|  | ||||
| ``` | ||||
|  | ||||
| ### Making a custom provider: | ||||
|  | ||||
| All methods on the provider interface are optional, so you do not need | ||||
| to modify them. | ||||
|  | ||||
| * `provider.get(key)` -> promise for a domain object. | ||||
| * `provider.save(domainObject)` -> returns promise that is fulfilled when object  | ||||
|     has been saved. | ||||
| * `provider.delete(domainObject)` -> returns promise that is fulfilled when  | ||||
|     object has been deleted. | ||||
|  | ||||
|  | ||||
							
								
								
									
										49
									
								
								src/api/objects/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/api/objects/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| /*global define*/ | ||||
|  | ||||
| define([ | ||||
|     './LegacyObjectAPIInterceptor', | ||||
|     'legacyRegistry' | ||||
| ], function ( | ||||
|     LegacyObjectAPIInterceptor, | ||||
|     legacyRegistry | ||||
| ) { | ||||
|     legacyRegistry.register('src/api/objects', { | ||||
|         name: 'Object API', | ||||
|         description: 'The public Objects API', | ||||
|         extensions: { | ||||
|             components: [ | ||||
|                 { | ||||
|                     provides: "objectService", | ||||
|                     type: "decorator", | ||||
|                     priority: "mandatory", | ||||
|                     implementation: LegacyObjectAPIInterceptor, | ||||
|                     depends: [ | ||||
|                         "roots[]", | ||||
|                         "instantiate" | ||||
|                     ] | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										67
									
								
								src/api/objects/object-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/api/objects/object-utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| define([ | ||||
|  | ||||
| ], function ( | ||||
|  | ||||
| ) { | ||||
|  | ||||
|     // take a key string and turn it into a key object | ||||
|     // 'scratch:root' ==> {namespace: 'scratch', identifier: 'root'} | ||||
|     var parseKeyString = function (key) { | ||||
|         if (typeof key === 'object') { | ||||
|             return key; | ||||
|         } | ||||
|         var namespace = '', | ||||
|             identifier = key; | ||||
|         for (var i = 0, escaped = false, len=key.length; i < len; i++) { | ||||
|             if (key[i] === ":" && !escaped) { | ||||
|                 namespace = key.slice(0, i); | ||||
|                 identifier = key.slice(i + 1); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         return { | ||||
|             namespace: namespace, | ||||
|             identifier: identifier | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     // take a key and turn it into a key string | ||||
|     // {namespace: 'scratch', identifier: 'root'} ==> 'scratch:root' | ||||
|     var makeKeyString = function (key) { | ||||
|         if (typeof key === 'string') { | ||||
|             return key; | ||||
|         } | ||||
|         if (!key.namespace) { | ||||
|             return key.identifier; | ||||
|         } | ||||
|         return [ | ||||
|             key.namespace.replace(':', '\\:'), | ||||
|             key.identifier.replace(':', '\\:') | ||||
|         ].join(':'); | ||||
|     }; | ||||
|  | ||||
|     // Converts composition to use key strings instead of keys | ||||
|     var toOldFormat = function (model) { | ||||
|         delete model.key; | ||||
|         if (model.composition) { | ||||
|             model.composition = model.composition.map(makeKeyString); | ||||
|         } | ||||
|         return model; | ||||
|     }; | ||||
|  | ||||
|     // converts composition to use keys instead of key strings | ||||
|     var toNewFormat = function (model, key) { | ||||
|         model.key = key; | ||||
|         if (model.composition) { | ||||
|             model.composition = model.composition.map(parseKeyString); | ||||
|         } | ||||
|         return model; | ||||
|     }; | ||||
|  | ||||
|     return { | ||||
|         toOldFormat: toOldFormat, | ||||
|         toNewFormat: toNewFormat, | ||||
|         makeKeyString: makeKeyString, | ||||
|         parseKeyString: parseKeyString | ||||
|     }; | ||||
| }); | ||||
| @@ -48,6 +48,7 @@ requirejs.config({ | ||||
|         "angular-route": "bower_components/angular-route/angular-route.min", | ||||
|         "csv": "bower_components/comma-separated-values/csv.min", | ||||
|         "es6-promise": "bower_components/es6-promise/promise.min", | ||||
|         "EventEmitter": "bower_components/eventemitter3/index", | ||||
|         "moment": "bower_components/moment/moment", | ||||
|         "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", | ||||
|         "saveAs": "bower_components/FileSaver.js/FileSaver.min", | ||||
| @@ -64,6 +65,9 @@ requirejs.config({ | ||||
|         "angular-route": { | ||||
|             "deps": [ "angular" ] | ||||
|         }, | ||||
|         "EventEmitter": { | ||||
|             "exports": "EventEmitter" | ||||
|         }, | ||||
|         "moment-duration-format": { | ||||
|             "deps": [ "moment" ] | ||||
|         }, | ||||
|   | ||||
							
								
								
									
										127
									
								
								tutorial-server/app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								tutorial-server/app.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| /*global require,process,console*/ | ||||
|  | ||||
| var CONFIG = { | ||||
|     port: 8081, | ||||
|     dictionary: "dictionary.json", | ||||
|     interval: 1000 | ||||
| }; | ||||
|  | ||||
| (function () { | ||||
|     "use strict"; | ||||
|  | ||||
|     var WebSocketServer = require('ws').Server, | ||||
|         fs = require('fs'), | ||||
|         wss = new WebSocketServer({ port: CONFIG.port }), | ||||
|         dictionary = JSON.parse(fs.readFileSync(CONFIG.dictionary, "utf8")), | ||||
|         spacecraft = { | ||||
|             "prop.fuel": 77, | ||||
|             "prop.thrusters": "OFF", | ||||
|             "comms.recd": 0, | ||||
|             "comms.sent": 0, | ||||
|             "pwr.temp": 245, | ||||
|             "pwr.c": 8.15, | ||||
|             "pwr.v": 30 | ||||
|         }, | ||||
|         histories = {}, | ||||
|         listeners = []; | ||||
|  | ||||
|     function updateSpacecraft() { | ||||
|         spacecraft["prop.fuel"] = Math.max( | ||||
|             0, | ||||
|             spacecraft["prop.fuel"] - | ||||
|             (spacecraft["prop.thrusters"] === "ON" ? 0.5 : 0) | ||||
|         ); | ||||
|         spacecraft["pwr.temp"] = spacecraft["pwr.temp"] * 0.985 | ||||
|         + Math.random() * 0.25 + Math.sin(Date.now()); | ||||
|         spacecraft["pwr.c"] = spacecraft["pwr.c"] * 0.985; | ||||
|         spacecraft["pwr.v"] = 30 + Math.pow(Math.random(), 3); | ||||
|     } | ||||
|  | ||||
|     function generateTelemetry() { | ||||
|         var timestamp = Date.now(), sent = 0; | ||||
|         Object.keys(spacecraft).forEach(function (id) { | ||||
|             var state = { timestamp: timestamp, value: spacecraft[id] }; | ||||
|             histories[id] = histories[id] || []; // Initialize | ||||
|             histories[id].push(state); | ||||
|             spacecraft["comms.sent"] += JSON.stringify(state).length; | ||||
|         }); | ||||
|         listeners.forEach(function (listener) { | ||||
|             listener(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function update() { | ||||
|         updateSpacecraft(); | ||||
|         generateTelemetry(); | ||||
|     } | ||||
|  | ||||
|     function handleConnection(ws) { | ||||
|         var subscriptions = {}, // Active subscriptions for this connection | ||||
|             handlers = {        // Handlers for specific requests | ||||
|                 dictionary: function () { | ||||
|                     ws.send(JSON.stringify({ | ||||
|                         type: "dictionary", | ||||
|                         value: dictionary | ||||
|                     })); | ||||
|                 }, | ||||
|                 subscribe: function (id) { | ||||
|                     subscriptions[id] = true; | ||||
|                 }, | ||||
|                 unsubscribe: function (id) { | ||||
|                     delete subscriptions[id]; | ||||
|                 }, | ||||
|                 history: function (id) { | ||||
|                     ws.send(JSON.stringify({ | ||||
|                         type: "history", | ||||
|                         id: id, | ||||
|                         value: histories[id] | ||||
|                     })); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|         function notifySubscribers() { | ||||
|             Object.keys(subscriptions).forEach(function (id) { | ||||
|                 var history = histories[id]; | ||||
|                 if (history) { | ||||
|                     ws.send(JSON.stringify({ | ||||
|                         type: "data", | ||||
|                         id: id, | ||||
|                         value: history[history.length - 1] | ||||
|                     })); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Listen for requests | ||||
|         ws.on('message', function (message) { | ||||
|             var parts = message.split(' '), | ||||
|                 handler = handlers[parts[0]]; | ||||
|             if (handler) { | ||||
|                 handler.apply(handlers, parts.slice(1)); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // Stop sending telemetry updates for this connection when closed | ||||
|         ws.on('close', function () { | ||||
|             listeners = listeners.filter(function (listener) { | ||||
|                 return listener !== notifySubscribers; | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Notify subscribers when telemetry is updated | ||||
|         listeners.push(notifySubscribers); | ||||
|     } | ||||
|  | ||||
|     update(); | ||||
|     setInterval(update, CONFIG.interval); | ||||
|  | ||||
|     wss.on('connection', handleConnection); | ||||
|  | ||||
|     console.log("Example spacecraft running on port "); | ||||
|     console.log("Press Enter to toggle thruster state."); | ||||
|     process.stdin.on('data', function (data) { | ||||
|         spacecraft['prop.thrusters'] = | ||||
|             (spacecraft['prop.thrusters'] === "OFF") ? "ON" : "OFF"; | ||||
|         console.log("Thrusters " + spacecraft["prop.thrusters"]); | ||||
|     }); | ||||
| }()); | ||||
							
								
								
									
										66
									
								
								tutorial-server/dictionary.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								tutorial-server/dictionary.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| { | ||||
|     "name": "Example Spacecraft", | ||||
|     "identifier": "sc", | ||||
|     "subsystems": [ | ||||
|         { | ||||
|             "name": "Propulsion", | ||||
|             "identifier": "prop", | ||||
|             "measurements": [ | ||||
|                 { | ||||
|                     "name": "Fuel", | ||||
|                     "identifier": "prop.fuel", | ||||
|                     "units": "kilograms", | ||||
|                     "type": "float" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Thrusters", | ||||
|                     "identifier": "prop.thrusters", | ||||
|                     "units": "None", | ||||
|                     "type": "string" | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "Communications", | ||||
|             "identifier": "comms", | ||||
|             "measurements": [ | ||||
|                 { | ||||
|                     "name": "Received", | ||||
|                     "identifier": "comms.recd", | ||||
|                     "units": "bytes", | ||||
|                     "type": "integer" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Sent", | ||||
|                     "identifier": "comms.sent", | ||||
|                     "units": "bytes", | ||||
|                     "type": "integer" | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "Power", | ||||
|             "identifier": "pwr", | ||||
|             "measurements": [ | ||||
|                 { | ||||
|                     "name": "Generator Temperature", | ||||
|                     "identifier": "pwr.temp", | ||||
|                     "units": "\u0080C", | ||||
|                     "type": "float" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Generator Current", | ||||
|                     "identifier": "pwr.c", | ||||
|                     "units": "A", | ||||
|                     "type": "float" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Generator Voltage", | ||||
|                     "identifier": "pwr.v", | ||||
|                     "units": "V", | ||||
|                     "type": "float" | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										66
									
								
								tutorials/bargraph/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								tutorials/bargraph/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| define([ | ||||
|     'legacyRegistry', | ||||
|     './src/controllers/BarGraphController' | ||||
| ], function ( | ||||
|     legacyRegistry, | ||||
|     BarGraphController | ||||
|     ) { | ||||
|     legacyRegistry.register("tutorials/bargraph", { | ||||
|         "name": "Bar Graph", | ||||
|         "description": "Provides the Bar Graph view of telemetry elements.", | ||||
|         "extensions": { | ||||
|             "views": [ | ||||
|                 { | ||||
|                     "name": "Bar Graph", | ||||
|                     "key": "example.bargraph", | ||||
|                     "glyph": "H", | ||||
|                     "templateUrl": "templates/bargraph.html", | ||||
|                     "needs": [ "telemetry" ], | ||||
|                     "delegation": true, | ||||
|                     "editable": true, | ||||
|                     "toolbar": { | ||||
|                         "sections": [ | ||||
|                             { | ||||
|                                 "items": [ | ||||
|                                     { | ||||
|                                         "name": "Low", | ||||
|                                         "property": "low", | ||||
|                                         "required": true, | ||||
|                                         "control": "textfield", | ||||
|                                         "size": 4 | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         "name": "Middle", | ||||
|                                         "property": "middle", | ||||
|                                         "required": true, | ||||
|                                         "control": "textfield", | ||||
|                                         "size": 4 | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         "name": "High", | ||||
|                                         "property": "high", | ||||
|                                         "required": true, | ||||
|                                         "control": "textfield", | ||||
|                                         "size": 4 | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             "stylesheets": [ | ||||
|                 { | ||||
|                     "stylesheetUrl": "css/bargraph.css" | ||||
|                 } | ||||
|             ], | ||||
|             "controllers": [ | ||||
|                 { | ||||
|                     "key": "BarGraphController", | ||||
|                     "implementation": BarGraphController, | ||||
|                     "depends": [ "$scope", "telemetryHandler" ] | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										35
									
								
								tutorials/bargraph/res/templates/bargraph.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								tutorials/bargraph/res/templates/bargraph.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <div class="example-bargraph" ng-controller="BarGraphController"> | ||||
|     <div class="example-tick-labels"> | ||||
|         <div ng-repeat="value in [low, middle, high] track by $index" | ||||
|              class="example-tick-label" | ||||
|              style="bottom: {{ toPercent(value) }}%"> | ||||
|             {{value}} | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="example-graph-area"> | ||||
|         <div ng-repeat="telemetryObject in telemetryObjects" | ||||
|              style="left: {{barWidth * $index}}%; width: {{barWidth}}%" | ||||
|              class="example-bar-holder"> | ||||
|             <div class="example-bar" | ||||
|                  ng-style="{ | ||||
|                      bottom: getBottom(telemetryObject) + '%', | ||||
|                      top: getTop(telemetryObject) + '%' | ||||
|                  }"> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div style="bottom: {{ toPercent(middle) }}%" | ||||
|              class="example-graph-tick"> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="example-bar-labels"> | ||||
|         <div ng-repeat="telemetryObject in telemetryObjects" | ||||
|              style="left: {{barWidth * $index}}%; width: {{barWidth}}%" | ||||
|              class="example-bar-holder example-label"> | ||||
|             <mct-representation key="'label'" | ||||
|                                 mct-object="telemetryObject"> | ||||
|             </mct-representation> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										75
									
								
								tutorials/bargraph/src/controllers/BarGraphController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								tutorials/bargraph/src/controllers/BarGraphController.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| define(function () { | ||||
|     function BarGraphController($scope, telemetryHandler) { | ||||
|         var handle; | ||||
|  | ||||
|         // Expose configuration constants directly in scope | ||||
|         function exposeConfiguration() { | ||||
|             $scope.low = $scope.configuration.low; | ||||
|             $scope.middle = $scope.configuration.middle; | ||||
|             $scope.high = $scope.configuration.high; | ||||
|         } | ||||
|  | ||||
|         // Populate a default value in the configuration | ||||
|         function setDefault(key, value) { | ||||
|             if ($scope.configuration[key] === undefined) { | ||||
|                 $scope.configuration[key] = value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Getter-setter for configuration properties (for view proxy) | ||||
|         function getterSetter(property) { | ||||
|             return function (value) { | ||||
|                 value = parseFloat(value); | ||||
|                 if (!isNaN(value)) { | ||||
|                     $scope.configuration[property] = value; | ||||
|                     exposeConfiguration(); | ||||
|                 } | ||||
|                 return $scope.configuration[property]; | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         // Add min/max defaults | ||||
|         setDefault('low', -1); | ||||
|         setDefault('middle', 0); | ||||
|         setDefault('high', 1); | ||||
|         exposeConfiguration($scope.configuration); | ||||
|  | ||||
|         // Expose view configuration options | ||||
|         if ($scope.selection) { | ||||
|             $scope.selection.proxy({ | ||||
|                 low: getterSetter('low'), | ||||
|                 middle: getterSetter('middle'), | ||||
|                 high: getterSetter('high') | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Convert value to a percent between 0-100 | ||||
|         $scope.toPercent = function (value) { | ||||
|             var pct = 100 * (value - $scope.low) / | ||||
|                 ($scope.high - $scope.low); | ||||
|             return Math.min(100, Math.max(0, pct)); | ||||
|         }; | ||||
|  | ||||
|         // Get bottom and top (as percentages) for current value | ||||
|         $scope.getBottom = function (telemetryObject) { | ||||
|             var value = handle.getRangeValue(telemetryObject); | ||||
|             return $scope.toPercent(Math.min($scope.middle, value)); | ||||
|         }; | ||||
|         $scope.getTop = function (telemetryObject) { | ||||
|             var value = handle.getRangeValue(telemetryObject); | ||||
|             return 100 - $scope.toPercent(Math.max($scope.middle, value)); | ||||
|         }; | ||||
|  | ||||
|         // Use the telemetryHandler to get telemetry objects here | ||||
|         handle = telemetryHandler.handle($scope.domainObject, function () { | ||||
|             $scope.telemetryObjects = handle.getTelemetryObjects(); | ||||
|             $scope.barWidth = | ||||
|                 100 / Math.max(($scope.telemetryObjects).length, 1); | ||||
|         }); | ||||
|  | ||||
|         // Release subscriptions when scope is destroyed | ||||
|         $scope.$on('$destroy', handle.unsubscribe); | ||||
|     } | ||||
|  | ||||
|     return BarGraphController; | ||||
| }); | ||||
							
								
								
									
										44
									
								
								tutorials/grootprovider/groots.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tutorials/grootprovider/groots.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| define(function () { | ||||
|     return function grootPlugin(mct) { | ||||
|         var ROOT_KEY = { | ||||
|             namespace: 'groot', | ||||
|             identifier: 'groot' | ||||
|         }; | ||||
|  | ||||
|         var GROOT_ROOT = { | ||||
|             name: 'I am groot', | ||||
|             type: 'folder', | ||||
|             composition: [ | ||||
|                 { | ||||
|                     namespace: 'groot', | ||||
|                     identifier: 'arms' | ||||
|                 }, | ||||
|                 { | ||||
|                     namespace: 'groot', | ||||
|                     identifier: 'legs' | ||||
|                 }, | ||||
|                 { | ||||
|                     namespace: 'groot', | ||||
|                     identifier: 'torso' | ||||
|                 } | ||||
|             ] | ||||
|         }; | ||||
|  | ||||
|         var GrootProvider = { | ||||
|             get: function (key) { | ||||
|                 if (key.identifier === 'groot') { | ||||
|                     return Promise.resolve(GROOT_ROOT); | ||||
|                 } | ||||
|                 return Promise.resolve({ | ||||
|                     name: 'Groot\'s ' + key.identifier | ||||
|                 }); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         mct.Objects.addRoot(ROOT_KEY); | ||||
|  | ||||
|         mct.Objects.addProvider('groot', GrootProvider); | ||||
|  | ||||
|         return mct; | ||||
|     }; | ||||
| }); | ||||
							
								
								
									
										90
									
								
								tutorials/telemetry/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								tutorials/telemetry/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| define([ | ||||
|     'legacyRegistry', | ||||
|     './src/ExampleTelemetryServerAdapter', | ||||
|     './src/ExampleTelemetryInitializer', | ||||
|     './src/ExampleTelemetryModelProvider' | ||||
| ], function ( | ||||
|     legacyRegistry, | ||||
|     ExampleTelemetryServerAdapter, | ||||
|     ExampleTelemetryInitializer, | ||||
|     ExampleTelemetryModelProvider | ||||
| ) { | ||||
|     legacyRegistry.register("tutorials/telemetry", { | ||||
|         "name": "Example Telemetry Adapter", | ||||
|         "extensions": { | ||||
|             "types": [ | ||||
|                 { | ||||
|                     "name": "Spacecraft", | ||||
|                     "key": "example.spacecraft", | ||||
|                     "glyph": "o" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Subsystem", | ||||
|                     "key": "example.subsystem", | ||||
|                     "glyph": "o", | ||||
|                     "model": { "composition": [] } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Measurement", | ||||
|                     "key": "example.measurement", | ||||
|                     "glyph": "T", | ||||
|                     "model": { "telemetry": {} }, | ||||
|                     "telemetry": { | ||||
|                         "source": "example.source", | ||||
|                         "domains": [ | ||||
|                             { | ||||
|                                 "name": "Time", | ||||
|                                 "key": "timestamp" | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             "roots": [ | ||||
|                 { | ||||
|                     "id": "example:sc", | ||||
|                     "priority": "preferred", | ||||
|                     "model": { | ||||
|                         "type": "example.spacecraft", | ||||
|                         "name": "My Spacecraft", | ||||
|                         "composition": [] | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             "services": [ | ||||
|                 { | ||||
|                     "key": "example.adapter", | ||||
|                     "implementation": "ExampleTelemetryServerAdapter.js", | ||||
|                     "depends": [ "$q", "EXAMPLE_WS_URL" ] | ||||
|                 } | ||||
|             ], | ||||
|             "constants": [ | ||||
|                 { | ||||
|                     "key": "EXAMPLE_WS_URL", | ||||
|                     "priority": "fallback", | ||||
|                     "value": "ws://localhost:8081" | ||||
|                 } | ||||
|             ], | ||||
|             "runs": [ | ||||
|                 { | ||||
|                     "implementation": "ExampleTelemetryInitializer.js", | ||||
|                     "depends": [ "example.adapter", "objectService" ] | ||||
|                 } | ||||
|             ], | ||||
|             "components": [ | ||||
|                 { | ||||
|                     "provides": "modelService", | ||||
|                     "type": "provider", | ||||
|                     "implementation": "ExampleTelemetryModelProvider.js", | ||||
|                     "depends": [ "example.adapter", "$q" ] | ||||
|                 }, | ||||
|                 { | ||||
|                     "provides": "telemetryService", | ||||
|                     "type": "provider", | ||||
|                     "implementation": "ExampleTelemetryProvider.js", | ||||
|                     "depends": [ "example.adapter", "$q" ] | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										47
									
								
								tutorials/telemetry/src/ExampleTelemetryInitializer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tutorials/telemetry/src/ExampleTelemetryInitializer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| define( | ||||
|     function () { | ||||
|         "use strict"; | ||||
|  | ||||
|         var TAXONOMY_ID = "example:sc", | ||||
|             PREFIX = "example_tlm:"; | ||||
|  | ||||
|         function ExampleTelemetryInitializer(adapter, objectService) { | ||||
|             // Generate a domain object identifier for a dictionary element | ||||
|             function makeId(element) { | ||||
|                 return PREFIX + element.identifier; | ||||
|             } | ||||
|  | ||||
|             // When the dictionary is available, add all subsystems | ||||
|             // to the composition of My Spacecraft | ||||
|             function initializeTaxonomy(dictionary) { | ||||
|                 // Get the top-level container for dictionary objects | ||||
|                 // from a group of domain objects. | ||||
|                 function getTaxonomyObject(domainObjects) { | ||||
|                     return domainObjects[TAXONOMY_ID]; | ||||
|                 } | ||||
|  | ||||
|                 // Populate | ||||
|                 function populateModel(taxonomyObject) { | ||||
|                     return taxonomyObject.useCapability( | ||||
|                         "mutation", | ||||
|                         function (model) { | ||||
|                             model.name = | ||||
|                                 dictionary.name; | ||||
|                             model.composition = | ||||
|                                 dictionary.subsystems.map(makeId); | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|  | ||||
|                 // Look up My Spacecraft, and populate it accordingly. | ||||
|                 objectService.getObjects([TAXONOMY_ID]) | ||||
|                     .then(getTaxonomyObject) | ||||
|                     .then(populateModel); | ||||
|             } | ||||
|  | ||||
|             adapter.dictionary().then(initializeTaxonomy); | ||||
|         } | ||||
|  | ||||
|         return ExampleTelemetryInitializer; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										78
									
								
								tutorials/telemetry/src/ExampleTelemetryModelProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								tutorials/telemetry/src/ExampleTelemetryModelProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| define( | ||||
|     function () { | ||||
|         "use strict"; | ||||
|  | ||||
|         var PREFIX = "example_tlm:", | ||||
|             FORMAT_MAPPINGS = { | ||||
|                 float: "number", | ||||
|                 integer: "number", | ||||
|                 string: "string" | ||||
|             }; | ||||
|  | ||||
|         function ExampleTelemetryModelProvider(adapter, $q) { | ||||
|             var modelPromise, empty = $q.when({}); | ||||
|  | ||||
|             // Check if this model is in our dictionary (by prefix) | ||||
|             function isRelevant(id) { | ||||
|                 return id.indexOf(PREFIX) === 0; | ||||
|             } | ||||
|  | ||||
|             // Build a domain object identifier by adding a prefix | ||||
|             function makeId(element) { | ||||
|                 return PREFIX + element.identifier; | ||||
|             } | ||||
|  | ||||
|             // Create domain object models from this dictionary | ||||
|             function buildTaxonomy(dictionary) { | ||||
|                 var models = {}; | ||||
|  | ||||
|                 // Create & store a domain object model for a measurement | ||||
|                 function addMeasurement(measurement) { | ||||
|                     var format = FORMAT_MAPPINGS[measurement.type]; | ||||
|                     models[makeId(measurement)] = { | ||||
|                         type: "example.measurement", | ||||
|                         name: measurement.name, | ||||
|                         telemetry: { | ||||
|                             key: measurement.identifier, | ||||
|                             ranges: [{ | ||||
|                                 key: "value", | ||||
|                                 name: "Value", | ||||
|                                 units: measurement.units, | ||||
|                                 format: format | ||||
|                             }] | ||||
|                         } | ||||
|                     }; | ||||
|                 } | ||||
|  | ||||
|                 // Create & store a domain object model for a subsystem | ||||
|                 function addSubsystem(subsystem) { | ||||
|                     var measurements = | ||||
|                         (subsystem.measurements || []); | ||||
|                     models[makeId(subsystem)] = { | ||||
|                         type: "example.subsystem", | ||||
|                         name: subsystem.name, | ||||
|                         composition: measurements.map(makeId) | ||||
|                     }; | ||||
|                     measurements.forEach(addMeasurement); | ||||
|                 } | ||||
|  | ||||
|                 (dictionary.subsystems || []).forEach(addSubsystem); | ||||
|  | ||||
|                 return models; | ||||
|             } | ||||
|  | ||||
|             // Begin generating models once the dictionary is available | ||||
|             modelPromise = adapter.dictionary().then(buildTaxonomy); | ||||
|  | ||||
|             return { | ||||
|                 getModels: function (ids) { | ||||
|                     // Return models for the dictionary only when they | ||||
|                     // are relevant to the request. | ||||
|                     return ids.some(isRelevant) ? modelPromise : empty; | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return ExampleTelemetryModelProvider; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										80
									
								
								tutorials/telemetry/src/ExampleTelemetryProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								tutorials/telemetry/src/ExampleTelemetryProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| define( | ||||
|     ['./ExampleTelemetrySeries'], | ||||
|     function (ExampleTelemetrySeries) { | ||||
|         "use strict"; | ||||
|  | ||||
|         var SOURCE = "example.source"; | ||||
|  | ||||
|         function ExampleTelemetryProvider(adapter, $q) { | ||||
|             var subscribers = {}; | ||||
|  | ||||
|             // Used to filter out requests for telemetry | ||||
|             // from some other source | ||||
|             function matchesSource(request) { | ||||
|                 return (request.source === SOURCE); | ||||
|             } | ||||
|  | ||||
|             // Listen for data, notify subscribers | ||||
|             adapter.listen(function (message) { | ||||
|                 var packaged = {}; | ||||
|                 packaged[SOURCE] = {}; | ||||
|                 packaged[SOURCE][message.id] = | ||||
|                     new ExampleTelemetrySeries([message.value]); | ||||
|                 (subscribers[message.id] || []).forEach(function (cb) { | ||||
|                     cb(packaged); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             return { | ||||
|                 requestTelemetry: function (requests) { | ||||
|                     var packaged = {}, | ||||
|                         relevantReqs = requests.filter(matchesSource); | ||||
|  | ||||
|                     // Package historical telemetry that has been received | ||||
|                     function addToPackage(history) { | ||||
|                         packaged[SOURCE][history.id] = | ||||
|                             new ExampleTelemetrySeries(history.value); | ||||
|                     } | ||||
|  | ||||
|                     // Retrieve telemetry for a specific measurement | ||||
|                     function handleRequest(request) { | ||||
|                         var key = request.key; | ||||
|                         return adapter.history(key).then(addToPackage); | ||||
|                     } | ||||
|  | ||||
|                     packaged[SOURCE] = {}; | ||||
|                     return $q.all(relevantReqs.map(handleRequest)) | ||||
|                         .then(function () { return packaged; }); | ||||
|                 }, | ||||
|                 subscribe: function (callback, requests) { | ||||
|                     var keys = requests.filter(matchesSource) | ||||
|                         .map(function (req) { return req.key; }); | ||||
|  | ||||
|                     function notCallback(cb) { | ||||
|                         return cb !== callback; | ||||
|                     } | ||||
|  | ||||
|                     function unsubscribe(key) { | ||||
|                         subscribers[key] = | ||||
|                             (subscribers[key] || []).filter(notCallback); | ||||
|                         if (subscribers[key].length < 1) { | ||||
|                             adapter.unsubscribe(key); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     keys.forEach(function (key) { | ||||
|                         subscribers[key] = subscribers[key] || []; | ||||
|                         adapter.subscribe(key); | ||||
|                         subscribers[key].push(callback); | ||||
|                     }); | ||||
|  | ||||
|                     return function () { | ||||
|                         keys.forEach(unsubscribe); | ||||
|                     }; | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return ExampleTelemetryProvider; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										23
									
								
								tutorials/telemetry/src/ExampleTelemetrySeries.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tutorials/telemetry/src/ExampleTelemetrySeries.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /*global define*/ | ||||
|  | ||||
| define( | ||||
|     function () { | ||||
|         "use strict"; | ||||
|  | ||||
|         function ExampleTelemetrySeries(data) { | ||||
|             return { | ||||
|                 getPointCount: function () { | ||||
|                     return data.length; | ||||
|                 }, | ||||
|                 getDomainValue: function (index) { | ||||
|                     return (data[index] || {}).timestamp; | ||||
|                 }, | ||||
|                 getRangeValue: function (index) { | ||||
|                     return (data[index] || {}).value; | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return ExampleTelemetrySeries; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										60
									
								
								tutorials/telemetry/src/ExampleTelemetryServerAdapter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								tutorials/telemetry/src/ExampleTelemetryServerAdapter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| define( | ||||
|     [], | ||||
|     function () { | ||||
|         "use strict"; | ||||
|  | ||||
|         function ExampleTelemetryServerAdapter($q, wsUrl) { | ||||
|             var ws = new WebSocket(wsUrl), | ||||
|                 histories = {}, | ||||
|                 listeners = [], | ||||
|                 dictionary = $q.defer(); | ||||
|  | ||||
|             // Handle an incoming message from the server | ||||
|             ws.onmessage = function (event) { | ||||
|                 var message = JSON.parse(event.data); | ||||
|  | ||||
|                 switch (message.type) { | ||||
|                 case "dictionary": | ||||
|                     dictionary.resolve(message.value); | ||||
|                     break; | ||||
|                 case "history": | ||||
|                     histories[message.id].resolve(message); | ||||
|                     delete histories[message.id]; | ||||
|                     break; | ||||
|                 case "data": | ||||
|                     listeners.forEach(function (listener) { | ||||
|                         listener(message); | ||||
|                     }); | ||||
|                     break; | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             // Request dictionary once connection is established | ||||
|             ws.onopen = function () { | ||||
|                 ws.send("dictionary"); | ||||
|             }; | ||||
|  | ||||
|             return { | ||||
|                 dictionary: function () { | ||||
|                     return dictionary.promise; | ||||
|                 }, | ||||
|                 history: function (id) { | ||||
|                     histories[id] = histories[id] || $q.defer(); | ||||
|                     ws.send("history " + id); | ||||
|                     return histories[id].promise; | ||||
|                 }, | ||||
|                 subscribe: function (id) { | ||||
|                     ws.send("subscribe " + id); | ||||
|                 }, | ||||
|                 unsubscribe: function (id) { | ||||
|                     ws.send("unsubscribe " + id); | ||||
|                 }, | ||||
|                 listen: function (callback) { | ||||
|                     listeners.push(callback); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return ExampleTelemetryServerAdapter; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										59
									
								
								tutorials/todo/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								tutorials/todo/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| define([ | ||||
|     'legacyRegistry', | ||||
|     './src/controllers/TodoController' | ||||
| ], function ( | ||||
|     legacyRegistry, | ||||
|     TodoController | ||||
| ) { | ||||
|     legacyRegistry.register("tutorials/todo", { | ||||
|         "name": "To-do Plugin", | ||||
|         "description": "Allows creating and editing to-do lists.", | ||||
|         "extensions": { | ||||
|             "views": [ | ||||
|                 { | ||||
|                     "key": "example.todo", | ||||
|                     "type": "example.todo", | ||||
|                     "glyph": "2", | ||||
|                     "name": "List", | ||||
|                     "templateUrl": "templates/todo.html", | ||||
|                     "editable": true, | ||||
|                     "toolbar": { | ||||
|                         "sections": [ | ||||
|                             { | ||||
|                                 "items": [ | ||||
|                                     { | ||||
|                                         "text": "Add Task", | ||||
|                                         "glyph": "+", | ||||
|                                         "method": "addTask", | ||||
|                                         "control": "button" | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "items": [ | ||||
|                                     { | ||||
|                                         "glyph": "Z", | ||||
|                                         "method": "removeTask", | ||||
|                                         "control": "button" | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 } | ||||
|             ], | ||||
|             "controllers": [ | ||||
|                 { | ||||
|                     "key": "TodoController", | ||||
|                     "implementation": TodoController, | ||||
|                     "depends": [ "$scope", "dialogService" ] | ||||
|                 } | ||||
|             ], | ||||
|                "stylesheets": [ | ||||
|                    { | ||||
|                        "stylesheetUrl": "css/todo.css" | ||||
|               } | ||||
|        ] | ||||
|     } | ||||
| }); | ||||
| }); | ||||
							
								
								
									
										29
									
								
								tutorials/todo/res/templates/todo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tutorials/todo/res/templates/todo.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| <div ng-controller="TodoController" class="example-todo"> | ||||
|     <div class="example-button-group"> | ||||
|         <a ng-class="{ selected: checkVisibility(true) }" | ||||
|            ng-click="setVisibility(true)">All</a> | ||||
|         <a ng-class="{ selected: checkVisibility(false, false) }" | ||||
|            ng-click="setVisibility(false, false)">Incomplete</a> | ||||
|         <a ng-class="{ selected: checkVisibility(false, true) }" | ||||
|            ng-click="setVisibility(false, true)">Complete</a> | ||||
|     </div> | ||||
|  | ||||
|     <ul> | ||||
|         <li ng-repeat="task in model.tasks" | ||||
|             ng-class="{ 'example-task-completed': task.completed }" | ||||
|             ng-if="showTask(task)"> | ||||
|  | ||||
|             <input type="checkbox" | ||||
|                    ng-checked="task.completed" | ||||
|                    ng-click="toggleCompletion($index)"> | ||||
|             <span ng-click="selectTask($index)" | ||||
|                   ng-class="{ selected: isSelected($index) }" | ||||
|                   class="example-task-description"> | ||||
|                 {{task.description}} | ||||
|             </span> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <div ng-if="model.tasks.length < 1" class="example-message"> | ||||
|         There are no tasks to show. | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										97
									
								
								tutorials/todo/src/controllers/TodoController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								tutorials/todo/src/controllers/TodoController.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| define(function () { | ||||
|     // Form to display when adding new tasks | ||||
|     var NEW_TASK_FORM = { | ||||
|         name: "Add a Task", | ||||
|         sections: [{ | ||||
|             rows: [{ | ||||
|                 name: 'Description', | ||||
|                 key: 'description', | ||||
|                 control: 'textfield', | ||||
|                 required: true | ||||
|             }] | ||||
|         }] | ||||
|     }; | ||||
|  | ||||
|     function TodoController($scope, dialogService) { | ||||
|         var showAll = true, | ||||
|             showCompleted; | ||||
|  | ||||
|         // Persist changes made to a domain object's model | ||||
|         function persist() { | ||||
|             var persistence = | ||||
|                 $scope.domainObject.getCapability('persistence'); | ||||
|             return persistence && persistence.persist(); | ||||
|         } | ||||
|  | ||||
|         // Remove a task | ||||
|         function removeTaskAtIndex(taskIndex) { | ||||
|             $scope.domainObject.useCapability('mutation', function (model) { | ||||
|                 model.tasks.splice(taskIndex, 1); | ||||
|             }); | ||||
|             persist(); | ||||
|         } | ||||
|  | ||||
|         // Add a task | ||||
|         function addNewTask(task) { | ||||
|             $scope.domainObject.useCapability('mutation', function (model) { | ||||
|                 model.tasks.push(task); | ||||
|             }); | ||||
|             persist(); | ||||
|         } | ||||
|  | ||||
|         // Change which tasks are visible | ||||
|         $scope.setVisibility = function (all, completed) { | ||||
|             showAll = all; | ||||
|             showCompleted = completed; | ||||
|         }; | ||||
|  | ||||
|         // Check if current visibility settings match | ||||
|         $scope.checkVisibility = function (all, completed) { | ||||
|             return showAll ? all : (completed === showCompleted); | ||||
|         }; | ||||
|  | ||||
|         // Toggle the completion state of a task | ||||
|         $scope.toggleCompletion = function (taskIndex) { | ||||
|             $scope.domainObject.useCapability('mutation', function (model) { | ||||
|                 var task = model.tasks[taskIndex]; | ||||
|                 task.completed = !task.completed; | ||||
|             }); | ||||
|             persist(); | ||||
|         }; | ||||
|  | ||||
|         // Check whether a task should be visible | ||||
|         $scope.showTask = function (task) { | ||||
|             return showAll || (showCompleted === !!(task.completed)); | ||||
|         }; | ||||
|  | ||||
|         // Handle selection state in edit mode | ||||
|         if ($scope.selection) { | ||||
|             // Expose the ability to select tasks | ||||
|             $scope.selectTask = function (taskIndex) { | ||||
|                 $scope.selection.select({ | ||||
|                     removeTask: function () { | ||||
|                         removeTaskAtIndex(taskIndex); | ||||
|                         $scope.selection.deselect(); | ||||
|                     }, | ||||
|                     taskIndex: taskIndex | ||||
|                 }); | ||||
|             }; | ||||
|  | ||||
|             // Expose a check for current selection state | ||||
|             $scope.isSelected = function (taskIndex) { | ||||
|                 return ($scope.selection.get() || {}).taskIndex === | ||||
|                     taskIndex; | ||||
|             }; | ||||
|  | ||||
|             // Expose a view-level selection proxy | ||||
|             $scope.selection.proxy({ | ||||
|                 addTask: function () { | ||||
|                     dialogService.getUserInput(NEW_TASK_FORM, {}) | ||||
|                         .then(addNewTask); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return TodoController; | ||||
| }); | ||||
							
								
								
									
										19
									
								
								tutorials/todo/todo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tutorials/todo/todo.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| define(function () { | ||||
|     return function todoPlugin(mct) { | ||||
|         var todoType = new mct.Type({ | ||||
|             metadata: { | ||||
|                 label: "To-Do List", | ||||
|                 glyph: "2", | ||||
|                 description: "A list of things that need to be done." | ||||
|             }, | ||||
|             initialize: function (model) { | ||||
|                 model.tasks = []; | ||||
|             }, | ||||
|             creatable: true | ||||
|         }); | ||||
|  | ||||
|         mct.type('example.todo', todoType); | ||||
|  | ||||
|         return mct; | ||||
|     }; | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user