update.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * Update plugin. Use updateUrl and updateInterval (optional, default is 60000ms)
  3. * in the meta data of the diagram to configure the plugin. It will send the XML
  4. * of the current page to the given URL as a POST request (with a parameter called
  5. * xml) and allows for the following type of XML response (with CORS headers):
  6. *
  7. * <updates>
  8. * <update ...>
  9. * </updates>
  10. *
  11. * Where update must contain an id attribute to reference the cell in the diagram.
  12. *
  13. * - An optional value attribute that contains XML markup is used as the value for
  14. * the cell, with label and tooltip for the label and tooltip, respectively.
  15. * Additionally, placeholders="1" can be used to enable placeholders in the label
  16. * or tooltip of the cell.
  17. *
  18. * - An optional replace-value attribute that contains 1 can be specified to
  19. * replace the value of the cell. Default is to add the attributes of the XML
  20. * value specified above to the existing value of the cell. (Attributes with
  21. * an empty string value are removed.)
  22. *
  23. * - An optional style attribute that contains the cell style is be used to replace
  24. * the existing cell style.
  25. *
  26. * - An optional icon attribute that contains JSON is used to add an icon to the
  27. * given cell. The object value that the icon attribute is parsed to may contain
  28. * a tooltip (string), align ("left"|"center"|"right", default is "right"), valign
  29. * (top|middle|bottom, default is bottom) and append (true|false, default is false)
  30. * for adding or replacing existing icons. The image attribute is an object value
  31. * with src, width and height for defining the icon to be displayed (default is
  32. * mxGraph.warningImage). An empty string for the attribute removes all icons.
  33. *
  34. * See below for an example XML.
  35. */
  36. Draw.loadPlugin(function(editorUi)
  37. {
  38. if (editorUi.editor.chromeless)
  39. {
  40. var graph = editorUi.editor.graph;
  41. var interval = 60000;
  42. function createOverlay(desc)
  43. {
  44. var overlay = new mxCellOverlay(desc.image || graph.warningImage,
  45. desc.tooltip, desc.align, desc.valign, desc.offset);
  46. // Installs a handler for clicks on the overlay
  47. overlay.addListener(mxEvent.CLICK, function(sender, evt)
  48. {
  49. editorUi.alert(desc.tooltip);
  50. });
  51. return overlay;
  52. };
  53. function parseUpdates(xml)
  54. {
  55. if (xml != null && xml.length > 0)
  56. {
  57. var doc = mxUtils.parseXml(xml);
  58. if (doc != null && doc.documentElement != null)
  59. {
  60. var model = graph.getModel();
  61. var nodes = doc.documentElement.getElementsByTagName('update');
  62. if (nodes != null && nodes.length > 0)
  63. {
  64. model.beginUpdate();
  65. try
  66. {
  67. for (var i = 0; i < nodes.length; i++)
  68. {
  69. // Resolves the cell ID
  70. var cell = model.getCell(nodes[i].getAttribute('id'));
  71. if (cell != null)
  72. {
  73. // Changes the value
  74. try
  75. {
  76. var value = nodes[i].getAttribute('value');
  77. if (value != null)
  78. {
  79. var node = mxUtils.parseXml(value).documentElement;
  80. if (node != null)
  81. {
  82. if (nodes[i].getAttribute('replace-value') == '1')
  83. {
  84. graph.model.setValue(cell, node);
  85. }
  86. else
  87. {
  88. var attrs = node.attributes;
  89. for (var j = 0; j < attrs.length; j++)
  90. {
  91. graph.setAttributeForCell(cell, attrs[j].nodeName,
  92. (attrs[j].nodeValue.length > 0) ? attrs[j].nodeValue : null);
  93. }
  94. }
  95. }
  96. }
  97. }
  98. catch (e)
  99. {
  100. console.log('Error in value for ' + cell.id + ': ' + e);
  101. }
  102. // Changes the style
  103. try
  104. {
  105. var style = nodes[i].getAttribute('style');
  106. if (style != null)
  107. {
  108. graph.model.setStyle(cell, style);
  109. }
  110. }
  111. catch (e)
  112. {
  113. console.log('Error in style for ' + cell.id + ': ' + e);
  114. }
  115. // Adds or removes an overlay icon
  116. try
  117. {
  118. var icon = nodes[i].getAttribute('icon');
  119. if (icon != null)
  120. {
  121. var desc = (icon.length > 0) ? JSON.parse(icon) : null;
  122. if (desc == null || !desc.append)
  123. {
  124. graph.removeCellOverlays(cell);
  125. }
  126. if (desc != null)
  127. {
  128. graph.addCellOverlay(cell, createOverlay(desc));
  129. }
  130. }
  131. }
  132. catch (e)
  133. {
  134. console.log('Error in icon for ' + cell.id + ': ' + e);
  135. }
  136. }
  137. } // for
  138. }
  139. finally
  140. {
  141. model.endUpdate();
  142. }
  143. }
  144. }
  145. }
  146. };
  147. var currentThread = null;
  148. function scheduleUpdates()
  149. {
  150. var root = editorUi.editor.graph.getModel().getRoot();
  151. var result = false;
  152. if (root.value != null && typeof(root.value) == 'object')
  153. {
  154. interval = parseInt(root.value.getAttribute('updateInterval') || interval);
  155. var url = root.value.getAttribute('updateUrl');
  156. if (url != null)
  157. {
  158. var currentXml = mxUtils.getXml(editorUi.editor.getGraphXml());
  159. function doUpdate()
  160. {
  161. if (url === 'demo')
  162. {
  163. parseUpdates(mxUtils.getXml(createDemoResponse().documentElement));
  164. schedule();
  165. }
  166. else
  167. {
  168. mxUtils.post(url, 'xml=' + encodeURIComponent(currentXml), function(req)
  169. {
  170. if (root === editorUi.editor.graph.getModel().getRoot())
  171. {
  172. if (req.getStatus() >= 200 && req.getStatus() <= 300)
  173. {
  174. parseUpdates(mxUtils.getXml(req.getDocumentElement()));
  175. schedule();
  176. }
  177. else
  178. {
  179. editorUi.handleError({message: mxResources.get('error') + ' ' +
  180. req.getStatus()});
  181. }
  182. }
  183. }, function(err)
  184. {
  185. editorUi.handleError(err);
  186. });
  187. }
  188. };
  189. function schedule()
  190. {
  191. currentThread = window.setTimeout(doUpdate, interval);
  192. };
  193. doUpdate();
  194. result = true;
  195. }
  196. }
  197. return result;
  198. };
  199. function startUpdates()
  200. {
  201. var result = scheduleUpdates();
  202. if (result)
  203. {
  204. editorUi.editor.addListener('pageSelected', function()
  205. {
  206. window.clearTimeout(currentThread);
  207. scheduleUpdates();
  208. });
  209. }
  210. return result;
  211. };
  212. function createDemoResponse()
  213. {
  214. var doc = mxUtils.createXmlDocument();
  215. var status = doc.createElement('updates');
  216. for (var id in graph.model.cells)
  217. {
  218. var cell = graph.model.cells[id];
  219. if (graph.model.isVertex(cell))
  220. {
  221. // For the purpose of the demo we flag stuff to update with update="1".
  222. // This is not needed for the general case.
  223. if (cell.value != null && typeof(cell.value) == 'object' &&
  224. cell.value.getAttribute('update') == '1')
  225. {
  226. if (Math.random() > 0.5)
  227. {
  228. var update = doc.createElement('update');
  229. update.setAttribute('id', cell.id);
  230. update.setAttribute('value', '<object tooltip="%load%% Done" load="' +
  231. Math.round(Math.random() * 100) + '" placeholders="1">');
  232. update.setAttribute('style', cell.style + ';fillColor=#d5e8d4;gradientColor=white;');
  233. update.setAttribute('icon', JSON.stringify({tooltip: 'Running', align: "right",
  234. valign: "top", image: {src: IMAGE_PATH + '/spin.gif', width: 12, height: 12}}));
  235. status.appendChild(update);
  236. // Adds another icon
  237. if (Math.random() > 0.5)
  238. {
  239. var update = doc.createElement('update');
  240. update.setAttribute('id', cell.id);
  241. update.setAttribute('icon', JSON.stringify({tooltip: 'Locked', append: true,
  242. image: {src: IMAGE_PATH + '/locked.png', width: 12, height:12}}));
  243. status.appendChild(update);
  244. }
  245. }
  246. else
  247. {
  248. var update = doc.createElement('update');
  249. update.setAttribute('id', cell.id);
  250. update.setAttribute('style', cell.style + ';fillColor=#d4e1f5;gradientColor=white;');
  251. update.setAttribute('value', '<object tooltip="">');
  252. update.setAttribute('icon', '');
  253. status.appendChild(update);
  254. }
  255. }
  256. }
  257. }
  258. doc.appendChild(status);
  259. return doc;
  260. };
  261. // Wait for file to be loaded if no animation data is present
  262. if (!startUpdates())
  263. {
  264. editorUi.editor.addListener('fileLoaded', startUpdates);
  265. }
  266. }
  267. });