API Docs for: 0.0.1
Show:

File: src/dialog/dialog.js

  1. "use strict";
  2. /**
  3. * Defines a dialog-panel to display messages.
  4. * Every message that fulfills will get the dialog-content as well as the pressed button as return.
  5. *
  6. *
  7. * <i>Copyright (c) 2014 ITSA - https://github.com/itsa</i>
  8. * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
  9. *
  10. *
  11. * @module dialog
  12. * @class Dialog
  13. * @since 0.0.1
  14. */
  15.  
  16. require('js-ext');
  17. require('polyfill');
  18. require('./css/dialog.css');
  19.  
  20. var NAME = '[dialog]: ',
  21. MESSAGE_LEVELS = {
  22. 'message': 1,
  23. 'warn': 2,
  24. 'error': 3
  25. },
  26. MESSAGE_HASHES = {
  27. 'message': 'messages',
  28. 'warn': 'warnings',
  29. 'error': 'errors'
  30. },
  31. MESSAGE_HASHES_NR = {
  32. 1: 'messages',
  33. 2: 'warnings',
  34. 3: 'errors'
  35. },
  36. FOLLOWUP_DELAY = 150,
  37. createHashMap = require('js-ext/extra/hashmap.js').createMap;
  38.  
  39. module.exports = function (window) {
  40.  
  41. var DOCUMENT = window.document,
  42. Classes = require('js-ext/extra/classes.js'),
  43. UTILS = require('utils'),
  44. later = UTILS.later,
  45. async = UTILS.async,
  46. dialog, Dialog, Event;
  47.  
  48. window._ITSAmodules || Object.protectedProp(window, '_ITSAmodules', createHashMap());
  49.  
  50. /*jshint boss:true */
  51. if (Dialog=window._ITSAmodules.Dialog) {
  52. /*jshint boss:false */
  53. return Dialog; // Dialog was already created
  54. }
  55.  
  56. require('panel')(window);
  57. Event = require('itsa-event');
  58.  
  59. /**
  60. * Model that is passed through to the Panel.
  61. *
  62. * @property model
  63. * @default {
  64. draggable: true
  65. }
  66. * @type Object
  67. * @since 0.0.1
  68. */
  69.  
  70. /**
  71. * Internal property that tells what message-level is currently active.
  72. *
  73. * @property _currentMessageLevel
  74. * @default 0
  75. * @type Number
  76. * @private
  77. * @since 0.0.1
  78. */
  79.  
  80. /**
  81. * Internal hash all queued message with level=1 (*:message)
  82. *
  83. * @property messages
  84. * @default []
  85. * @type Array
  86. * @since 0.0.1
  87. */
  88.  
  89. /**
  90. * Internal hash all queued message with level=2 (*:warn)
  91. *
  92. * @property warnings
  93. * @default []
  94. * @type Array
  95. * @since 0.0.1
  96. */
  97.  
  98. /**
  99. * Internal hash all queued message with level=3 (*:error)
  100. *
  101. * @property errors
  102. * @default []
  103. * @type Array
  104. * @since 0.0.1
  105. */
  106. Dialog = Classes.createClass(function() {
  107. var instance = this;
  108. instance.model = {
  109. draggable: true
  110. };
  111. instance._currentMessageLevel = 0;
  112. instance.messages = [];
  113. instance.warnings = [];
  114. instance.errors = [];
  115. instance.createContainer();
  116. instance.setupListeners();
  117. }, {
  118.  
  119. /**
  120. * Creates a Panel-instance that will be used to display the messages.
  121. * Sets instance.model as panel's model and defines model.callback
  122. * which fulfills the message when a button on the dialog is pressed,
  123. *
  124. * @method createContainer
  125. * @since 0.0.1
  126. */
  127. createContainer: function() {
  128. var instance = this,
  129. model = instance.model;
  130. model.callback = function(buttonNode) {
  131. var containerNode = DOCUMENT.createElement('div'),
  132. contentNode = instance.panel.getElement('>div[is="content"]'),
  133. messagePromise = model.messagePromise;
  134. containerNode = contentNode.cloneNode(true);
  135. // now append a copy of the buttonNode:
  136. containerNode.append(buttonNode.getOuterHTML());
  137. messagePromise.fulfill(containerNode);
  138. // we can safely remove the newly created container-node: the vdom holds it for 1 minute
  139. containerNode.remove();
  140. };
  141. instance.panel = DOCUMENT.createPanel(model);
  142. },
  143.  
  144. /**
  145. * Processes messages that are emitted by `messages`-module and add them in the queue.
  146. *
  147. * @method queueMessage
  148. * @param e {Object} the eventobject
  149. * @since 0.0.1
  150. */
  151. queueMessage: function(e) {
  152. var instance = this,
  153. messagePromise = e.messagePromise,
  154. type = e.type,
  155. level = MESSAGE_LEVELS[type],
  156. list = instance[MESSAGE_HASHES[type]];
  157. list[list.length] = messagePromise;
  158. messagePromise.finally(
  159. function() {
  160. list.remove(messagePromise);
  161. // handle the next message (if there)
  162. instance.handleMessage(true);
  163. }
  164. );
  165. (level>instance._currentMessageLevel) && instance.handleMessage(!instance.isWaiting(), level);
  166. },
  167.  
  168. /**
  169. * Defines subscribers to the events: *:message, *:warn and *:error.
  170. *
  171. * @method setupListeners
  172. * @since 0.0.1
  173. */
  174. setupListeners: function() {
  175. var instance = this;
  176. Event.after(['*:message', '*:warn', '*:error'], instance.queueMessage.bind(instance));
  177. },
  178.  
  179. /**
  180. * Tells whether `dialog` is waitin g for new messages and is currently iddle.
  181. *
  182. * @method isWaiting
  183. * @return {Boolean} whether `dialog` is waitin g for new messages
  184. * @since 0.0.1
  185. */
  186. isWaiting: function() {
  187. return (this._currentMessageLevel===0);
  188. },
  189.  
  190. /**
  191. * Retrieves the next message from the queue and calls showMessage() if it finds one.
  192. *
  193. * @method handleMessage
  194. * @param [delay] {Boolean} if there should be a delay between the previous dialog and the new one
  195. * @param [level] {Number} to force handling a specific level
  196. * @since 0.0.1
  197. */
  198. handleMessage: function(delay, level) {
  199. var instance = this,
  200. model = instance.model,
  201. messagePromise;
  202. if (!level) {
  203. // search level
  204. if (instance.errors.length>0) {
  205. level = 3;
  206. }
  207. else if (instance.warnings.length>0) {
  208. level = 2;
  209. }
  210. else if (instance.messages.length>0) {
  211. level = 1;
  212. }
  213. }
  214. if (!level || (instance[MESSAGE_HASHES_NR[level]].length===0)) {
  215. // DO NOT make messagePromise null: it sould be there as return value
  216. // of the last message
  217. instance._currentMessageLevel = 0;
  218. model.header = null;
  219. model.content = '';
  220. model.footer = null;
  221. model.validate = null;
  222. model.visible = false;
  223. return;
  224. }
  225. instance._currentMessageLevel = level;
  226. // now process the highest message
  227. messagePromise = instance[MESSAGE_HASHES_NR[level]][0];
  228. if (delay) {
  229. model.visible = false;
  230. later(instance.showMessage.bind(instance, messagePromise), FOLLOWUP_DELAY);
  231. }
  232. else {
  233. async(instance.showMessage.bind(instance, messagePromise));
  234. }
  235. },
  236.  
  237. /**
  238. * Shows the specified message-promise.
  239. *
  240. * @method showMessage
  241. * @param messagePromise {Promise} the message to be shown.
  242. * @since 0.0.1
  243. */
  244. showMessage: function(messagePromise) {
  245. var model = this.model;
  246. window.scrollTo(0, 0);
  247. model.messagePromise = messagePromise;
  248. model.header = messagePromise.header;
  249. model.content = messagePromise.content;
  250. model.footer = messagePromise.footer;
  251. model.validate = messagePromise.validate;
  252. model.visible = true;
  253. }
  254. });
  255.  
  256. // instantiate Dialog and make it operational:
  257. dialog = new Dialog();
  258.  
  259. window._ITSAmodules.Dialog = Dialog;
  260.  
  261. return Dialog;
  262. };