Reusable Accessible Mapping Platform

API Docs for: 5.0.0
Show:

File: src\js\RAMP\Modules\layerItem.js

  1. /* global define, tmpl, $, console */
  2.  
  3. /**
  4. * @module RAMP
  5. * @submodule FilterManager
  6. * @main FilterManager
  7. */
  8.  
  9. /**
  10. * Create a layer item for each map layer to be displayed in the layer selector. Allows for dynamic changing of the layer item state.
  11. *
  12. * ####Imports RAMP Modules:
  13. * {{#crossLink "TmplHelper"}}{{/crossLink}}
  14. * {{#crossLink "TmplUtil"}}{{/crossLink}}
  15. * {{#crossLink "Array"}}{{/crossLink}}
  16. * {{#crossLink "Dictionary"}}{{/crossLink}}
  17. *
  18. *
  19. * ####Uses RAMP Templates:
  20. * {{#crossLink "templates/layer_selector_template.json"}}{{/crossLink}}
  21. *
  22. * @class LayerItem
  23. * @constructor
  24. * @uses dojo/Evented
  25. * @uses dojo/_base/declare
  26. * @uses dojo/lang
  27. *
  28. * @param {Object} config a config definition of the layer
  29. * @param {Object} [options] Additional options
  30. *
  31. * @param {String} [options.state] Specifies the initial state of the LyerItem; must be one of the `LayerItem.state` defaults
  32. * @param {String} [options.type] Specifies type of this LayerItem and the name of the layer item template to use
  33. *
  34. * @param {Object} [options.stateMatrix] additional state matrix records to be mixed into the default
  35. * @param {Object} [options.transitionMatrix] additional state transition matrix records to be mixed into the default
  36. *
  37. * @return {LayerItem} A control object representing a layer allowing to dynamically change its state.
  38. */
  39.  
  40. define([
  41. "dojo/Evented", "dojo/_base/declare", "dojo/_base/lang",
  42.  
  43. /* Text */
  44. "dojo/text!./templates/layer_selector_template.json",
  45.  
  46. /* Util */
  47. "utils/tmplHelper", "utils/tmplUtil", "utils/array", "utils/dictionary"
  48. ],
  49. function (
  50. Evented, declare, lang,
  51. layer_selector_template,
  52. TmplHelper, TmplUtil, UtilArray, UtilDict
  53. ) {
  54. "use strict";
  55.  
  56. var LayerItem,
  57. ALL_STATES_CLASS;
  58.  
  59. LayerItem = declare([Evented], {
  60. constructor: function (config, options) {
  61. // declare individual properties inside the constructor: http://dojotoolkit.org/reference-guide/1.9/dojo/_base/declare.html#id6
  62. lang.mixin(this,
  63. {
  64. /**
  65. * Layer id. Upon initialization, `id` can be overwritten by `config.id` value.
  66. *
  67. * @property id
  68. * @type String
  69. * @default null
  70. */
  71. id: null,
  72.  
  73. /**
  74. * A node of the LayerItem.
  75. *
  76. * @property node
  77. * @type JObject
  78. * @default null
  79. */
  80. node: null,
  81.  
  82. /**
  83. * A copy of the layer config supplied during LayerItem creation; is set to `config` value.
  84. *
  85. * @property _config
  86. * @private
  87. * @type Object
  88. * @default null
  89. */
  90. _config: null,
  91.  
  92. /**
  93. * A node of the image container.
  94. *
  95. * @property _imageContainerNode
  96. * @private
  97. * @type JObject
  98. * @default null
  99. */
  100. _imageContainerNode: null,
  101.  
  102. /**
  103. * A node of the layer display name.
  104. *
  105. * @property _displayNameNode
  106. * @private
  107. * @type JObject
  108. * @default null
  109. */
  110. _displayNameNode: null,
  111.  
  112. /**
  113. * A node of the layer controls.
  114. *
  115. * @property _controlsNode
  116. * @private
  117. * @type JObject
  118. * @default null
  119. */
  120. _controlsNode: null,
  121.  
  122. /**
  123. * A node of the layer toggles.
  124. *
  125. * @property _togglesNode
  126. * @private
  127. * @type JObject
  128. * @default null
  129. */
  130. _togglesNode: null,
  131.  
  132. /**
  133. * A dictionary of control nodes available for this layer.
  134. *
  135. * @property _controlStore
  136. * @private
  137. * @type Object
  138. * @default {}
  139. */
  140. _controlStore: {},
  141.  
  142. /**
  143. * A dictionary of toggle nodes available for this layer.
  144. *
  145. * @property _toggleStore
  146. * @private
  147. * @type Object
  148. * @default {}
  149. */
  150. _toggleStore: {},
  151.  
  152. /**
  153. * A dictionary of notice nodes available for this layer.
  154. *
  155. * @property _noticeStore
  156. * @private
  157. * @type Object
  158. * @default {}
  159. */
  160. _noticeStore: {},
  161.  
  162. /**
  163. * Templates to be used in construction of the layer nodes.
  164. *
  165. * @property templates
  166. * @type Object
  167. * @default layer_selector_template.json
  168. */
  169. templates: JSON.parse(TmplHelper.stringifyTemplate(layer_selector_template)),
  170.  
  171. /**
  172. * State of this LayerItem; can be overwritten by `options.state`.
  173. *
  174. * @property state
  175. * @type String
  176. * @default LayerItem.state.DEFAULT
  177. */
  178. state: LayerItem.state.DEFAULT,
  179.  
  180. /**
  181. * Specifies type of this LayerItem and the name of the layer item template to use; can be overwritten by `options.type`.
  182. *
  183. * @property type
  184. * @type String
  185. * @default null
  186. */
  187. type: null
  188. },
  189. options,
  190. {
  191. id: config.id,
  192.  
  193. _config: config,
  194.  
  195. /**
  196. * Specifies a state matrix for this particular LayerItem. The default is mixed with `options.stateMatrix` upon initialization.
  197. * The state matrix prescribes what controls, toggles, and notices are present in specific states.
  198. *
  199. * @property stateMatrix
  200. * @type Object
  201. * @default LayerItem.stateMatrix
  202. */
  203. stateMatrix: lang.mixin(
  204. lang.clone(LayerItem.stateMatrix),
  205. options.stateMatrix
  206. ),
  207.  
  208. /**
  209. * Specifies a state transition matrix for this particular LayerItem. The default is mixed with `options.transitionMatrix` upon initialization.
  210. * The state transition matrix prescribes the direction of state changes for specific states.
  211. *
  212. * @property transitionMatrix
  213. * @type Object
  214. * @default LayerItem.transitionMatrix
  215. */
  216. transitionMatrix: lang.mixin(
  217. lang.clone(LayerItem.transitionMatrix),
  218. options.transitionMatrix
  219. )
  220. }
  221. );
  222.  
  223. this.node = $(this._template(this.type, this._config));
  224. this._imageBoxNode = this.node.find(".layer-details > div:first");
  225. this._displayNameNode = this.node.find(".layer-name > span");
  226. this._controlsNode = this.node.find(".layer-controls-group");
  227. this._togglesNode = this.node.find(".layer-checkboxes");
  228. this._noticesNode = this.node.find(".layer-notices");
  229.  
  230. this._generateParts("controls", "layer_control_", this._controlStore);
  231. this._generateParts("toggles", "layer_toggle_", this._toggleStore);
  232. this._generateParts("notices", "layer_notice_", this._noticeStore);
  233.  
  234. this.setState(this.state, null, true);
  235.  
  236. console.debug("-->", this.state, options);
  237. },
  238.  
  239. /**
  240. * Generates control, toggle, and notice nodes for the LayerItem object to be used in different states.
  241. *
  242. * @param {String} partType name of the part type - "controls", "toggles", or "notices"
  243. * @param {String} templateKey a template name prefix for the template parts
  244. * @param {Object} partStore a dictionary to store generated nodes
  245. * @method _generateParts
  246. * @private
  247. */
  248. _generateParts: function (partType, templateKey, partStore) {
  249. var that = this,
  250.  
  251. stateKey,
  252. partKeys = [],
  253. part;
  254.  
  255. Object
  256. .getOwnPropertyNames(LayerItem.state)
  257. .forEach(function (s) {
  258. stateKey = LayerItem.state[s];
  259. partKeys = partKeys.concat(that.stateMatrix[stateKey][partType]);
  260. });
  261.  
  262. partKeys = UtilArray.unique(partKeys);
  263.  
  264. partKeys.forEach(function (pKey) {
  265. part = that._generatePart(templateKey, pKey);
  266.  
  267. partStore[pKey] = (part);
  268. });
  269. },
  270.  
  271. /**
  272. * Generates a control given the template name and additional data object to pass to the template engine.
  273. *
  274. * @param {String} templateKey a template name prefix for the template parts
  275. * @param {String} pKey name of the template to build
  276. * @param {Object} [data] optional data to pass to template engine; used to update strings on notice objects
  277. * @method _generatePart
  278. * @private
  279. * @return Created part node
  280. */
  281. _generatePart: function (templateKey, pKey, data) {
  282. var part = $(this._template(templateKey + pKey,
  283. {
  284. id: this.id,
  285. config: this._config,
  286. nameKey: pKey,
  287. data: data
  288. }
  289. ));
  290.  
  291. return part;
  292. },
  293.  
  294. /**
  295. * Changes the state of the LayerItem and update its UI representation.
  296. *
  297. * @param {String} state name of the state to be set
  298. * @param {Object} [options] additional options
  299. * @param {Object} [options.notices] custom information to be displayed in a notice for the current state if needed; object structure is not set; look at the appropriate template;
  300. * @example
  301. * {
  302. * notices: {
  303. * error: {
  304. * message: "I'm error"
  305. * },
  306. * scale: {
  307. * message: "All your base are belong to us"
  308. * }
  309. * }
  310. * }
  311. * @param {Boolean} force if `true`, forces the state change even if it's no allowed by the `transitionMatrix`
  312. * @method setState
  313. */
  314. setState: function (state, options, force) {
  315. var allowedStates = this.transitionMatrix[this.state],
  316. notice,
  317.  
  318. that = this;
  319.  
  320. if (allowedStates.indexOf(state) !== -1 || force) {
  321.  
  322. this.state = state;
  323. //lang.mixin(this, options);
  324.  
  325. // set state class on the layerItem root node
  326. this.node
  327. .removeClass(ALL_STATES_CLASS)
  328. .addClass(this.state);
  329.  
  330. // regenerate notice controls if extra data is provided
  331. if (options) {
  332. if (options.notices) {
  333.  
  334. UtilDict.forEachEntry(options.notices, function (pKey, data) {
  335. notice = that._generatePart("layer_notice_", pKey, data);
  336.  
  337. that._noticeStore[pKey] = (notice);
  338. });
  339. }
  340. }
  341.  
  342. this._setParts("controls", this._controlStore, this._controlsNode);
  343. this._setParts("toggles", this._toggleStore, this._togglesNode);
  344. this._setParts("notices", this._noticeStore, this._noticesNode);
  345.  
  346. switch (this.state) {
  347. case LayerItem.state.DEFAULT:
  348. console.log(LayerItem.state.DEFAULT);
  349. break;
  350.  
  351. case LayerItem.state.LOADING:
  352. this.node.attr("aria-busy", true); // indicates that the region is loading
  353.  
  354. console.log(LayerItem.state.LOADING);
  355. break;
  356.  
  357. case LayerItem.state.LOADED:
  358. this.node.attr("aria-busy", false); // indicates that the loading is complete
  359. this.setState(LayerItem.state.DEFAULT);
  360.  
  361. console.log(LayerItem.state.LOADED);
  362. break;
  363.  
  364. case LayerItem.state.ERROR:
  365. console.log(LayerItem.state.ERROR);
  366. break;
  367.  
  368. case LayerItem.state.OFF_SCALE:
  369. console.log(LayerItem.state.OFF_SCALE);
  370. break;
  371.  
  372. default:
  373. break;
  374. }
  375.  
  376. return true;
  377. } else {
  378. return false;
  379. }
  380. },
  381.  
  382. /**
  383. * Sets controls, toggles, and notices of the LayerItem according to its state.
  384. *
  385. * @param {String} partType name of the part type - "controls", "toggles", or "notices"
  386. * @param {Object} partStore a dictionary to store generated nodes
  387. * @param {JObject} target a jQuery node where the nodes should be appended
  388. * @method _setParts
  389. * @private
  390. */
  391. _setParts: function (partType, partStore, target) {
  392. var controls = [];
  393.  
  394. this.stateMatrix[this.state][partType].forEach(function (pKey) {
  395. controls.push(partStore[pKey]);
  396. });
  397.  
  398. target
  399. .empty()
  400. .append(controls);
  401. },
  402.  
  403. /**
  404. * Populates a template specified by the key with the supplied data.
  405. *
  406. * @param {String} key template name
  407. * @param {Object} data data to be inserted into the template
  408. * @method _template
  409. * @private
  410. * @return {String} a string template filled with supplied data
  411. */
  412. _template: function (key, data) {
  413. tmpl.cache = {};
  414. tmpl.templates = this.templates;
  415.  
  416. data = data || {};
  417. data.fn = TmplUtil;
  418.  
  419. return tmpl(key, data);
  420. }
  421. });
  422.  
  423. lang.mixin(LayerItem,
  424. {
  425. /**
  426. * A default collection of possible LayerItem states.
  427. *
  428. * @property LayerItem.state
  429. * @static
  430. * @type Object
  431. * @example
  432. * state: {
  433. * DEFAULT: "layer-state-default",
  434. * LOADING: "layer-state-loading",
  435. * LOADED: "layer-state-loaded",
  436. * UPDATING: "layer-state-updating",
  437. * ERROR: "layer-state-error",
  438. * OFF_SCALE: "layer-state-off-scale"
  439. * }
  440. */
  441. state: {
  442. DEFAULT: "layer-state-default",
  443. LOADING: "layer-state-loading",
  444. LOADED: "layer-state-loaded",
  445. UPDATING: "layer-state-updating",
  446. ERROR: "layer-state-error",
  447. OFF_SCALE: "layer-state-off-scale"
  448. },
  449.  
  450. /**
  451. * A default collection of possible LayerItem controls.
  452. *
  453. * @property LayerItem.controls
  454. * @static
  455. * @type Object
  456. * @example
  457. * controls: {
  458. * METADATA: "metadata",
  459. * SETTINGS: "settings",
  460. * LOADING: "loading",
  461. * REMOVE: "remove",
  462. * RELOAD: "reload",
  463. * ERROR: "error"
  464. * }
  465. */
  466. controls: {
  467. METADATA: "metadata",
  468. SETTINGS: "settings",
  469. LOADING: "loading",
  470. REMOVE: "remove",
  471. RELOAD: "reload",
  472. ERROR: "error"
  473. },
  474.  
  475. /**
  476. * A default collection of possible LayerItem toggles.
  477. *
  478. * @property LayerItem.toggles
  479. * @static
  480. * @type Object
  481. * @example
  482. * toggles: {
  483. * EYE: "eye",
  484. * BOX: "box",
  485. * RELOAD: "reload",
  486. * HIDE: "hide",
  487. * ZOOM: "zoom",
  488. * PLACEHOLDER: "placeholder"
  489. * }
  490. */
  491. toggles: {
  492. EYE: "eye",
  493. BOX: "box",
  494. RELOAD: "reload",
  495. HIDE: "hide",
  496. ZOOM: "zoom",
  497. PLACEHOLDER: "placeholder"
  498. },
  499.  
  500. /**
  501. * A default collection of possible LayerItem notices.
  502. *
  503. * @property LayerItem.notices
  504. * @static
  505. * @type Object
  506. * @example
  507. * notices: {
  508. * SCALE: "scale"
  509. * ERROR: "error",
  510. * UPDATE: "update"
  511. * }
  512. */
  513. notices: {
  514. SCALE: "scale",
  515. ERROR: "error",
  516. UPDATE: "update"
  517. },
  518.  
  519. /**
  520. * A default state matrix specifying what controls are active in which state.
  521. *
  522. * @property LayerItem.stateMatrix
  523. * @static
  524. * @type Object
  525. * @example
  526. * DEFAULT: {
  527. * controls: [
  528. * LayerItem.controls.METADATA,
  529. * LayerItem.controls.SETTINGS
  530. * ],
  531. * toggles: [
  532. * LayerItem.toggles.EYE,
  533. * LayerItem.toggles.BOX
  534. * ],
  535. * notices: []
  536. * },
  537. *
  538. * LOADING: {
  539. * controls: [
  540. * LayerItem.controls.LOADING
  541. * ],
  542. * toggles: [],
  543. * notices: []
  544. * },
  545. *
  546. * LOADED: {
  547. * controls: [],
  548. * toggles: [],
  549. * notices: []
  550. * },
  551. * DEFAULT: {
  552. * controls: [
  553. * LayerItem.controls.METADATA,
  554. * LayerItem.controls.SETTINGS
  555. * ],
  556. * toggles: [
  557. * LayerItem.toggles.EYE,
  558. * LayerItem.toggles.BOX
  559. * ],
  560. * notices: [
  561. * LayerItem.notices.UPDATE
  562. * ]
  563. * },
  564. *
  565. * ERROR: {
  566. * controls: [
  567. * LayerItem.controls.RELOAD,
  568. * LayerItem.controls.REMOVE
  569. * ],
  570. * toggles: [],
  571. * notices: [
  572. * LayerItem.notices.ERROR
  573. * ]
  574. * },
  575. *
  576. * OFF_SCALE: {
  577. * controls: [
  578. * LayerItem.controls.METADATA,
  579. * LayerItem.controls.SETTINGS
  580. * ],
  581. * toggles: [
  582. * LayerItem.toggles.ZOOM,
  583. * LayerItem.toggles.EYE,
  584. * LayerItem.toggles.BOX
  585. * ],
  586. * notices: [
  587. * LayerItem.notices.SCALE
  588. * ]
  589. * }
  590. */
  591. stateMatrix: {},
  592.  
  593. /**
  594. * A default state transition matrix specifying to what state the LayerItem can transition.
  595. *
  596. * @property LayerItem.transitionMatrix
  597. * @static
  598. * @type Object
  599. * @example
  600. * DEFAULT: [
  601. * LayerItem.state.ERROR,
  602. * LayerItem.state.OFF_SCALE,
  603. * LayerItem.state.UPDATING
  604. * ],
  605. * LOADED: [
  606. * LayerItem.state.DEFAULT
  607. * ],
  608. * LOADING: [
  609. * LayerItem.state.LOADED
  610. * ],
  611. * UPDATING: [
  612. * LayerItem.state.ERROR,
  613. * LayerItem.state.OFF_SCALE,
  614. * LayerItem.state.DEFAULT
  615. * ],
  616. * ERROR: [
  617. * LayerItem.state.LOADING
  618. * ],
  619. * OFF_SCALE: [
  620. * LayerItem.state.ERROR,
  621. * LayerItem.state.DEFAULT,
  622. * LayerItem.state.UPDATING
  623. * ]
  624. *
  625. */
  626. transitionMatrix: {}
  627. }
  628. );
  629.  
  630. // setting defaults for state matrix
  631. LayerItem.stateMatrix[LayerItem.state.DEFAULT] = {
  632. controls: [
  633. LayerItem.controls.METADATA,
  634. LayerItem.controls.SETTINGS
  635. ],
  636. toggles: [
  637. LayerItem.toggles.EYE,
  638. LayerItem.toggles.BOX
  639. ],
  640. notices: []
  641. };
  642.  
  643. LayerItem.stateMatrix[LayerItem.state.LOADING] = {
  644. controls: [
  645. LayerItem.controls.LOADING
  646. ],
  647. toggles: [],
  648. notices: []
  649. };
  650.  
  651. LayerItem.stateMatrix[LayerItem.state.LOADED] = {
  652. controls: [],
  653. toggles: [],
  654. notices: []
  655. };
  656.  
  657. LayerItem.stateMatrix[LayerItem.state.UPDATING] = {
  658. controls: [
  659. LayerItem.controls.METADATA,
  660. LayerItem.controls.SETTINGS
  661. ],
  662. toggles: [
  663. LayerItem.toggles.EYE,
  664. LayerItem.toggles.BOX
  665. ],
  666. notices: [
  667. LayerItem.notices.UPDATE
  668. ]
  669. };
  670.  
  671. LayerItem.stateMatrix[LayerItem.state.ERROR] = {
  672. controls: [
  673. LayerItem.controls.RELOAD,
  674. LayerItem.controls.REMOVE
  675. ],
  676. toggles: [],
  677. notices: [
  678. LayerItem.notices.ERROR
  679. ]
  680. };
  681.  
  682. LayerItem.stateMatrix[LayerItem.state.OFF_SCALE] = {
  683. controls: [
  684. LayerItem.controls.METADATA,
  685. LayerItem.controls.SETTINGS
  686. ],
  687. toggles: [
  688. LayerItem.toggles.ZOOM,
  689. LayerItem.toggles.EYE,
  690. LayerItem.toggles.BOX
  691. ],
  692. notices: [
  693. LayerItem.notices.SCALE
  694. ]
  695. };
  696.  
  697. // setting defaults for transition matrix
  698. LayerItem.transitionMatrix[LayerItem.state.DEFAULT] = [
  699. LayerItem.state.ERROR,
  700. LayerItem.state.OFF_SCALE,
  701. LayerItem.state.UPDATING
  702. ];
  703.  
  704. LayerItem.transitionMatrix[LayerItem.state.LOADING] = [
  705. LayerItem.state.LOADED,
  706. LayerItem.state.ERROR,
  707. LayerItem.state.UPDATING
  708. ];
  709.  
  710. LayerItem.transitionMatrix[LayerItem.state.LOADED] = [
  711. LayerItem.state.DEFAULT
  712. ];
  713.  
  714. LayerItem.transitionMatrix[LayerItem.state.UPDATING] = [
  715. LayerItem.state.LOADED,
  716. LayerItem.state.ERROR
  717. ];
  718.  
  719. LayerItem.transitionMatrix[LayerItem.state.ERROR] = [
  720. LayerItem.state.LOADING
  721. ];
  722.  
  723. LayerItem.transitionMatrix[LayerItem.state.OFF_SCALE] = [
  724. LayerItem.state.ERROR,
  725. LayerItem.state.DEFAULT,
  726. LayerItem.state.UPDATING
  727. ];
  728.  
  729. // a string with all possible layerItem state CSS classes joined by " "; used to clear any CSS state class from the node
  730. ALL_STATES_CLASS =
  731. Object
  732. .getOwnPropertyNames(LayerItem.state)
  733. .map(function (key) { return LayerItem.state[key]; })
  734. .join(" ");
  735.  
  736. return LayerItem;
  737. });