model.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. "use strict";
  2. // Copyright 2012 United States Government, as represented by the Secretary of Defense, Under
  3. // Secretary of Defense (Personnel & Readiness).
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed under the License
  11. // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  12. // or implied. See the License for the specific language governing permissions and limitations under
  13. // the License.
  14. /// @module vwf/kernel/model
  15. /// @requires vwf/model
  16. define( [ "module", "vwf/model" ], function( module, model ) {
  17. return model.load( module, {
  18. // == Module Definition ====================================================================
  19. initialize: function() {
  20. this.state.enabled = true; // kernel reentry allowed?
  21. this.state.blocked = false; // kernel reentry attempted?
  22. },
  23. /// Allow kernel reentry from the drivers.
  24. enable: function() {
  25. this.state.enabled = true;
  26. this.state.blocked = false;
  27. },
  28. /// Prevent kernel reentry from the drivers.
  29. disable: function() {
  30. this.state.enabled = false;
  31. this.state.blocked = false;
  32. },
  33. /// Indicate if kernel reentry is currently enabled.
  34. enabled: function() {
  35. return this.state.enabled;
  36. },
  37. /// Indicate if kernel reentry is currently disabled.
  38. disabled: function() {
  39. return ! this.state.enabled;
  40. },
  41. /// Indicate if a driver attempted to call back into the kernel while reentry was disabled,
  42. /// and clear the *blocked* flag.
  43. blocked: function() {
  44. var blocked = this.state.blocked;
  45. this.state.blocked = false;
  46. return blocked;
  47. },
  48. /// Invoke a task and record any async actions that it initiates. After the actions have
  49. /// completed, execute their callbacks, then call a completion callback.
  50. ///
  51. /// @param {Function} task
  52. /// The task to execute and monitor for async actions. `task` is invoked with no
  53. /// arguments.
  54. /// @param {Function} callback
  55. /// Invoked after the async actions have completed.
  56. /// @param {Object} [that]
  57. /// The `this` value for the `task` and `callback` functions.
  58. capturingAsyncs: function( task, callback, that ) {
  59. // Create an array to capture the callbacks and results from async actions. When
  60. // `this.state.asyncs` exists, async actions hand off their callbacks to `asyncs.defer`.
  61. var asyncs = this.state.asyncs = [];
  62. asyncs.defer = defer;
  63. asyncs.completed = 0;
  64. asyncs.callback = callback;
  65. asyncs.that = that;
  66. // Invoke the task.
  67. task.call( that );
  68. // Detach the array from `this.state.asyncs` to stop capturing async actions.
  69. this.state.asyncs = undefined;
  70. // If there were no async actions, call the completion callback immediately.
  71. if ( asyncs.completed == asyncs.length ) {
  72. asyncs.callback.call( asyncs.that );
  73. }
  74. /// The `this.state.asyncs` array `defer` method.
  75. ///
  76. /// Wrap a callback function with a new function that will defer the original callback
  77. /// until a collection of actions have completed, then call the deferred callbacks
  78. /// followed by a completion callback.
  79. function defer( callback /* result */ ) {
  80. var self = this;
  81. // Save the original callback. The wrapping callback will save the result here when
  82. // received.
  83. var deferred = {
  84. callback: callback /* result */,
  85. result: undefined
  86. };
  87. this.push( deferred );
  88. // Return a new callback in place of the original. Record the result, then if all
  89. // actions have completed, call the original callbacks, then call the completion
  90. // function.
  91. return function( result ) {
  92. deferred.result = result;
  93. if ( ++self.completed == self.length ) {
  94. // Call the original callbacks.
  95. self.forEach( function( deferred ) {
  96. deferred.callback && deferred.callback( deferred.result );
  97. } );
  98. // Call the completion callback.
  99. if ( self.callback ) {
  100. self.callback.call( self.that );
  101. }
  102. }
  103. }
  104. };
  105. },
  106. }, function( modelFunctionName ) {
  107. // == Model API ============================================================================
  108. // The kernel bypasses vwf/kernel/model and calls directly into the first driver stage.
  109. return undefined;
  110. }, function( kernelFunctionName ) {
  111. // == Kernel API ===========================================================================
  112. switch ( kernelFunctionName ) {
  113. // -- Read-write functions -------------------------------------------------------------
  114. // TODO: setState
  115. // TODO: getState
  116. // TODO: hashState
  117. case "createNode":
  118. return function( nodeComponent, nodeAnnotation, baseURI, when, callback /* nodeID */ ) {
  119. // Interpret `createNode( nodeComponent, when, callback )` as
  120. // `createNode( nodeComponent, undefined, undefined, when, callback )` and
  121. // `createNode( nodeComponent, nodeAnnotation, when, callback )` as
  122. // `createNode( nodeComponent, nodeAnnotation, undefined, when, callback )`.
  123. // `nodeAnnotation` was added in 0.6.12, and `baseURI` was added in 0.6.25.
  124. if ( typeof baseURI == "function" || baseURI instanceof Function ) {
  125. callback = baseURI;
  126. when = nodeAnnotation;
  127. baseURI = undefined;
  128. nodeAnnotation = undefined;
  129. } else if ( typeof when == "function" || when instanceof Function ) {
  130. callback = when;
  131. when = baseURI;
  132. baseURI = undefined;
  133. }
  134. // Make the call.
  135. if ( this.state.enabled ) {
  136. if ( when === undefined ) {
  137. if ( this.state.asyncs ) {
  138. callback = this.state.asyncs.defer( callback /* nodeID */ );
  139. }
  140. return this.kernel[kernelFunctionName]( nodeComponent, nodeAnnotation, function( nodeID ) {
  141. callback && callback( nodeID );
  142. } );
  143. } else {
  144. this.kernel.plan( undefined, kernelFunctionName, undefined,
  145. [ nodeComponent, nodeAnnotation ], when, callback /* result */ );
  146. }
  147. } else {
  148. this.state.blocked = true;
  149. }
  150. };
  151. case "deleteNode":
  152. return function( nodeID, when, callback ) {
  153. if ( this.state.enabled ) {
  154. if ( when === undefined ) {
  155. return this.kernel[kernelFunctionName]( nodeID );
  156. } else {
  157. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  158. undefined, when, callback /* result */ );
  159. }
  160. } else {
  161. this.state.blocked = true;
  162. }
  163. };
  164. // TODO: setNode
  165. // TODO: getNode
  166. case "createChild":
  167. return function( nodeID, childName, childComponent, childURI, when, callback /* childID */ ) {
  168. if ( this.state.enabled ) {
  169. if ( when === undefined ) {
  170. if ( this.state.asyncs ) {
  171. callback = this.state.asyncs.defer( callback /* childID */ );
  172. }
  173. return this.kernel[kernelFunctionName]( nodeID, childName, childComponent, childURI, function( childID ) {
  174. callback && callback( childID );
  175. } );
  176. } else {
  177. this.kernel.plan( nodeID, kernelFunctionName, childName,
  178. [ childComponent, childURI ], when, callback /* result */ );
  179. }
  180. } else {
  181. this.state.blocked = true;
  182. }
  183. };
  184. case "deleteChild":
  185. return function( nodeID, childName, when, callback ) {
  186. if ( this.state.enabled ) {
  187. if ( when === undefined ) {
  188. return this.kernel[kernelFunctionName]( nodeID, childName );
  189. } else {
  190. this.kernel.plan( nodeID, kernelFunctionName, childName,
  191. undefined, when, callback /* result */ );
  192. }
  193. } else {
  194. this.state.blocked = true;
  195. }
  196. };
  197. case "addChild":
  198. return function( nodeID, childID, childName, when, callback ) {
  199. if ( this.state.enabled ) {
  200. if ( when === undefined ) {
  201. return this.kernel[kernelFunctionName]( nodeID, childID, childName );
  202. } else {
  203. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  204. [ childID, childName ], when, callback /* result */ ); // TODO: swap childID & childName?
  205. }
  206. } else {
  207. this.state.blocked = true;
  208. }
  209. };
  210. case "removeChild":
  211. return function( nodeID, childID, when, callback ) {
  212. if ( this.state.enabled ) {
  213. if ( when === undefined ) {
  214. return this.kernel[kernelFunctionName]( nodeID, childID );
  215. } else {
  216. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  217. [ childID ], when, callback /* result */ ); // TODO: swap childID & childName?
  218. }
  219. } else {
  220. this.state.blocked = true;
  221. }
  222. };
  223. case "setProperties":
  224. return function( nodeID, properties, when, callback ) {
  225. if ( this.state.enabled ) {
  226. if ( when === undefined ) {
  227. return this.kernel[kernelFunctionName]( nodeID, properties );
  228. } else {
  229. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  230. [ properties ], when, callback /* result */ );
  231. }
  232. } else {
  233. this.state.blocked = true;
  234. }
  235. };
  236. case "getProperties":
  237. return function( nodeID, when, callback ) {
  238. if ( this.state.enabled ) {
  239. if ( when === undefined ) {
  240. return this.kernel[kernelFunctionName]( nodeID );
  241. } else {
  242. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  243. undefined, when, callback /* result */ );
  244. }
  245. } else {
  246. this.state.blocked = true;
  247. }
  248. };
  249. case "createProperty":
  250. return function( nodeID, propertyName, propertyValue, propertyGet, propertySet, when, callback ) {
  251. if ( this.state.enabled ) {
  252. if ( when === undefined ) {
  253. return this.kernel[kernelFunctionName]( nodeID, propertyName, propertyValue, propertyGet, propertySet );
  254. } else {
  255. this.kernel.plan( nodeID, kernelFunctionName, propertyName,
  256. [ propertyValue, propertyGet, propertySet ], when, callback /* result */ ); // TODO: { value: propertyValue, get: propertyGet, set: propertySet } ? -- vwf.receive() needs to parse
  257. }
  258. } else {
  259. this.state.blocked = true;
  260. }
  261. };
  262. // TODO: deleteProperty
  263. case "setProperty":
  264. return function( nodeID, propertyName, propertyValue, when, callback ) {
  265. if ( this.state.enabled ) {
  266. if ( when === undefined ) {
  267. return this.kernel[kernelFunctionName]( nodeID, propertyName, propertyValue );
  268. } else {
  269. this.kernel.plan( nodeID, kernelFunctionName, propertyName,
  270. [ propertyValue ], when, callback /* result */ );
  271. }
  272. } else {
  273. this.state.blocked = true;
  274. }
  275. };
  276. case "getProperty":
  277. return function( nodeID, propertyName, when, callback ) {
  278. if ( this.state.enabled ) {
  279. if ( when === undefined ) {
  280. return this.kernel[kernelFunctionName]( nodeID, propertyName );
  281. } else {
  282. this.kernel.plan( nodeID, kernelFunctionName, propertyName,
  283. undefined, when, callback /* result */ );
  284. }
  285. } else {
  286. this.state.blocked = true;
  287. }
  288. };
  289. case "createMethod":
  290. return function( nodeID, methodName, methodParameters, methodBody, when, callback ) {
  291. if ( this.state.enabled ) {
  292. if ( when === undefined ) {
  293. return this.kernel[kernelFunctionName]( nodeID, methodName, methodParameters, methodBody );
  294. } else {
  295. this.kernel.plan( nodeID, kernelFunctionName, methodName,
  296. [ methodParameters, methodBody ], when, callback /* result */ ); // TODO: { parameters: methodParameters, body: methodBody } ? -- vwf.receive() needs to parse
  297. }
  298. } else {
  299. this.state.blocked = true;
  300. }
  301. };
  302. // TODO: deleteMethod
  303. case "setMethod":
  304. return function( nodeID, methodName, methodHandler, when, callback ) {
  305. if ( this.state.enabled ) {
  306. if ( when === undefined ) {
  307. return this.kernel[kernelFunctionName]( nodeID, methodName, methodHandler );
  308. } else {
  309. this.kernel.plan( nodeID, kernelFunctionName, methodName,
  310. [ methodHandler ], when, callback /* result */ );
  311. }
  312. } else {
  313. this.state.blocked = true;
  314. }
  315. };
  316. case "getMethod":
  317. return function( nodeID, methodName, when, callback ) {
  318. if ( this.state.enabled ) {
  319. if ( when === undefined ) {
  320. return this.kernel[kernelFunctionName]( nodeID, methodName );
  321. } else {
  322. this.kernel.plan( nodeID, kernelFunctionName, methodName,
  323. undefined, when, callback /* result */ );
  324. }
  325. } else {
  326. this.state.blocked = true;
  327. }
  328. };
  329. case "callMethod":
  330. return function( nodeID, methodName, methodParameters, when, callback ) {
  331. if ( this.state.enabled ) {
  332. if ( when === undefined ) {
  333. return this.kernel[kernelFunctionName]( nodeID, methodName, methodParameters );
  334. } else {
  335. this.kernel.plan( nodeID, kernelFunctionName, methodName,
  336. [ methodParameters ], when, callback /* result */ );
  337. }
  338. } else {
  339. this.state.blocked = true;
  340. }
  341. };
  342. case "createEvent":
  343. return function( nodeID, eventName, eventParameters, when, callback ) {
  344. if ( this.state.enabled ) {
  345. if ( when === undefined ) {
  346. return this.kernel[kernelFunctionName]( nodeID, eventName, eventParameters );
  347. } else {
  348. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  349. [ eventParameters ], when, callback /* result */ );
  350. }
  351. } else {
  352. this.state.blocked = true;
  353. }
  354. };
  355. // TODO: deleteEvent
  356. case "addEventListener":
  357. return function( nodeID, eventName, eventHandler, eventContextID, eventPhases, when, callback ) {
  358. if ( this.state.enabled ) {
  359. if ( when === undefined ) {
  360. return this.kernel[kernelFunctionName]( nodeID, eventName, eventHandler, eventContextID, eventPhases );
  361. } else {
  362. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  363. [ eventHandler, eventContextID, eventPhases ], when, callback /* result */ );
  364. }
  365. } else {
  366. this.state.blocked = true;
  367. }
  368. };
  369. case "removeEventListener":
  370. return function( nodeID, eventName, eventListenerID, when, callback ) {
  371. if ( this.state.enabled ) {
  372. if ( when === undefined ) {
  373. return this.kernel[kernelFunctionName]( nodeID, eventName, eventListenerID );
  374. } else {
  375. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  376. [ eventListenerID ], when, callback /* result */ );
  377. }
  378. } else {
  379. this.state.blocked = true;
  380. }
  381. };
  382. case "flushEventListeners":
  383. return function( nodeID, eventName, eventContextID, when, callback ) {
  384. if ( this.state.enabled ) {
  385. if ( when === undefined ) {
  386. return this.kernel[kernelFunctionName]( nodeID, eventName, eventContextID );
  387. } else {
  388. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  389. [ eventContextID ], when, callback /* result */ );
  390. }
  391. } else {
  392. this.state.blocked = true;
  393. }
  394. };
  395. case "fireEvent":
  396. return function( nodeID, eventName, eventParameters, when, callback ) {
  397. if ( this.state.enabled ) {
  398. if ( when === undefined ) {
  399. return this.kernel[kernelFunctionName]( nodeID, eventName, eventParameters );
  400. } else {
  401. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  402. [ eventParameters ], when, callback /* result */ );
  403. }
  404. } else {
  405. this.state.blocked = true;
  406. }
  407. };
  408. case "dispatchEvent":
  409. return function( nodeID, eventName, eventParameters, eventNodeParameters, when, callback ) {
  410. if ( this.state.enabled ) {
  411. if ( when === undefined ) {
  412. return this.kernel[kernelFunctionName]( nodeID, eventName, eventParameters, eventNodeParameters );
  413. } else {
  414. this.kernel.plan( nodeID, kernelFunctionName, eventName,
  415. [ eventParameters, eventNodeParameters ], when, callback /* result */ );
  416. }
  417. } else {
  418. this.state.blocked = true;
  419. }
  420. };
  421. case "execute":
  422. return function( nodeID, scriptText, scriptType, when, callback /* result */ ) {
  423. if ( this.state.enabled ) {
  424. if ( when === undefined ) {
  425. if ( this.state.asyncs ) {
  426. callback = this.state.asyncs.defer( callback /* result */ );
  427. }
  428. return this.kernel[kernelFunctionName]( nodeID, scriptText, scriptType, function( result ) {
  429. callback && callback( result );
  430. } );
  431. } else {
  432. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  433. [ scriptText, scriptType ], when, callback /* result */ ); // TODO: { text: scriptText, type: scriptType } ? -- vwf.receive() needs to parse
  434. }
  435. } else {
  436. this.state.blocked = true;
  437. }
  438. };
  439. case "random":
  440. return function( nodeID, when, callback ) {
  441. if ( this.state.enabled ) {
  442. if ( when === undefined ) {
  443. return this.kernel[kernelFunctionName]( nodeID );
  444. } else {
  445. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  446. undefined, when, callback /* result */ );
  447. }
  448. } else {
  449. this.state.blocked = true;
  450. }
  451. };
  452. case "seed":
  453. return function( nodeID, seed, when, callback ) {
  454. if ( this.state.enabled ) {
  455. if ( when === undefined ) {
  456. return this.kernel[kernelFunctionName]( nodeID, seed );
  457. } else {
  458. this.kernel.plan( nodeID, kernelFunctionName, undefined,
  459. [ seed ], when, callback /* result */ );
  460. }
  461. } else {
  462. this.state.blocked = true;
  463. }
  464. };
  465. // -- Read-only functions --------------------------------------------------------------
  466. case "time":
  467. case "client":
  468. case "moniker":
  469. case "application":
  470. case "intrinsics":
  471. case "uri":
  472. case "name":
  473. case "prototype":
  474. case "prototypes":
  475. case "behaviors":
  476. case "ancestors":
  477. case "parent":
  478. case "children":
  479. case "descendants":
  480. case "find":
  481. case "test":
  482. case "findClients":
  483. return function() {
  484. return this.kernel[kernelFunctionName].apply( this.kernel, arguments );
  485. };
  486. }
  487. } );
  488. } );