update.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /**
  2. * Update plugin. Use updateUrl and updateInterval (optional, default is 60000ms)
  3. * in the meta data of the diagram to configure the plugin. (Alternatively, the
  4. * update-url and update-interval URL parameters may be used instead.)
  5. *
  6. * It will send the XML of the current page to the given URL as a POST request
  7. * (with a parameter called xml) and allows for the following type of XML response
  8. * (with CORS headers):
  9. *
  10. * <updates>
  11. * <update ...>
  12. * <model>...</model>
  13. * <view ...>
  14. * <fit ...>
  15. * </updates>
  16. *
  17. * The outermost updates node may contain an optional url and interval property
  18. * to change the current updateUrl and updateInterval.
  19. *
  20. * Where update must contain an id attribute to reference the cell in the diagram.
  21. *
  22. * - An optional value attribute that contains XML markup is used as the value for
  23. * the cell, with label and tooltip for the label and tooltip, respectively.
  24. * Additionally, placeholders="1" can be used to enable placeholders in the label
  25. * or tooltip of the cell.
  26. *
  27. * Example: <object label="Hello, %var1%!" var1="World" tooltip=
  28. * "Click <a href=\"https://www.draw.io\">here</a>" placeholders="1">
  29. *
  30. * - An optional replace-value attribute that contains 1 can be specified to
  31. * replace the value of the cell. Default is to add the attributes of the XML
  32. * value specified above to the existing value of the cell. (Attributes with
  33. * an empty string value are removed.)
  34. *
  35. * - An optional style attribute that contains the cell style is used to replace
  36. * the existing cell style.
  37. *
  38. * Example: fillColor=red;gradientColor=white;"
  39. *
  40. * - An optional icon attribute that contains JSON is used to add an icon to the
  41. * given cell. The object value that the icon attribute is parsed and may contain
  42. * a tooltip (string), align ("left"|"center"|"right", default is "right"), valign
  43. * (top|middle|bottom, default is bottom) and append (true|false, default is false)
  44. * for adding or replacing existing icons. The image attribute is an object value
  45. * with src, width and height for defining the icon to be displayed (default is
  46. * mxGraph.warningImage). An empty string for the attribute removes all icons.
  47. *
  48. * Example: JSON.stringify({tooltip: 'Locked', append: true, image:
  49. * {src: IMAGE_PATH + '/locked.png', width: 26, height:26}}
  50. *
  51. * - An optional geometry attribute that contains a JSON mxGeometry object can be used
  52. * to replace the current geometry of the refenced cell. In addition to the existing
  53. * field names in mxGeometry, dx and dy can be used to define a vector for moving the
  54. * shape, and dh and dw can be used to resize the cell.
  55. *
  56. * Example: JSON.stringify({dx: (Math.random() * 100) - 50, dh: (Math.random() * 100) - 50}))
  57. *
  58. * - Additionally a model node may be specified to set the current graph model.
  59. *
  60. * Example: <model><mxGraphModel><root><mxCell id="0"/></mxCell>...</root></mxGraphModel></model>
  61. *
  62. * - A view node may be specified with a scale, dx and dy attribute to change the current
  63. * scale and translate.
  64. *
  65. * Example: <view scale="0.5" dx="100" dy="100"/>
  66. *
  67. * - A fit node may be specified with a max-scale property to fit the diagram to the
  68. * available viewport with the specified max-scale.
  69. */
  70. Draw.loadPlugin(function(editorUi)
  71. {
  72. if (editorUi.editor.isChromelessView())
  73. {
  74. var graph = editorUi.editor.graph;
  75. var updateInterval = parseInt(urlParams['update-interval'] || 60000);
  76. var updateUrlParam = urlParams['update-url'];
  77. var updateUrl = null;
  78. if (updateUrlParam != null)
  79. {
  80. updateUrl = decodeURIComponent(updateUrlParam);
  81. // Creates empty file if update URL is in URL parameter
  82. if (editorUi.createFile != null && editorUi.getCurrentFile() == null)
  83. {
  84. editorUi.createFile(editorUi.defaultFilename, null, null, null, null, null, null, true);
  85. }
  86. }
  87. function createOverlay(desc)
  88. {
  89. var overlay = new mxCellOverlay(desc.image || graph.warningImage,
  90. desc.tooltip, desc.align, desc.valign, desc.offset);
  91. // Installs a handler for clicks on the overlay
  92. overlay.addListener(mxEvent.CLICK, function(sender, evt)
  93. {
  94. editorUi.alert(desc.tooltip);
  95. });
  96. return overlay;
  97. };
  98. function parseResponse(xml)
  99. {
  100. var doc = editorUi.updateDiagram(xml);
  101. var node = (doc != null) ? doc.documentElement : null;
  102. if (node != null && node.nodeName == 'updates')
  103. {
  104. if (node.hasAttribute('url'))
  105. {
  106. updateUrl = node.getAttribute('url');
  107. }
  108. if (node.hasAttribute('interval'))
  109. {
  110. updateInterval = node.getAttribute('interval');
  111. }
  112. }
  113. };
  114. var currentThread = null;
  115. function scheduleUpdates()
  116. {
  117. var page = editorUi.currentPage;
  118. var root = editorUi.editor.graph.getModel().getRoot();
  119. var result = false;
  120. if (urlParams['update-url'] || (root.value != null && typeof(root.value) == 'object'))
  121. {
  122. if (root.value != null && typeof(root.value) == 'object')
  123. {
  124. updateInterval = parseInt(root.value.getAttribute('updateInterval') || updateInterval);
  125. updateUrl = root.value.getAttribute('updateUrl') || updateUrl;
  126. }
  127. if (updateUrl != null)
  128. {
  129. var currentXml = mxUtils.getXml(editorUi.editor.getGraphXml());
  130. function doUpdate()
  131. {
  132. if (updateUrl === 'demo')
  133. {
  134. parseResponse(mxUtils.getXml(createDemoResponse().documentElement));
  135. schedule();
  136. }
  137. else
  138. {
  139. mxUtils.post(updateUrl, 'xml=' + encodeURIComponent(currentXml), function(req)
  140. {
  141. if (page === editorUi.currentPage)
  142. {
  143. if (req.getStatus() >= 200 && req.getStatus() <= 300)
  144. {
  145. parseResponse(mxUtils.getXml(req.getDocumentElement()));
  146. schedule();
  147. }
  148. else
  149. {
  150. editorUi.handleError({message: mxResources.get('error') + ' ' +
  151. req.getStatus()});
  152. }
  153. }
  154. }, function(err)
  155. {
  156. editorUi.handleError(err);
  157. });
  158. }
  159. };
  160. function schedule()
  161. {
  162. currentThread = window.setTimeout(doUpdate, updateInterval);
  163. };
  164. doUpdate();
  165. result = true;
  166. }
  167. }
  168. return result;
  169. };
  170. function startUpdates()
  171. {
  172. var result = scheduleUpdates();
  173. if (result)
  174. {
  175. editorUi.editor.addListener('pageSelected', function()
  176. {
  177. window.clearTimeout(currentThread);
  178. scheduleUpdates();
  179. });
  180. }
  181. return result;
  182. };
  183. function createDemoResponse()
  184. {
  185. var doc = mxUtils.createXmlDocument();
  186. var status = doc.createElement('updates');
  187. for (var id in graph.model.cells)
  188. {
  189. var cell = graph.model.cells[id];
  190. if (graph.model.isEdge(cell))
  191. {
  192. // Ignores short edges
  193. var state = graph.view.getState(cell);
  194. if (Math.random() > 0.5 && state != null && state.length > 50)
  195. {
  196. var update = doc.createElement('update');
  197. update.setAttribute('id', cell.id);
  198. update.setAttribute('value', '<object label="%load% minutes" load="' +
  199. Math.round(Math.random() * 100) + '" placeholders="1">');
  200. update.setAttribute('style', cell.style + ';strokeColor=red;strokeWidth=' +
  201. Math.round(Math.random() * 5) + ';');
  202. status.appendChild(update);
  203. }
  204. else
  205. {
  206. var update = doc.createElement('update');
  207. update.setAttribute('id', cell.id);
  208. update.setAttribute('value', '<object label="" load="' +
  209. Math.round(Math.random() * 100) + '" placeholders="1">');
  210. update.setAttribute('style', cell.style + ';strokeColor=black;strokeWidth=;');
  211. status.appendChild(update);
  212. }
  213. }
  214. else if (graph.model.isVertex(cell))
  215. {
  216. // For the purpose of the demo we flag stuff to update with update="1".
  217. // This is not needed for the general case.
  218. if (cell.value != null && typeof(cell.value) == 'object' &&
  219. cell.value.getAttribute('update') == '1')
  220. {
  221. // Restores original style in demo roundtrip
  222. if (cell.prevStyle == null)
  223. {
  224. cell.prevStyle = cell.style;
  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.prevStyle + ';fillColor=red;gradientColor=white;');
  233. update.setAttribute('icon', JSON.stringify({tooltip: 'Alert', align: 'right',
  234. valign: 'top', image: {src: 'https://www.draw.io/mxgraph/images/warning.gif', width: 26, height: 26}}));
  235. // update.setAttribute('geometry', JSON.stringify({dx: (Math.random() * 100) - 50,
  236. // y: cell.geometry.y + (Math.random() * 100) - 50, dh: (Math.random() * 100) - 50}));
  237. status.appendChild(update);
  238. // Adds another icon
  239. if (Math.random() > 0.5)
  240. {
  241. var update = doc.createElement('update');
  242. update.setAttribute('id', cell.id);
  243. update.setAttribute('icon', JSON.stringify({tooltip: 'Busy', append: true,
  244. image: {src: IMAGE_PATH + '/spin.gif', width: 26, height:26}}));
  245. status.appendChild(update);
  246. }
  247. }
  248. else
  249. {
  250. var update = doc.createElement('update');
  251. update.setAttribute('id', cell.id);
  252. update.setAttribute('style', cell.prevStyle + ';fillColor=#d4e1f5;gradientColor=white;');
  253. update.setAttribute('value',
  254. '<object tooltip="Click <a href=\"https://www.draw.io\">here</a>">');
  255. update.setAttribute('icon', '');
  256. status.appendChild(update);
  257. }
  258. }
  259. }
  260. }
  261. // var modelNode = mxUtils.parseXml('<model><mxGraphModel> <root> <mxCell id="0"/> <mxCell id="1" parent="0"/> <mxCell id="12" value="Program" style="rounded=0;shadow=0;strokeWidth=1;fontSize=12;fillColor=#F0F0F0;" vertex="1" parent="1"> <mxGeometry x="274" y="227" width="100" height="40" as="geometry"/> </mxCell> <mxCell id="13" value="PDF&#xa;Outline" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="80" y="247" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="14" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="13" target="12" parent="1"> <mxGeometry relative="1" as="geometry"/> </mxCell> <mxCell id="15" value="HTML&#xa;Outline" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="118" y="140" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="16" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="15" target="12" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="267" y="158.2814070351758" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="17" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="18" target="12" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="413.7317073170732" y="171" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="18" value="Name" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="274" y="100" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="19" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="20" target="12" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="464.5244755244755" y="227" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="20" value="Description" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="437" y="124" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="21" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="22" target="12" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="436.80419580419584" y="319" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="22" value="Admission&#xa;Deadline" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="495" y="216" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="23" value="courses" style="rhombus;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="284" y="349" width="80" height="50" as="geometry"/> </mxCell> <mxCell id="24" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="23" target="12" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="495.26224188188667" y="238.15603653581252" as="sourcePoint"/> <mxPoint x="374" y="244.4537037037037" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="25" value="Course" style="rounded=0;shadow=0;strokeWidth=1;fontSize=12;fillColor=#F0F0F0;" vertex="1" parent="1"> <mxGeometry x="274" y="458" width="100" height="40" as="geometry"/> </mxCell> <mxCell id="26" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="23" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="324" y="349" as="sourcePoint"/> <mxPoint x="324" y="267" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="27" value="Course&#xa;Number" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="80" y="418" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="28" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="27" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="271.91489361702133" y="652" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="29" value="Subject" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="80" y="514" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="30" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="29" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="274" y="563.9497487437186" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="31" value="PDF&#xa;Outline" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="163" y="587" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="32" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="31" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="364" y="584.070351758794" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="33" value="HTML&#xa;Outline" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="279" y="626" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="34" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="33" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="401.97468354430384" y="537" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="35" value="Description" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="420" y="567" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="36" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="35" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="465" y="456" as="targetPoint"/> </mxGeometry> </mxCell> <mxCell id="37" value="Name" style="ellipse;rounded=0;shadow=0;strokeWidth=1;fillColor=none;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="495" y="458" width="90" height="40" as="geometry"/> </mxCell> <mxCell id="38" style="rounded=0;html=0;shadow=0;startArrow=none;endArrow=none;endFill=0;endSize=10;strokeColor=#000000;strokeWidth=1;fontSize=12;startFill=0;" edge="1" source="37" target="25" parent="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="437.1935483870968" y="381" as="targetPoint"/> </mxGeometry> </mxCell> </root></mxGraphModel></model>');
  262. // status.appendChild(modelNode.documentElement);
  263. //
  264. // var fitNode = mxUtils.parseXml('<view scale="0.5" dx="0"/>');
  265. // status.appendChild(fitNode.documentElement);
  266. doc.appendChild(status);
  267. return doc;
  268. };
  269. // Wait for file to be loaded if no animation data is present
  270. if (!startUpdates())
  271. {
  272. editorUi.editor.addListener('fileLoaded', startUpdates);
  273. }
  274. }
  275. });