Commit edb4d5a6ec3b369a026318af28b99d3e9b42a5e3

Authored by ww
1 parent 959f9d93

chore: del dist folder

1   -/**
2   - * Copyright (c) 2006-2012, JGraph Ltd
3   - */
4   -Format = function (editorUi, container) {
5   - this.editorUi = editorUi;
6   - this.container = container;
7   -};
8   -
9   -/**
10   - * Background color for inactive tabs.
11   - * 没有激活的tab栏 背景色
12   - */
13   -Format.inactiveTabBackgroundColor = "#f1f3f4";
14   -
15   -/**
16   - * Icons for markers (24x16).
17   - */
18   -Format.classicFilledMarkerImage = Graph.createSvgImage(
19   - 20,
20   - 22,
21   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
22   - 32,
23   - 20,
24   -);
25   -Format.classicThinFilledMarkerImage = Graph.createSvgImage(
26   - 20,
27   - 22,
28   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 3 8 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
29   - 32,
30   - 20,
31   -);
32   -Format.openFilledMarkerImage = Graph.createSvgImage(
33   - 20,
34   - 22,
35   - '<path transform="translate(4,2)" stroke-width="2" d="M 8 0 L 0 8 L 8 16 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
36   - 32,
37   - 20,
38   -);
39   -Format.openThinFilledMarkerImage = Graph.createSvgImage(
40   - 20,
41   - 22,
42   - '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 8 12 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
43   - 32,
44   - 20,
45   -);
46   -Format.openAsyncFilledMarkerImage = Graph.createSvgImage(
47   - 20,
48   - 22,
49   - '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
50   - 32,
51   - 20,
52   -);
53   -Format.blockFilledMarkerImage = Graph.createSvgImage(
54   - 20,
55   - 22,
56   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
57   - 32,
58   - 20,
59   -);
60   -Format.blockThinFilledMarkerImage = Graph.createSvgImage(
61   - 20,
62   - 22,
63   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
64   - 32,
65   - 20,
66   -);
67   -Format.asyncFilledMarkerImage = Graph.createSvgImage(
68   - 20,
69   - 22,
70   - '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
71   - 32,
72   - 20,
73   -);
74   -Format.ovalFilledMarkerImage = Graph.createSvgImage(
75   - 20,
76   - 22,
77   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="#404040"/>',
78   - 32,
79   - 20,
80   -);
81   -Format.diamondFilledMarkerImage = Graph.createSvgImage(
82   - 20,
83   - 22,
84   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
85   - 32,
86   - 20,
87   -);
88   -Format.diamondThinFilledMarkerImage = Graph.createSvgImage(
89   - 20,
90   - 22,
91   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>',
92   - 32,
93   - 20,
94   -);
95   -Format.classicMarkerImage = Graph.createSvgImage(
96   - 20,
97   - 22,
98   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>',
99   - 32,
100   - 20,
101   -);
102   -Format.classicThinMarkerImage = Graph.createSvgImage(
103   - 20,
104   - 22,
105   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 5 8 L 8 12 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>',
106   - 32,
107   - 20,
108   -);
109   -Format.blockMarkerImage = Graph.createSvgImage(
110   - 20,
111   - 22,
112   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>',
113   - 32,
114   - 20,
115   -);
116   -Format.blockThinMarkerImage = Graph.createSvgImage(
117   - 20,
118   - 22,
119   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>',
120   - 32,
121   - 20,
122   -);
123   -Format.asyncMarkerImage = Graph.createSvgImage(
124   - 20,
125   - 22,
126   - '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
127   - 32,
128   - 20,
129   -);
130   -Format.ovalMarkerImage = Graph.createSvgImage(
131   - 20,
132   - 22,
133   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>',
134   - 32,
135   - 20,
136   -);
137   -Format.diamondMarkerImage = Graph.createSvgImage(
138   - 20,
139   - 22,
140   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>',
141   - 32,
142   - 20,
143   -);
144   -Format.diamondThinMarkerImage = Graph.createSvgImage(
145   - 20,
146   - 22,
147   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>',
148   - 32,
149   - 20,
150   -);
151   -Format.boxMarkerImage = Graph.createSvgImage(
152   - 20,
153   - 22,
154   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 L 10 3 L 10 13 L 0 13 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>',
155   - 32,
156   - 20,
157   -);
158   -Format.halfCircleMarkerImage = Graph.createSvgImage(
159   - 20,
160   - 22,
161   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 A 5 5 0 0 1 5 8 A 5 5 0 0 1 0 13 M 5 8 L 24 8" stroke="#404040" fill="transparent"/>',
162   - 32,
163   - 20,
164   -);
165   -Format.dashMarkerImage = Graph.createSvgImage(
166   - 20,
167   - 22,
168   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
169   - 32,
170   - 20,
171   -);
172   -Format.crossMarkerImage = Graph.createSvgImage(
173   - 20,
174   - 22,
175   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 12 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
176   - 32,
177   - 20,
178   -);
179   -Format.circlePlusMarkerImage = Graph.createSvgImage(
180   - 20,
181   - 22,
182   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 6 2 L 6 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
183   - 32,
184   - 20,
185   -);
186   -Format.circleMarkerImage = Graph.createSvgImage(
187   - 20,
188   - 22,
189   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>',
190   - 32,
191   - 20,
192   -);
193   -Format.ERmandOneMarkerImage = Graph.createSvgImage(
194   - 20,
195   - 22,
196   - '<path transform="translate(4,2)" stroke-width="2" d="M 6 2 L 6 14 M 9 2 L 9 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
197   - 32,
198   - 20,
199   -);
200   -Format.ERmanyMarkerImage = Graph.createSvgImage(
201   - 20,
202   - 22,
203   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
204   - 32,
205   - 20,
206   -);
207   -Format.ERoneToManyMarkerImage = Graph.createSvgImage(
208   - 20,
209   - 22,
210   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 15 2 L 15 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
211   - 32,
212   - 20,
213   -);
214   -Format.ERzeroToOneMarkerImage = Graph.createSvgImage(
215   - 20,
216   - 22,
217   - '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 4 3 L 4 13" stroke="#404040" fill="transparent"/>',
218   - 32,
219   - 20,
220   -);
221   -Format.ERzeroToManyMarkerImage = Graph.createSvgImage(
222   - 20,
223   - 22,
224   - '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 0 3 L 8 8 L 0 13" stroke="#404040" fill="transparent"/>',
225   - 32,
226   - 20,
227   -);
228   -Format.EROneMarkerImage = Graph.createSvgImage(
229   - 20,
230   - 22,
231   - '<path transform="translate(4,2)" stroke-width="2" d="M 5 2 L 5 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
232   - 32,
233   - 20,
234   -);
235   -Format.baseDashMarkerImage = Graph.createSvgImage(
236   - 20,
237   - 22,
238   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>',
239   - 32,
240   - 20,
241   -);
242   -Format.doubleBlockMarkerImage = Graph.createSvgImage(
243   - 20,
244   - 22,
245   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>',
246   - 32,
247   - 20,
248   -);
249   -Format.doubleBlockFilledMarkerImage = Graph.createSvgImage(
250   - 20,
251   - 22,
252   - '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="#404040"/>',
253   - 32,
254   - 20,
255   -);
256   -
257   -/**
258   - * Adds a style change item to the given menu.
259   - */
260   -Format.processMenuIcon = function (elt, transform) {
261   - var imgs = elt.getElementsByTagName("img");
262   -
263   - if (imgs.length > 0) {
264   - if (Editor.isDarkMode()) {
265   - imgs[0].style.filter = "invert(100%)";
266   - }
267   -
268   - imgs[0].className = "geIcon";
269   - imgs[0].style.padding = "0px";
270   - imgs[0].style.margin = "0 0 0 2px";
271   -
272   - if (transform != null) {
273   - mxUtils.setPrefixedStyle(imgs[0].style, "transform", transform);
274   - }
275   - }
276   -
277   - return elt;
278   -};
279   -
280   -/**
281   - * Returns information about the current selection.
282   - */
283   -Format.prototype.labelIndex = 0;
284   -
285   -/**
286   - * Returns information about the current selection.
287   - * 默认选中的formatBar的tab栏索引 / 0是第一个
288   - */
289   -Format.prototype.diagramIndex = 0;
290   -
291   -/**
292   - * Returns information about the current selection.
293   - */
294   -Format.prototype.currentIndex = 0;
295   -
296   -/**
297   - * Returns information about the current selection.
298   - * 是否显示关闭按钮
299   - */
300   -Format.prototype.showCloseButton = false;
301   -
302   -/**
303   - * Adds the label menu items to the given menu and parent.
304   - */
305   -Format.prototype.init = function () {
306   - var ui = this.editorUi;
307   - var editor = ui.editor;
308   - var graph = editor.graph;
309   - this.update = mxUtils.bind(this, function (sender, evt) {
310   - this.refresh();
311   - });
312   -
313   - graph.getSelectionModel().addListener(mxEvent.CHANGE, this.update);
314   - graph.getModel().addListener(mxEvent.CHANGE, this.update);
315   - graph.addListener(mxEvent.EDITING_STARTED, this.update);
316   - graph.addListener(mxEvent.EDITING_STOPPED, this.update);
317   - graph.getView().addListener("unitChanged", this.update);
318   - editor.addListener("autosaveChanged", this.update);
319   - graph.addListener(mxEvent.ROOT, this.update);
320   - ui.addListener("styleChanged", this.update);
321   -
322   - this.refresh();
323   -};
324   -
325   -/**
326   - * Adds the label menu items to the given menu and parent.
327   - */
328   -Format.prototype.clear = function () {
329   - this.container.innerHTML = "";
330   -
331   - // Destroy existing panels
332   - if (this.panels != null) {
333   - for (var i = 0; i < this.panels.length; i++) {
334   - this.panels[i].destroy();
335   - }
336   - }
337   -
338   - this.panels = [];
339   -};
340   -
341   -/**
342   - * Adds the label menu items to the given menu and parent.
343   - */
344   -Format.prototype.refresh = function () {
345   - if (this.pendingRefresh != null) {
346   - window.clearTimeout(this.pendingRefresh);
347   - this.pendingRefresh = null;
348   - }
349   -
350   - this.pendingRefresh = window.setTimeout(
351   - mxUtils.bind(this, function () {
352   - this.immediateRefresh();
353   - }),
354   - );
355   -};
356   -
357   -/**
358   - * Adds the label menu items to the given menu and parent.
359   - */
360   -Format.prototype.immediateRefresh = function () {
361   - // Performance tweak: No refresh needed if not visible
362   - if (this.container.style.width == "0px") {
363   - return;
364   - }
365   -
366   - this.clear();
367   - var ui = this.editorUi;
368   - var graph = ui.editor.graph;
369   -
370   - var div = document.createElement("div");
371   - div.style.whiteSpace = "nowrap";
372   - div.style.color = "rgb(112, 112, 112)";
373   - div.style.textAlign = "left";
374   - div.style.cursor = "default";
375   - // div.style.display = 'flex'
376   -
377   - var label = document.createElement("div");
378   - label.className = "geFormatSection";
379   - label.style.textAlign = "center";
380   - label.style.fontWeight = "bold";
381   - label.style.paddingTop = "8px";
382   - label.style.fontSize = "13px";
383   - label.style.borderWidth = "0px 0px 1px 1px";
384   - label.style.borderStyle = "solid";
385   - label.style.display = "inline-block";
386   - label.style.height = "25px";
387   - label.style.overflow = "hidden";
388   - label.style.width = "100%";
389   - label.style.flex = 'auto'
390   - this.container.appendChild(div);
391   -
392   - // Prevents text selection
393   - mxEvent.addListener(
394   - label,
395   - mxClient.IS_POINTER ? "pointerdown" : "mousedown",
396   - mxUtils.bind(this, function (evt) {
397   - evt.preventDefault();
398   - }),
399   - );
400   -
401   - var ss = ui.getSelectionState();
402   - var containsLabel = ss.containsLabel;
403   - var currentLabel = null;
404   - var currentPanel = null;
405   -
406   -
407   - /**
408   - * @description 验证是否有数据绑定面板
409   - * @returns {boolean}
410   - */
411   - const validateHasDataSourcePanel = () => {
412   - const ui = this.editorUi;
413   - const ss = ui.getSelectionState();
414   - const vertices = ss.vertices || []
415   - const sidebarInstance = ui.sidebar
416   - const cell = vertices[0]
417   - if (!cell) return false
418   - const basicAttr = sidebarInstance.enumCellBasicAttribute
419   - const componentType = cell.getAttribute(basicAttr.COMPONENT_TYPE)
420   - const hasPermission = sidebarInstance.getComponentPermission(componentType)
421   - return !!hasPermission.length && hasSavePermission()
422   - }
423   -
424   - var addClickHandler = mxUtils.bind(
425   - this,
426   - function (elt, panel, index, lastEntry) {
427   - var clickHandler = mxUtils.bind(this, function (evt) {
428   - if (currentLabel != elt) {
429   - if (containsLabel) {
430   - this.labelIndex = index;
431   - } else if (graph.isSelectionEmpty()) {
432   - this.diagramIndex = index;
433   - } else {
434   - this.currentIndex = index;
435   - }
436   -
437   - if (currentLabel != null) {
438   - currentLabel.style.backgroundColor =
439   - Format.inactiveTabBackgroundColor;
440   - currentLabel.style.borderBottomWidth = "1px";
441   - }
442   -
443   - currentLabel = elt;
444   - currentLabel.style.backgroundColor = "";
445   - currentLabel.style.borderBottomWidth = "0px";
446   -
447   - if (currentPanel != panel) {
448   - if (currentPanel != null) {
449   - currentPanel.style.display = "none";
450   - }
451   -
452   - currentPanel = panel;
453   - currentPanel.style.display = "";
454   - }
455   - }
456   -
457   - if (!validateHasDataSourcePanel()) this.currentIndex = 0
458   - });
459   -
460   - mxEvent.addListener(elt, "click", clickHandler);
461   -
462   - // Prevents text selection
463   - mxEvent.addListener(
464   - elt,
465   - mxClient.IS_POINTER ? "pointerdown" : "mousedown",
466   - mxUtils.bind(this, function (evt) {
467   - evt.preventDefault();
468   - }),
469   - );
470   -
471   - if (
472   - (lastEntry && currentLabel == null) ||
473   - index ==
474   - (containsLabel
475   - ? this.labelIndex
476   - : graph.isSelectionEmpty()
477   - ? this.diagramIndex
478   - : this.currentIndex)
479   - ) {
480   - // Invokes handler directly as a workaround for no click on DIV in KHTML.
481   - clickHandler();
482   - }
483   - },
484   - );
485   -
486   - var idx = 0;
487   -
488   - if (graph.isSelectionEmpty()) {
489   - mxUtils.write(label, mxResources.get("diagram"));
490   - label.style.borderLeftWidth = "0px";
491   -
492   - div.appendChild(label);
493   - var diagramPanel = div.cloneNode(false);
494   - this.panels.push(new DiagramFormatPanel(this, ui, diagramPanel));
495   - this.container.appendChild(diagramPanel);
496   -
497   - if (Editor.styles != null) {
498   - diagramPanel.style.display = "none";
499   - label.style.width = this.showCloseButton ? "106px" : "50%";
500   - label.style.cursor = "pointer";
501   - label.style.backgroundColor = Format.inactiveTabBackgroundColor;
502   -
503   - var label2 = label.cloneNode(false);
504   - label2.style.borderLeftWidth = "1px";
505   - label2.style.borderRightWidth = "1px";
506   - label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
507   -
508   - addClickHandler(label, diagramPanel, idx++);
509   -
510   - var stylePanel = div.cloneNode(false);
511   - stylePanel.style.display = "none";
512   - mxUtils.write(label2, mxResources.get("style"));
513   - div.appendChild(label2);
514   - this.panels.push(new DiagramStylePanel(this, ui, stylePanel));
515   - this.container.appendChild(stylePanel);
516   -
517   - addClickHandler(label2, stylePanel, idx++);
518   - }
519   -
520   - // Adds button to hide the format panel since
521   - // people don't seem to find the toolbar button
522   - // and the menu item in the format menu
523   - if (this.showCloseButton) {
524   - var label2 = label.cloneNode(false);
525   - label2.style.borderLeftWidth = "1px";
526   - label2.style.borderRightWidth = "1px";
527   - label2.style.borderBottomWidth = "1px";
528   - label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
529   - label2.style.position = "absolute";
530   - label2.style.right = "0px";
531   - label2.style.top = "0px";
532   - label2.style.width = "25px";
533   -
534   - var img = document.createElement("img");
535   - img.setAttribute("border", "0");
536   - img.setAttribute("src", Dialog.prototype.closeImage);
537   - img.setAttribute("title", mxResources.get("hide"));
538   - img.style.position = "absolute";
539   - img.style.display = "block";
540   - img.style.right = "0px";
541   - img.style.top = "8px";
542   - img.style.cursor = "pointer";
543   - img.style.marginTop = "1px";
544   - img.style.marginRight = "6px";
545   - img.style.border = "1px solid transparent";
546   - img.style.padding = "1px";
547   - img.style.opacity = 0.5;
548   - label2.appendChild(img);
549   -
550   - mxEvent.addListener(img, "click", function () {
551   - ui.actions.get("formatPanel").funct();
552   - });
553   -
554   - div.appendChild(label2);
555   - }
556   - } else if (graph.isEditing()) {
557   - mxUtils.write(label, mxResources.get("text"));
558   - div.appendChild(label);
559   - this.panels.push(new TextFormatPanel(this, ui, div));
560   - } else {
561   - //选中图形,右侧FormatBar添加样式 TODO add other style
562   - label.style.backgroundColor = Format.inactiveTabBackgroundColor;
563   - label.style.borderLeftWidth = "1px";
564   - label.style.cursor = "pointer";
565   - label.style.width = containsLabel || ss.cells.length == 0 ? "50%" : validateHasDataSourcePanel() ? "25%" : "33.333%";
566   - var label2 = label.cloneNode(false);
567   - var label3 = label2.cloneNode(false);
568   - var label4 = label3.cloneNode(false);
569   -
570   - // Workaround for ignored background in IE
571   - label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
572   - label3.style.backgroundColor = Format.inactiveTabBackgroundColor;
573   - label4.style.backgroundColor = Format.inactiveTabBackgroundColor;
574   -
575   - // Style
576   - if (containsLabel) {
577   - label2.style.borderLeftWidth = "0px";
578   - } else {
579   - label.style.borderLeftWidth = "0px";
580   - mxUtils.write(label, mxResources.get("style"));
581   - div.appendChild(label);
582   -
583   - var stylePanel = div.cloneNode(false);
584   - stylePanel.style.display = "none";
585   - this.panels.push(new StyleFormatPanel(this, ui, stylePanel));
586   - this.container.appendChild(stylePanel);
587   -
588   - addClickHandler(label, stylePanel, idx++);
589   - }
590   -
591   - if (validateHasDataSourcePanel()) {
592   - // bind data
593   - mxUtils.write(label4, "数据绑定");
594   - div.appendChild(label4);
595   -
596   - var dataPanel = div.cloneNode(false);
597   - dataPanel.style.display = "none";
598   - this.panels.push(new DataFormatPanel(this, ui, dataPanel));
599   - this.container.appendChild(dataPanel);
600   - }
601   -
602   - // Text
603   - mxUtils.write(label2, mxResources.get("text"));
604   - div.appendChild(label2);
605   -
606   - var textPanel = div.cloneNode(false);
607   - textPanel.style.display = "none";
608   - this.panels.push(new TextFormatPanel(this, ui, textPanel));
609   - this.container.appendChild(textPanel);
610   -
611   - // Arrange
612   - mxUtils.write(label3, mxResources.get("arrange"));
613   - div.appendChild(label3);
614   -
615   - var arrangePanel = div.cloneNode(false);
616   - arrangePanel.style.display = "none";
617   - this.panels.push(new ArrangePanel(this, ui, arrangePanel));
618   - this.container.appendChild(arrangePanel);
619   -
620   - if (ss.cells.length > 0) {
621   - addClickHandler(label2, textPanel, idx++);
622   - } else {
623   - label2.style.display = "none";
624   - }
625   - addClickHandler(label3, arrangePanel, idx++);
626   - if (ss.cells.length > 0) {
627   - addClickHandler(label4, dataPanel, idx++, true);
628   - } else {
629   - label4.style.display = "none";
630   - }
631   - }
632   -};
633   -
634   -/**
635   - * Base class for format panels.
636   - */
637   -BaseFormatPanel = function (format, editorUi, container) {
638   - this.format = format;
639   - this.editorUi = editorUi;
640   - this.container = container;
641   - this.listeners = [];
642   -};
643   -
644   -/**
645   - *
646   - */
647   -BaseFormatPanel.prototype.buttonBackgroundColor = "white";
648   -
649   -/**
650   - * Install input handler.
651   - */
652   -BaseFormatPanel.prototype.installInputHandler = function (
653   - input,
654   - key,
655   - defaultValue,
656   - min,
657   - max,
658   - unit,
659   - textEditFallback,
660   - isFloat,
661   -) {
662   - unit = unit != null ? unit : "";
663   - isFloat = isFloat != null ? isFloat : false;
664   -
665   - var ui = this.editorUi;
666   - var graph = ui.editor.graph;
667   -
668   - min = min != null ? min : 1;
669   - max = max != null ? max : 999;
670   -
671   - var selState = null;
672   - var updating = false;
673   -
674   - var update = mxUtils.bind(this, function (evt) {
675   - var value = isFloat ? parseFloat(input.value) : parseInt(input.value);
676   -
677   - // Special case: angle mod 360
678   - if (!isNaN(value) && key == mxConstants.STYLE_ROTATION) {
679   - // Workaround for decimal rounding errors in floats is to
680   - // use integer and round all numbers to two decimal point
681   - value = mxUtils.mod(Math.round(value * 100), 36000) / 100;
682   - }
683   -
684   - value = Math.min(max, Math.max(min, isNaN(value) ? defaultValue : value));
685   -
686   - if (graph.cellEditor.isContentEditing() && textEditFallback) {
687   - if (!updating) {
688   - updating = true;
689   -
690   - if (selState != null) {
691   - graph.cellEditor.restoreSelection(selState);
692   - selState = null;
693   - }
694   -
695   - textEditFallback(value);
696   - input.value = value + unit;
697   -
698   - // Restore focus and selection in input
699   - updating = false;
700   - }
701   - } else if (
702   - value != mxUtils.getValue(ui.getSelectionState().style, key, defaultValue)
703   - ) {
704   - if (graph.isEditing()) {
705   - graph.stopEditing(true);
706   - }
707   - // TODO update data ??
708   - graph.getModel().beginUpdate();
709   - try {
710   - var cells = ui.getSelectionState().cells;
711   - graph.setCellStyles(key, value, cells);
712   -
713   - // Handles special case for fontSize where HTML labels are parsed and updated
714   - if (key == mxConstants.STYLE_FONTSIZE) {
715   - graph.updateLabelElements(cells, function (elt) {
716   - elt.style.fontSize = value + "px";
717   - elt.removeAttribute("size");
718   - });
719   - }
720   -
721   - for (var i = 0; i < cells.length; i++) {
722   - if (graph.model.getChildCount(cells[i]) == 0) {
723   - graph.autoSizeCell(cells[i], false);
724   - }
725   - }
726   -
727   - ui.fireEvent(
728   - new mxEventObject(
729   - "styleChanged",
730   - "keys",
731   - [key],
732   - "values",
733   - [value],
734   - "cells",
735   - cells,
736   - ),
737   - );
738   - } finally {
739   - graph.getModel().endUpdate();
740   - }
741   - }
742   -
743   - input.value = value + unit;
744   - mxEvent.consume(evt);
745   - });
746   -
747   - if (textEditFallback && graph.cellEditor.isContentEditing()) {
748   - // KNOWN: Arrow up/down clear selection text in quirks/IE 8
749   - // Text size via arrow button limits to 16 in IE11. Why?
750   - mxEvent.addListener(input, "mousedown", function () {
751   - if (document.activeElement == graph.cellEditor.textarea) {
752   - selState = graph.cellEditor.saveSelection();
753   - }
754   - });
755   -
756   - mxEvent.addListener(input, "touchstart", function () {
757   - if (document.activeElement == graph.cellEditor.textarea) {
758   - selState = graph.cellEditor.saveSelection();
759   - }
760   - });
761   - }
762   -
763   - mxEvent.addListener(input, "change", update);
764   - mxEvent.addListener(input, "blur", update);
765   -
766   - return update;
767   -};
768   -
769   -/**
770   - * Adds the given option.
771   - */
772   -BaseFormatPanel.prototype.createPanel = function () {
773   - var div = document.createElement("div");
774   - div.className = "geFormatSection";
775   - div.style.padding = "12px 0px 12px 14px";
776   -
777   - return div;
778   -};
779   -
780   -/**
781   - * Adds the given option.
782   - */
783   -BaseFormatPanel.prototype.createTitle = function (title) {
784   - var div = document.createElement("div");
785   - div.style.padding = "0px 0px 6px 0px";
786   - div.style.whiteSpace = "nowrap";
787   - div.style.overflow = "hidden";
788   - div.style.width = "200px";
789   - div.style.fontWeight = "bold";
790   - mxUtils.write(div, title);
791   -
792   - return div;
793   -};
794   -
795   -/**
796   - *
797   - */
798   -BaseFormatPanel.prototype.addAction = function (div, name) {
799   - var action = this.editorUi.actions.get(name);
800   - var btn = null;
801   -
802   - if (action != null && action.isEnabled()) {
803   - btn = mxUtils.button(action.label, function (evt) {
804   - action.funct(evt, evt);
805   - });
806   -
807   - var short = action.shortcut != null ? " (" + action.shortcut + ")" : "";
808   - btn.setAttribute("title", action.label + short);
809   - btn.style.marginBottom = "2px";
810   - btn.style.width = "210px";
811   - div.appendChild(btn);
812   - result = true;
813   - }
814   -
815   - return btn;
816   -};
817   -
818   -/**
819   - *
820   - */
821   -BaseFormatPanel.prototype.addActions = function (div, names) {
822   - var lastBr = null;
823   - var last = null;
824   - var count = 0;
825   -
826   - for (var i = 0; i < names.length; i++) {
827   - var btn = this.addAction(div, names[i]);
828   -
829   - if (btn != null) {
830   - count++;
831   -
832   - if (mxUtils.mod(count, 2) == 0) {
833   - last.style.marginRight = "2px";
834   - last.style.width = "104px";
835   - btn.style.width = "104px";
836   - lastBr.parentNode.removeChild(lastBr);
837   - }
838   -
839   - lastBr = mxUtils.br(div);
840   - last = btn;
841   - }
842   - }
843   -
844   - return count;
845   -};
846   -
847   -/**
848   - *
849   - */
850   -BaseFormatPanel.prototype.createStepper = function (
851   - input,
852   - update,
853   - step,
854   - height,
855   - disableFocus,
856   - defaultValue,
857   - isFloat,
858   -) {
859   - step = step != null ? step : 1;
860   - height = height != null ? height : 9;
861   - var bigStep = 10 * step;
862   -
863   - var stepper = document.createElement("div");
864   - mxUtils.setPrefixedStyle(stepper.style, "borderRadius", "3px");
865   - stepper.style.border = "1px solid rgb(192, 192, 192)";
866   - stepper.style.position = "absolute";
867   -
868   - var up = document.createElement("div");
869   - up.style.borderBottom = "1px solid rgb(192, 192, 192)";
870   - up.style.position = "relative";
871   - up.style.height = height + "px";
872   - up.style.width = "10px";
873   - up.className = "geBtnUp";
874   - stepper.appendChild(up);
875   -
876   - var down = up.cloneNode(false);
877   - down.style.border = "none";
878   - down.style.height = height + "px";
879   - down.className = "geBtnDown";
880   - stepper.appendChild(down);
881   -
882   - mxEvent.addGestureListeners(
883   - down,
884   - function (evt) {
885   - // Stops text selection on shift+click
886   - mxEvent.consume(evt);
887   - },
888   - null,
889   - function (evt) {
890   - if (input.value == "") {
891   - input.value = defaultValue || "2";
892   - }
893   -
894   - var val = isFloat ? parseFloat(input.value) : parseInt(input.value);
895   -
896   - if (!isNaN(val)) {
897   - input.value = val - (mxEvent.isShiftDown(evt) ? bigStep : step);
898   -
899   - if (update != null) {
900   - update(evt);
901   - }
902   - }
903   -
904   - mxEvent.consume(evt);
905   - },
906   - );
907   -
908   - mxEvent.addGestureListeners(
909   - up,
910   - function (evt) {
911   - // Stops text selection on shift+click
912   - mxEvent.consume(evt);
913   - },
914   - null,
915   - function (evt) {
916   - if (input.value == "") {
917   - input.value = defaultValue || "0";
918   - }
919   -
920   - var val = isFloat ? parseFloat(input.value) : parseInt(input.value);
921   -
922   - if (!isNaN(val)) {
923   - input.value = val + (mxEvent.isShiftDown(evt) ? bigStep : step);
924   -
925   - if (update != null) {
926   - update(evt);
927   - }
928   - }
929   -
930   - mxEvent.consume(evt);
931   - },
932   - );
933   -
934   - // Disables transfer of focus to DIV but also :active CSS
935   - // so it's only used for fontSize where the focus should
936   - // stay on the selected text, but not for any other input.
937   - if (disableFocus) {
938   - var currentSelection = null;
939   -
940   - mxEvent.addGestureListeners(
941   - stepper,
942   - function (evt) {
943   - mxEvent.consume(evt);
944   - },
945   - null,
946   - function (evt) {
947   - // Workaround for lost current selection in page because of focus in IE
948   - if (currentSelection != null) {
949   - try {
950   - currentSelection.select();
951   - } catch (e) {
952   - // ignore
953   - }
954   -
955   - currentSelection = null;
956   - mxEvent.consume(evt);
957   - }
958   - },
959   - );
960   - } else {
961   - // Stops propagation on checkbox labels
962   - mxEvent.addListener(stepper, "click", function (evt) {
963   - mxEvent.consume(evt);
964   - });
965   - }
966   -
967   - return stepper;
968   -};
969   -
970   -/**
971   - * Adds the given option.
972   - */
973   -BaseFormatPanel.prototype.createOption = function (
974   - label,
975   - isCheckedFn,
976   - setCheckedFn,
977   - listener,
978   - fn,
979   -) {
980   - var div = document.createElement("div");
981   - div.style.padding = "3px 0px 3px 0px";
982   - div.style.whiteSpace = "nowrap";
983   - div.style.textOverflow = "ellipsis";
984   - div.style.overflow = "hidden";
985   - div.style.width = "200px";
986   - div.style.height = "18px";
987   -
988   - var cb = document.createElement("input");
989   - cb.setAttribute("type", "checkbox");
990   - cb.style.margin = "1px 6px 0px 0px";
991   - cb.style.verticalAlign = "top";
992   - div.appendChild(cb);
993   -
994   - var span = document.createElement("span");
995   - span.style.verticalAlign = "top";
996   - span.style.userSelect = "none";
997   - mxUtils.write(span, label);
998   - div.appendChild(span);
999   -
1000   - var applying = false;
1001   - var value = isCheckedFn();
1002   -
1003   - var apply = function (newValue, evt) {
1004   - if (!applying) {
1005   - applying = true;
1006   -
1007   - if (newValue) {
1008   - cb.setAttribute("checked", "checked");
1009   - cb.defaultChecked = true;
1010   - cb.checked = true;
1011   - } else {
1012   - cb.removeAttribute("checked");
1013   - cb.defaultChecked = false;
1014   - cb.checked = false;
1015   - }
1016   -
1017   - if (value != newValue) {
1018   - value = newValue;
1019   -
1020   - // Checks if the color value needs to be updated in the model
1021   - if (isCheckedFn() != value) {
1022   - setCheckedFn(value, evt);
1023   - }
1024   - }
1025   -
1026   - applying = false;
1027   - }
1028   - };
1029   -
1030   - mxEvent.addListener(div, "click", function (evt) {
1031   - if (cb.getAttribute("disabled") != "disabled") {
1032   - // Toggles checkbox state for click on label
1033   - var source = mxEvent.getSource(evt);
1034   -
1035   - if (source == div || source == span) {
1036   - cb.checked = !cb.checked;
1037   - }
1038   -
1039   - apply(cb.checked, evt);
1040   - }
1041   - });
1042   -
1043   - apply(value);
1044   -
1045   - if (listener != null) {
1046   - listener.install(apply);
1047   - this.listeners.push(listener);
1048   - }
1049   -
1050   - if (fn != null) {
1051   - fn(div);
1052   - }
1053   -
1054   - return div;
1055   -};
1056   -
1057   -/**
1058   - * The string 'null' means use null in values.
1059   - */
1060   -BaseFormatPanel.prototype.createCellOption = function (
1061   - label,
1062   - key,
1063   - defaultValue,
1064   - enabledValue,
1065   - disabledValue,
1066   - fn,
1067   - action,
1068   - stopEditing,
1069   - cells,
1070   -) {
1071   - var ui = this.editorUi;
1072   - var editor = ui.editor;
1073   - var graph = editor.graph;
1074   -
1075   - enabledValue =
1076   - enabledValue != null ? (enabledValue == "null" ? null : enabledValue) : 1;
1077   - disabledValue =
1078   - disabledValue != null
1079   - ? disabledValue == "null"
1080   - ? null
1081   - : disabledValue
1082   - : 0;
1083   -
1084   - var style =
1085   - cells != null ? graph.getCommonStyle(cells) : ui.getSelectionState().style;
1086   -
1087   - return this.createOption(
1088   - label,
1089   - function () {
1090   - return mxUtils.getValue(style, key, defaultValue) != disabledValue;
1091   - },
1092   - function (checked) {
1093   - if (stopEditing) {
1094   - graph.stopEditing();
1095   - }
1096   -
1097   - if (action != null) {
1098   - action.funct();
1099   - } else {
1100   - graph.getModel().beginUpdate();
1101   - try {
1102   - var temp = cells != null ? cells : ui.getSelectionState().cells;
1103   - var value = checked ? enabledValue : disabledValue;
1104   - graph.setCellStyles(key, value, temp);
1105   -
1106   - if (fn != null) {
1107   - fn(temp, value);
1108   - }
1109   -
1110   - ui.fireEvent(
1111   - new mxEventObject(
1112   - "styleChanged",
1113   - "keys",
1114   - [key],
1115   - "values",
1116   - [value],
1117   - "cells",
1118   - temp,
1119   - ),
1120   - );
1121   - } finally {
1122   - graph.getModel().endUpdate();
1123   - }
1124   - }
1125   - },
1126   - {
1127   - install: function (apply) {
1128   - this.listener = function () {
1129   - apply(mxUtils.getValue(style, key, defaultValue) != disabledValue);
1130   - };
1131   -
1132   - graph.getModel().addListener(mxEvent.CHANGE, this.listener);
1133   - },
1134   - destroy: function () {
1135   - graph.getModel().removeListener(this.listener);
1136   - },
1137   - },
1138   - );
1139   -};
1140   -
1141   -/**
1142   - * Adds the given color option.
1143   - */
1144   -BaseFormatPanel.prototype.createColorOption = function (
1145   - label,
1146   - getColorFn,
1147   - setColorFn,
1148   - defaultColor,
1149   - listener,
1150   - callbackFn,
1151   - hideCheckbox,
1152   - defaultColorValue,
1153   -) {
1154   - var div = document.createElement("div");
1155   - div.style.padding = "3px 0px 3px 0px";
1156   - div.style.whiteSpace = "nowrap";
1157   - div.style.overflow = "hidden";
1158   - div.style.width = "200px";
1159   - div.style.height = "18px";
1160   -
1161   - var cb = document.createElement("input");
1162   - cb.setAttribute("type", "checkbox");
1163   - cb.style.margin = "1px 6px 0px 0px";
1164   - cb.style.verticalAlign = "top";
1165   -
1166   - if (!hideCheckbox) {
1167   - div.appendChild(cb);
1168   - }
1169   -
1170   - var span = document.createElement("span");
1171   - span.style.verticalAlign = "top";
1172   - mxUtils.write(span, label);
1173   - div.appendChild(span);
1174   -
1175   - var title = "Shift+Click for Color Dropper";
1176   - var value = getColorFn();
1177   - var applying = false;
1178   - var btn = null;
1179   -
1180   - var apply = function (color, disableUpdate, forceUpdate) {
1181   - if (!applying) {
1182   - var defaultValue = defaultColor == "null" ? null : defaultColor;
1183   -
1184   - applying = true;
1185   - color = /(^#?[a-zA-Z0-9]*$)/.test(color) ? color : defaultValue;
1186   - var tempColor =
1187   - color != null && color != mxConstants.NONE ? color : defaultValue;
1188   -
1189   - var div = document.createElement("div");
1190   - div.style.width = "36px";
1191   - div.style.height = "12px";
1192   - div.style.margin = "3px";
1193   - div.style.border = "1px solid black";
1194   - div.style.backgroundColor =
1195   - tempColor == "default" ? defaultColorValue : tempColor;
1196   - btn.innerHTML = "";
1197   - btn.appendChild(div);
1198   -
1199   - if (
1200   - color != null &&
1201   - color != mxConstants.NONE &&
1202   - color.length > 1 &&
1203   - typeof color === "string"
1204   - ) {
1205   - var clr =
1206   - color.charAt(0) == "#" ? color.substring(1).toUpperCase() : color;
1207   - var name = ColorDialog.prototype.colorNames[clr];
1208   - btn.setAttribute(
1209   - "title",
1210   - name != null ? name + " (" + title + ")" : title,
1211   - );
1212   - }
1213   -
1214   - if (color != null && color != mxConstants.NONE) {
1215   - cb.setAttribute("checked", "checked");
1216   - cb.defaultChecked = true;
1217   - cb.checked = true;
1218   - } else {
1219   - cb.removeAttribute("checked");
1220   - cb.defaultChecked = false;
1221   - cb.checked = false;
1222   - }
1223   -
1224   - btn.style.display = cb.checked || hideCheckbox ? "" : "none";
1225   -
1226   - if (callbackFn != null) {
1227   - callbackFn(color == "null" ? null : color);
1228   - }
1229   -
1230   - value = color;
1231   -
1232   - if (!disableUpdate) {
1233   - // Checks if the color value needs to be updated in the model
1234   - if (forceUpdate || hideCheckbox || getColorFn() != value) {
1235   - setColorFn(value == "null" ? null : value, value);
1236   - }
1237   - }
1238   -
1239   - applying = false;
1240   - }
1241   - };
1242   -
1243   - var clrInput = document.createElement("input");
1244   - clrInput.setAttribute("type", "color");
1245   - clrInput.style.visibility = "hidden";
1246   - clrInput.style.width = "0px";
1247   - clrInput.style.height = "0px";
1248   - clrInput.style.border = "none";
1249   - div.appendChild(clrInput);
1250   -
1251   - btn = mxUtils.button(
1252   - "",
1253   - mxUtils.bind(this, function (evt) {
1254   - var color = value;
1255   -
1256   - if (color == "default") {
1257   - color = defaultColorValue;
1258   - }
1259   -
1260   - if (mxEvent.isShiftDown(evt) && !mxClient.IS_IE && !mxClient.IS_IE11) {
1261   - clrInput.value = color;
1262   - clrInput.click();
1263   -
1264   - mxEvent.addListener(clrInput, "input", function () {
1265   - apply(clrInput.value, null, true);
1266   - });
1267   - } else {
1268   - this.editorUi.pickColor(
1269   - color,
1270   - function (newColor) {
1271   - apply(newColor, null, true);
1272   - },
1273   - defaultColorValue,
1274   - );
1275   - }
1276   -
1277   - mxEvent.consume(evt);
1278   - }),
1279   - );
1280   -
1281   - btn.style.position = "absolute";
1282   - btn.style.marginTop = "-3px";
1283   - btn.style.left = "178px";
1284   - btn.style.height = "22px";
1285   - btn.className = "geColorBtn";
1286   - btn.style.display = cb.checked || hideCheckbox ? "" : "none";
1287   - div.appendChild(btn);
1288   -
1289   - var clr =
1290   - value != null && typeof value === "string" && value.charAt(0) == "#"
1291   - ? value.substring(1).toUpperCase()
1292   - : value;
1293   - var name = ColorDialog.prototype.colorNames[clr];
1294   - btn.setAttribute("title", name != null ? name + " (" + title + ")" : title);
1295   -
1296   - mxEvent.addListener(div, "click", function (evt) {
1297   - var source = mxEvent.getSource(evt);
1298   -
1299   - if (source == cb || source.nodeName != "INPUT") {
1300   - // Toggles checkbox state for click on label
1301   - if (source != cb) {
1302   - cb.checked = !cb.checked;
1303   - }
1304   -
1305   - // Overrides default value with current value to make it easier
1306   - // to restore previous value if the checkbox is clicked twice
1307   - if (
1308   - !cb.checked &&
1309   - value != null &&
1310   - value != mxConstants.NONE &&
1311   - defaultColor != mxConstants.NONE
1312   - ) {
1313   - defaultColor = value;
1314   - }
1315   -
1316   - apply(cb.checked ? defaultColor : mxConstants.NONE);
1317   - }
1318   - });
1319   -
1320   - apply(value, true);
1321   -
1322   - if (listener != null) {
1323   - listener.install(apply);
1324   - this.listeners.push(listener);
1325   - }
1326   -
1327   - return div;
1328   -};
1329   -
1330   -/**
1331   - *
1332   - */
1333   -BaseFormatPanel.prototype.createCellColorOption = function (
1334   - label,
1335   - colorKey,
1336   - defaultColor,
1337   - callbackFn,
1338   - setStyleFn,
1339   - defaultColorValue,
1340   -) {
1341   - var ui = this.editorUi;
1342   - var editor = ui.editor;
1343   - var graph = editor.graph;
1344   -
1345   - return this.createColorOption(
1346   - label,
1347   - function () {
1348   - // Seems to be null sometimes, not sure why...
1349   - var state = graph.view.getState(ui.getSelectionState().cells[0]);
1350   -
1351   - if (state != null) {
1352   - return mxUtils.getValue(state.style, colorKey, null);
1353   - }
1354   -
1355   - return null;
1356   - },
1357   - function (color, realValue) {
1358   - graph.getModel().beginUpdate();
1359   - try {
1360   - var cells = ui.getSelectionState().cells;
1361   - graph.setCellStyles(colorKey, color, cells);
1362   -
1363   - if (setStyleFn != null) {
1364   - setStyleFn(color);
1365   - }
1366   -
1367   - ui.fireEvent(
1368   - new mxEventObject(
1369   - "styleChanged",
1370   - "keys",
1371   - [colorKey],
1372   - "values",
1373   - [color],
1374   - "cells",
1375   - cells,
1376   - ),
1377   - );
1378   - } finally {
1379   - graph.getModel().endUpdate();
1380   - }
1381   - },
1382   - defaultColor || mxConstants.NONE,
1383   - {
1384   - install: function (apply) {
1385   - this.listener = function () {
1386   - // Seems to be null sometimes, not sure why...
1387   - var state = graph.view.getState(ui.getSelectionState().cells[0]);
1388   -
1389   - if (state != null) {
1390   - apply(mxUtils.getValue(state.style, colorKey, null), true);
1391   - }
1392   - };
1393   -
1394   - graph.getModel().addListener(mxEvent.CHANGE, this.listener);
1395   - },
1396   - destroy: function () {
1397   - graph.getModel().removeListener(this.listener);
1398   - },
1399   - },
1400   - callbackFn,
1401   - null,
1402   - defaultColorValue,
1403   - );
1404   -};
1405   -
1406   -/**
1407   - *
1408   - */
1409   -BaseFormatPanel.prototype.addArrow = function (elt, height) {
1410   - height = height != null ? height : 10;
1411   -
1412   - var arrow = document.createElement("div");
1413   - arrow.style.display = "inline-block";
1414   - arrow.style.paddingRight = "4px";
1415   - arrow.style.padding = "6px";
1416   -
1417   - var m = 10 - height;
1418   -
1419   - if (m == 2) {
1420   - arrow.style.paddingTop = 6 + "px";
1421   - } else if (m > 0) {
1422   - arrow.style.paddingTop = 6 - m + "px";
1423   - } else {
1424   - arrow.style.marginTop = "-2px";
1425   - }
1426   -
1427   - arrow.style.height = height + "px";
1428   - arrow.style.borderLeft = "1px solid #a0a0a0";
1429   -
1430   - var img = document.createElement("img");
1431   - img.setAttribute("border", "0");
1432   - img.setAttribute("valign", "middle");
1433   - img.setAttribute("src", Toolbar.prototype.dropDownImage);
1434   - arrow.appendChild(img);
1435   -
1436   - var img = arrow.getElementsByTagName("img")[0];
1437   - img.style.position = "relative";
1438   - img.style.left = "1px";
1439   - img.style.top = mxClient.IS_FF ? "0px" : "-4px";
1440   - mxUtils.setOpacity(arrow, 70);
1441   -
1442   - var symbol = elt.getElementsByTagName("div")[0];
1443   -
1444   - if (symbol != null) {
1445   - symbol.style.paddingRight = "6px";
1446   - symbol.style.marginLeft = "4px";
1447   - symbol.style.marginTop = "-1px";
1448   - symbol.style.display = "inline-block";
1449   - mxUtils.setOpacity(symbol, 60);
1450   - }
1451   -
1452   - mxUtils.setOpacity(elt, 100);
1453   - elt.style.border = "1px solid #a0a0a0";
1454   - elt.style.backgroundColor = this.buttonBackgroundColor;
1455   - elt.style.backgroundImage = "none";
1456   - elt.style.width = "auto";
1457   - elt.className += " geColorBtn";
1458   - mxUtils.setPrefixedStyle(elt.style, "borderRadius", "3px");
1459   -
1460   - elt.appendChild(arrow);
1461   -
1462   - return symbol;
1463   -};
1464   -
1465   -/**
1466   - *
1467   - */
1468   -BaseFormatPanel.prototype.addUnitInput = function (
1469   - container,
1470   - unit,
1471   - right,
1472   - width,
1473   - update,
1474   - step,
1475   - marginTop,
1476   - disableFocus,
1477   - isFloat,
1478   -) {
1479   - marginTop = marginTop != null ? marginTop : 0;
1480   -
1481   - var input = document.createElement("input");
1482   - input.style.position = "absolute";
1483   - input.style.textAlign = "right";
1484   - input.style.marginTop = "-2px";
1485   - input.style.left = 228 - right - width + "px";
1486   - input.style.width = width + "px";
1487   - input.style.height = "21px";
1488   - input.style.border = "1px solid rgb(160, 160, 160)";
1489   - input.style.borderRadius = "4px";
1490   - input.style.boxSizing = "border-box";
1491   -
1492   - container.appendChild(input);
1493   -
1494   - var stepper = this.createStepper(
1495   - input,
1496   - update,
1497   - step,
1498   - null,
1499   - disableFocus,
1500   - null,
1501   - isFloat,
1502   - );
1503   - stepper.style.marginTop = marginTop - 2 + "px";
1504   - stepper.style.left = 228 - right + "px";
1505   - container.appendChild(stepper);
1506   -
1507   - return input;
1508   -};
1509   -
1510   -/**
1511   - *
1512   - */
1513   -BaseFormatPanel.prototype.createRelativeOption = function (
1514   - label,
1515   - key,
1516   - width,
1517   - handler,
1518   - init,
1519   -) {
1520   - width = width != null ? width : 52;
1521   -
1522   - var ui = this.editorUi;
1523   - var graph = ui.editor.graph;
1524   - var div = this.createPanel();
1525   - div.style.paddingTop = "10px";
1526   - div.style.paddingBottom = "10px";
1527   - mxUtils.write(div, label);
1528   - div.style.fontWeight = "bold";
1529   -
1530   - var update = mxUtils.bind(this, function (evt) {
1531   - if (handler != null) {
1532   - handler(input);
1533   - } else {
1534   - var value = parseInt(input.value);
1535   - value = Math.min(100, Math.max(0, isNaN(value) ? 100 : value));
1536   - var state = graph.view.getState(ui.getSelectionState().cells[0]);
1537   -
1538   - if (state != null && value != mxUtils.getValue(state.style, key, 100)) {
1539   - // Removes entry in style (assumes 100 is default for relative values)
1540   - if (value == 100) {
1541   - value = null;
1542   - }
1543   -
1544   - var cells = ui.getSelectionState().cells;
1545   - graph.setCellStyles(key, value, cells);
1546   - this.editorUi.fireEvent(
1547   - new mxEventObject(
1548   - "styleChanged",
1549   - "keys",
1550   - [key],
1551   - "values",
1552   - [value],
1553   - "cells",
1554   - cells,
1555   - ),
1556   - );
1557   - }
1558   -
1559   - input.value = (value != null ? value : "100") + " %";
1560   - }
1561   -
1562   - mxEvent.consume(evt);
1563   - });
1564   -
1565   - var input = this.addUnitInput(
1566   - div,
1567   - "%",
1568   - 16,
1569   - width,
1570   - update,
1571   - 10,
1572   - -15,
1573   - handler != null,
1574   - );
1575   -
1576   - if (key != null) {
1577   - var listener = mxUtils.bind(this, function (sender, evt, force) {
1578   - if (force || input != document.activeElement) {
1579   - var ss = ui.getSelectionState();
1580   - var tmp = parseInt(mxUtils.getValue(ss.style, key, 100));
1581   - input.value = isNaN(tmp) ? "" : tmp + " %";
1582   - }
1583   - });
1584   -
1585   - mxEvent.addListener(input, "keydown", function (e) {
1586   - if (e.keyCode == 13) {
1587   - graph.container.focus();
1588   - mxEvent.consume(e);
1589   - } else if (e.keyCode == 27) {
1590   - listener(null, null, true);
1591   - graph.container.focus();
1592   - mxEvent.consume(e);
1593   - }
1594   - });
1595   -
1596   - graph.getModel().addListener(mxEvent.CHANGE, listener);
1597   - this.listeners.push({
1598   - destroy: function () {
1599   - graph.getModel().removeListener(listener);
1600   - },
1601   - });
1602   - listener();
1603   - }
1604   -
1605   - mxEvent.addListener(input, "blur", update);
1606   - mxEvent.addListener(input, "change", update);
1607   -
1608   - if (init != null) {
1609   - init(input);
1610   - }
1611   -
1612   - return div;
1613   -};
1614   -
1615   -/**
1616   - *
1617   - */
1618   -BaseFormatPanel.prototype.addLabel = function (div, title, right, width) {
1619   - width = width != null ? width : 61;
1620   -
1621   - var label = document.createElement("div");
1622   - mxUtils.write(label, title);
1623   - label.style.position = "absolute";
1624   - label.style.left = 240 - right - width + "px";
1625   - label.style.width = width + "px";
1626   - label.style.marginTop = "6px";
1627   - label.style.textAlign = "center";
1628   - div.appendChild(label);
1629   -};
1630   -
1631   -/**
1632   - *
1633   - */
1634   -BaseFormatPanel.prototype.addKeyHandler = function (input, listener) {
1635   - mxEvent.addListener(
1636   - input,
1637   - "keydown",
1638   - mxUtils.bind(this, function (e) {
1639   - if (e.keyCode == 13) {
1640   - this.editorUi.editor.graph.container.focus();
1641   - mxEvent.consume(e);
1642   - } else if (e.keyCode == 27) {
1643   - if (listener != null) {
1644   - listener(null, null, true);
1645   - }
1646   -
1647   - this.editorUi.editor.graph.container.focus();
1648   - mxEvent.consume(e);
1649   - }
1650   - }),
1651   - );
1652   -};
1653   -
1654   -/**
1655   - *
1656   - */
1657   -BaseFormatPanel.prototype.styleButtons = function (elts) {
1658   - for (var i = 0; i < elts.length; i++) {
1659   - mxUtils.setPrefixedStyle(elts[i].style, "borderRadius", "3px");
1660   - mxUtils.setOpacity(elts[i], 100);
1661   - elts[i].style.border = "1px solid #a0a0a0";
1662   - elts[i].style.padding = "4px";
1663   - elts[i].style.paddingTop = "3px";
1664   - elts[i].style.paddingRight = "1px";
1665   - elts[i].style.margin = "1px";
1666   - elts[i].style.marginRight = "2px";
1667   - elts[i].style.width = "24px";
1668   - elts[i].style.height = "20px";
1669   - elts[i].className += " geColorBtn";
1670   - }
1671   -};
1672   -
1673   -/**
1674   - * Adds the label menu items to the given menu and parent.
1675   - */
1676   -BaseFormatPanel.prototype.destroy = function () {
1677   - if (this.listeners != null) {
1678   - for (var i = 0; i < this.listeners.length; i++) {
1679   - this.listeners[i].destroy();
1680   - }
1681   -
1682   - this.listeners = null;
1683   - }
1684   -};
1685   -
1686   -/**
1687   - * Adds the label menu items to the given menu and parent.
1688   - */
1689   -ArrangePanel = function (format, editorUi, container) {
1690   - BaseFormatPanel.call(this, format, editorUi, container);
1691   - this.init();
1692   -};
1693   -
1694   -mxUtils.extend(ArrangePanel, BaseFormatPanel);
1695   -
1696   -/**
1697   - * Adds the label menu items to the given menu and parent.
1698   - */
1699   -ArrangePanel.prototype.init = function () {
1700   - var ss = this.editorUi.getSelectionState();
1701   -
1702   - if (ss.cells.length > 0) {
1703   - this.container.appendChild(this.addLayerOps(this.createPanel()));
1704   -
1705   - // Special case that adds two panels
1706   - this.addGeometry(this.container);
1707   - this.addEdgeGeometry(this.container);
1708   -
1709   - if (!ss.containsLabel || ss.edges.length == 0) {
1710   - this.container.appendChild(this.addAngle(this.createPanel()));
1711   - }
1712   -
1713   - if (!ss.containsLabel) {
1714   - this.container.appendChild(this.addFlip(this.createPanel()));
1715   - }
1716   -
1717   - this.container.appendChild(this.addAlign(this.createPanel()));
1718   -
1719   - if (ss.vertices.length > 1 && !ss.cell && !ss.row) {
1720   - this.container.appendChild(this.addDistribute(this.createPanel()));
1721   - }
1722   -
1723   - this.container.appendChild(this.addTable(this.createPanel()));
1724   - this.container.appendChild(this.addGroupOps(this.createPanel()));
1725   - }
1726   -
1727   - if (ss.containsLabel) {
1728   - // Adds functions from hidden style format panel
1729   - var span = document.createElement("div");
1730   - span.style.width = "100%";
1731   - span.style.marginTop = "0px";
1732   - span.style.fontWeight = "bold";
1733   - span.style.padding = "10px 0 0 14px";
1734   - mxUtils.write(span, mxResources.get("style"));
1735   - this.container.appendChild(span);
1736   -
1737   - new StyleFormatPanel(this.format, this.editorUi, this.container);
1738   - }
1739   -};
1740   -
1741   -/**
1742   - *
1743   - */
1744   -ArrangePanel.prototype.addTable = function (div) {
1745   - var ui = this.editorUi;
1746   - var editor = ui.editor;
1747   - var graph = editor.graph;
1748   - var ss = ui.getSelectionState();
1749   - div.style.paddingTop = "6px";
1750   - div.style.paddingBottom = "10px";
1751   -
1752   - var span = document.createElement("div");
1753   - span.style.marginTop = "0px";
1754   - span.style.marginBottom = "6px";
1755   - span.style.fontWeight = "bold";
1756   - mxUtils.write(span, mxResources.get("table"));
1757   - div.appendChild(span);
1758   -
1759   - var panel = document.createElement("div");
1760   - panel.style.position = "relative";
1761   - panel.style.paddingLeft = "0px";
1762   - panel.style.borderWidth = "0px";
1763   - panel.style.width = "220px";
1764   - panel.className = "geToolbarContainer";
1765   -
1766   - var cell = ss.vertices[0];
1767   -
1768   - if (graph.getSelectionCount() > 1) {
1769   - if (graph.isTableCell(cell)) {
1770   - cell = graph.model.getParent(cell);
1771   - }
1772   -
1773   - if (graph.isTableRow(cell)) {
1774   - cell = graph.model.getParent(cell);
1775   - }
1776   - }
1777   -
1778   - var isTable = ss.table || ss.row || ss.cell;
1779   - var isStack = graph.isStack(cell) || graph.isStackChild(cell);
1780   -
1781   - var showCols = isTable;
1782   - var showRows = isTable;
1783   -
1784   - if (isStack) {
1785   - var style = graph.isStack(cell)
1786   - ? ss.style
1787   - : graph.getCellStyle(graph.model.getParent(cell));
1788   -
1789   - showRows = style["horizontalStack"] == "0";
1790   - showCols = !showRows;
1791   - }
1792   -
1793   - var btns = [];
1794   -
1795   - if (showCols) {
1796   - btns = btns.concat([
1797   - ui.toolbar.addButton(
1798   - "geSprite-insertcolumnbefore",
1799   - mxResources.get("insertColumnBefore"),
1800   - mxUtils.bind(this, function () {
1801   - try {
1802   - if (isStack) {
1803   - graph.insertLane(cell, true);
1804   - } else {
1805   - graph.insertTableColumn(cell, true);
1806   - }
1807   - } catch (e) {
1808   - ui.handleError(e);
1809   - }
1810   - }),
1811   - panel,
1812   - ),
1813   - ui.toolbar.addButton(
1814   - "geSprite-insertcolumnafter",
1815   - mxResources.get("insertColumnAfter"),
1816   - mxUtils.bind(this, function () {
1817   - try {
1818   - if (isStack) {
1819   - graph.insertLane(cell, false);
1820   - } else {
1821   - graph.insertTableColumn(cell, false);
1822   - }
1823   - } catch (e) {
1824   - ui.handleError(e);
1825   - }
1826   - }),
1827   - panel,
1828   - ),
1829   - ui.toolbar.addButton(
1830   - "geSprite-deletecolumn",
1831   - mxResources.get("deleteColumn"),
1832   - mxUtils.bind(this, function () {
1833   - try {
1834   - if (isStack) {
1835   - graph.deleteLane(cell);
1836   - } else {
1837   - graph.deleteTableColumn(cell);
1838   - }
1839   - } catch (e) {
1840   - ui.handleError(e);
1841   - }
1842   - }),
1843   - panel,
1844   - ),
1845   - ]);
1846   - }
1847   -
1848   - if (showRows) {
1849   - btns = btns.concat([
1850   - ui.toolbar.addButton(
1851   - "geSprite-insertrowbefore",
1852   - mxResources.get("insertRowBefore"),
1853   - mxUtils.bind(this, function () {
1854   - try {
1855   - if (isStack) {
1856   - graph.insertLane(cell, true);
1857   - } else {
1858   - graph.insertTableRow(cell, true);
1859   - }
1860   - } catch (e) {
1861   - ui.handleError(e);
1862   - }
1863   - }),
1864   - panel,
1865   - ),
1866   - ui.toolbar.addButton(
1867   - "geSprite-insertrowafter",
1868   - mxResources.get("insertRowAfter"),
1869   - mxUtils.bind(this, function () {
1870   - try {
1871   - if (isStack) {
1872   - graph.insertLane(cell, false);
1873   - } else {
1874   - graph.insertTableRow(cell, false);
1875   - }
1876   - } catch (e) {
1877   - ui.handleError(e);
1878   - }
1879   - }),
1880   - panel,
1881   - ),
1882   - ui.toolbar.addButton(
1883   - "geSprite-deleterow",
1884   - mxResources.get("deleteRow"),
1885   - mxUtils.bind(this, function () {
1886   - try {
1887   - if (isStack) {
1888   - graph.deleteLane(cell);
1889   - } else {
1890   - graph.deleteTableRow(cell);
1891   - }
1892   - } catch (e) {
1893   - ui.handleError(e);
1894   - }
1895   - }),
1896   - panel,
1897   - ),
1898   - ]);
1899   - }
1900   -
1901   - if (btns.length > 0) {
1902   - this.styleButtons(btns);
1903   - div.appendChild(panel);
1904   -
1905   - if (btns.length > 3) {
1906   - btns[2].style.marginRight = "10px";
1907   - }
1908   -
1909   - var count = 0;
1910   -
1911   - if (ss.mergeCell != null) {
1912   - count += this.addActions(div, ["mergeCells"]);
1913   - } else if (ss.style["colspan"] > 1 || ss.style["rowspan"] > 1) {
1914   - count += this.addActions(div, ["unmergeCells"]);
1915   - }
1916   -
1917   - if (count > 0) {
1918   - panel.style.paddingBottom = "2px";
1919   - }
1920   - } else {
1921   - div.style.display = "none";
1922   - }
1923   -
1924   - return div;
1925   -};
1926   -
1927   -/**
1928   - *
1929   - */
1930   -ArrangePanel.prototype.addLayerOps = function (div) {
1931   - this.addActions(div, ["toFront", "toBack"]);
1932   - this.addActions(div, ["bringForward", "sendBackward"]);
1933   -
1934   - return div;
1935   -};
1936   -
1937   -/**
1938   - *
1939   - */
1940   -ArrangePanel.prototype.addGroupOps = function (div) {
1941   - var ui = this.editorUi;
1942   - var graph = ui.editor.graph;
1943   - var ss = ui.getSelectionState();
1944   -
1945   - div.style.paddingTop = "8px";
1946   - div.style.paddingBottom = "6px";
1947   -
1948   - var count = 0;
1949   -
1950   - if (!ss.cell && !ss.row) {
1951   - count +=
1952   - this.addActions(div, ["group", "ungroup", "copySize", "pasteSize"]) +
1953   - this.addActions(div, ["removeFromGroup"]);
1954   - }
1955   -
1956   - var copyBtn = null;
1957   -
1958   - if (
1959   - ss.cells.length == 1 &&
1960   - ss.cells[0].value != null &&
1961   - !isNaN(ss.cells[0].value.nodeType)
1962   - ) {
1963   - copyBtn = mxUtils.button(mxResources.get("copyData"), function (evt) {
1964   - if (mxEvent.isShiftDown(evt)) {
1965   - var result = graph.getDataForCells(graph.getSelectionCells());
1966   -
1967   - var dlg = new EmbedDialog(
1968   - ui,
1969   - JSON.stringify(result, null, 2),
1970   - null,
1971   - null,
1972   - function () {
1973   - console.log(result);
1974   - ui.alert("Written to Console (Dev Tools)");
1975   - },
1976   - mxResources.get("copyData"),
1977   - null,
1978   - "Console",
1979   - "data.json",
1980   - );
1981   - ui.showDialog(dlg.container, 450, 240, true, true);
1982   - dlg.init();
1983   - } else {
1984   - ui.actions.get("copyData").funct(evt);
1985   - }
1986   - });
1987   -
1988   - copyBtn.setAttribute(
1989   - "title",
1990   - mxResources.get("copyData") +
1991   - " (" +
1992   - this.editorUi.actions.get("copyData").shortcut +
1993   - ")" +
1994   - " Shift+Click to Extract Data",
1995   - );
1996   - copyBtn.style.marginBottom = "2px";
1997   - copyBtn.style.width = "210px";
1998   - div.appendChild(copyBtn);
1999   - count++;
2000   - }
2001   -
2002   - var pasteBtn = null;
2003   -
2004   - if (ui.copiedValue != null && ss.cells.length > 0) {
2005   - pasteBtn = mxUtils.button(mxResources.get("pasteData"), function (evt) {
2006   - ui.actions.get("pasteData").funct(evt);
2007   - });
2008   -
2009   - pasteBtn.setAttribute(
2010   - "title",
2011   - mxResources.get("pasteData") +
2012   - " (" +
2013   - this.editorUi.actions.get("pasteData").shortcut +
2014   - ")",
2015   - );
2016   - pasteBtn.style.marginBottom = "2px";
2017   - pasteBtn.style.width = "210px";
2018   - div.appendChild(pasteBtn);
2019   - count++;
2020   -
2021   - if (copyBtn != null) {
2022   - copyBtn.style.width = "104px";
2023   - pasteBtn.style.width = "104px";
2024   - pasteBtn.style.marginBottom = "2px";
2025   - copyBtn.style.marginBottom = "2px";
2026   - copyBtn.style.marginRight = "2px";
2027   - }
2028   - }
2029   -
2030   - if (copyBtn != null || pasteBtn != null) {
2031   - mxUtils.br(div);
2032   - }
2033   -
2034   - var clearWaypoints = this.addAction(div, "clearWaypoints");
2035   -
2036   - if (clearWaypoints != null) {
2037   - mxUtils.br(div);
2038   - clearWaypoints.setAttribute(
2039   - "title",
2040   - mxResources.get("clearWaypoints") +
2041   - " (" +
2042   - this.editorUi.actions.get("clearWaypoints").shortcut +
2043   - ")" +
2044   - " Shift+Click to Clear Anchor Points",
2045   - );
2046   - count++;
2047   - }
2048   -
2049   - if (graph.getSelectionCount() == 1) {
2050   - count += this.addActions(div, ["editData", "editLink"]);
2051   - }
2052   -
2053   - if (count == 0) {
2054   - div.style.display = "none";
2055   - }
2056   -
2057   - return div;
2058   -};
2059   -
2060   -/**
2061   - *
2062   - */
2063   -ArrangePanel.prototype.addAlign = function (div) {
2064   - var ss = this.editorUi.getSelectionState();
2065   - var graph = this.editorUi.editor.graph;
2066   - div.style.paddingTop = "6px";
2067   - div.style.paddingBottom = "8px";
2068   - div.appendChild(this.createTitle(mxResources.get("align")));
2069   -
2070   - var stylePanel = document.createElement("div");
2071   - stylePanel.style.position = "relative";
2072   - stylePanel.style.whiteSpace = "nowrap";
2073   - stylePanel.style.paddingLeft = "0px";
2074   - stylePanel.style.paddingBottom = "2px";
2075   - stylePanel.style.borderWidth = "0px";
2076   - stylePanel.style.width = "220px";
2077   - stylePanel.className = "geToolbarContainer";
2078   -
2079   - if (ss.vertices.length > 1) {
2080   - var left = this.editorUi.toolbar.addButton(
2081   - "geSprite-alignleft",
2082   - mxResources.get("left"),
2083   - function () {
2084   - graph.alignCells(mxConstants.ALIGN_LEFT);
2085   - },
2086   - stylePanel,
2087   - );
2088   - var center = this.editorUi.toolbar.addButton(
2089   - "geSprite-aligncenter",
2090   - mxResources.get("center"),
2091   - function () {
2092   - graph.alignCells(mxConstants.ALIGN_CENTER);
2093   - },
2094   - stylePanel,
2095   - );
2096   - var right = this.editorUi.toolbar.addButton(
2097   - "geSprite-alignright",
2098   - mxResources.get("right"),
2099   - function () {
2100   - graph.alignCells(mxConstants.ALIGN_RIGHT);
2101   - },
2102   - stylePanel,
2103   - );
2104   -
2105   - var top = this.editorUi.toolbar.addButton(
2106   - "geSprite-aligntop",
2107   - mxResources.get("top"),
2108   - function () {
2109   - graph.alignCells(mxConstants.ALIGN_TOP);
2110   - },
2111   - stylePanel,
2112   - );
2113   - var middle = this.editorUi.toolbar.addButton(
2114   - "geSprite-alignmiddle",
2115   - mxResources.get("middle"),
2116   - function () {
2117   - graph.alignCells(mxConstants.ALIGN_MIDDLE);
2118   - },
2119   - stylePanel,
2120   - );
2121   - var bottom = this.editorUi.toolbar.addButton(
2122   - "geSprite-alignbottom",
2123   - mxResources.get("bottom"),
2124   - function () {
2125   - graph.alignCells(mxConstants.ALIGN_BOTTOM);
2126   - },
2127   - stylePanel,
2128   - );
2129   -
2130   - this.styleButtons([left, center, right, top, middle, bottom]);
2131   - right.style.marginRight = "10px";
2132   - }
2133   -
2134   - div.appendChild(stylePanel);
2135   - this.addActions(div, ["snapToGrid"]);
2136   -
2137   - return div;
2138   -};
2139   -
2140   -/**
2141   - *
2142   - */
2143   -ArrangePanel.prototype.addFlip = function (div) {
2144   - var ui = this.editorUi;
2145   - var editor = ui.editor;
2146   - var graph = editor.graph;
2147   - div.style.paddingTop = "6px";
2148   - div.style.paddingBottom = "10px";
2149   - var ss = this.editorUi.getSelectionState();
2150   -
2151   - var span = document.createElement("div");
2152   - span.style.marginTop = "2px";
2153   - span.style.marginBottom = "8px";
2154   - span.style.fontWeight = "bold";
2155   - mxUtils.write(span, mxResources.get("flip"));
2156   - div.appendChild(span);
2157   -
2158   - var btn = mxUtils.button(mxResources.get("horizontal"), function (evt) {
2159   - graph.flipCells(ss.cells, true);
2160   - });
2161   -
2162   - btn.setAttribute("title", mxResources.get("horizontal"));
2163   - btn.style.width = "104px";
2164   - btn.style.marginRight = "2px";
2165   - div.appendChild(btn);
2166   -
2167   - var btn = mxUtils.button(mxResources.get("vertical"), function (evt) {
2168   - graph.flipCells(ss.cells, false);
2169   - });
2170   -
2171   - btn.setAttribute("title", mxResources.get("vertical"));
2172   - btn.style.width = "104px";
2173   - div.appendChild(btn);
2174   -
2175   - return div;
2176   -};
2177   -
2178   -/**
2179   - *
2180   - */
2181   -ArrangePanel.prototype.addDistribute = function (div) {
2182   - var ui = this.editorUi;
2183   - var editor = ui.editor;
2184   - var graph = editor.graph;
2185   - div.style.paddingTop = "6px";
2186   - div.style.paddingBottom = "12px";
2187   -
2188   - div.appendChild(this.createTitle(mxResources.get("distribute")));
2189   -
2190   - var btn = mxUtils.button(mxResources.get("horizontal"), function (evt) {
2191   - graph.distributeCells(true);
2192   - });
2193   -
2194   - btn.setAttribute("title", mxResources.get("horizontal"));
2195   - btn.style.width = "104px";
2196   - btn.style.marginRight = "2px";
2197   - div.appendChild(btn);
2198   -
2199   - var btn = mxUtils.button(mxResources.get("vertical"), function (evt) {
2200   - graph.distributeCells(false);
2201   - });
2202   -
2203   - btn.setAttribute("title", mxResources.get("vertical"));
2204   - btn.style.width = "104px";
2205   - div.appendChild(btn);
2206   -
2207   - return div;
2208   -};
2209   -
2210   -/**
2211   - *
2212   - */
2213   -ArrangePanel.prototype.addAngle = function (div) {
2214   - var ui = this.editorUi;
2215   - var editor = ui.editor;
2216   - var graph = editor.graph;
2217   - var ss = ui.getSelectionState();
2218   -
2219   - div.style.paddingBottom = "8px";
2220   -
2221   - var span = document.createElement("div");
2222   - span.style.position = "absolute";
2223   - span.style.width = "70px";
2224   - span.style.marginTop = "0px";
2225   - span.style.fontWeight = "bold";
2226   -
2227   - var input = null;
2228   - var update = null;
2229   - var btn = null;
2230   -
2231   - if (ss.rotatable && !ss.table && !ss.row && !ss.cell) {
2232   - mxUtils.write(span, mxResources.get("angle"));
2233   - div.appendChild(span);
2234   -
2235   - input = this.addUnitInput(div, "°", 16, 52, function () {
2236   - update.apply(this, arguments);
2237   - });
2238   -
2239   - mxUtils.br(div);
2240   - div.style.paddingTop = "10px";
2241   - } else {
2242   - div.style.paddingTop = "8px";
2243   - }
2244   -
2245   - if (!ss.containsLabel) {
2246   - var label = mxResources.get("reverse");
2247   -
2248   - if (ss.vertices.length > 0 && ss.edges.length > 0) {
2249   - label = mxResources.get("turn") + " / " + label;
2250   - } else if (ss.vertices.length > 0) {
2251   - label = mxResources.get("turn");
2252   - }
2253   -
2254   - btn = mxUtils.button(label, function (evt) {
2255   - ui.actions.get("turn").funct(evt);
2256   - });
2257   -
2258   - btn.setAttribute(
2259   - "title",
2260   - label + " (" + this.editorUi.actions.get("turn").shortcut + ")",
2261   - );
2262   - btn.style.width = "210px";
2263   - div.appendChild(btn);
2264   -
2265   - if (input != null) {
2266   - btn.style.marginTop = "8px";
2267   - }
2268   - }
2269   -
2270   - if (input != null) {
2271   - var listener = mxUtils.bind(this, function (sender, evt, force) {
2272   - if (force || document.activeElement != input) {
2273   - ss = ui.getSelectionState();
2274   - var tmp = parseFloat(
2275   - mxUtils.getValue(ss.style, mxConstants.STYLE_ROTATION, 0),
2276   - );
2277   - input.value = isNaN(tmp) ? "" : tmp + "°";
2278   - }
2279   - });
2280   -
2281   - update = this.installInputHandler(
2282   - input,
2283   - mxConstants.STYLE_ROTATION,
2284   - 0,
2285   - 0,
2286   - 360,
2287   - "°",
2288   - null,
2289   - true,
2290   - );
2291   - this.addKeyHandler(input, listener);
2292   -
2293   - graph.getModel().addListener(mxEvent.CHANGE, listener);
2294   - this.listeners.push({
2295   - destroy: function () {
2296   - graph.getModel().removeListener(listener);
2297   - },
2298   - });
2299   - listener();
2300   - }
2301   -
2302   - return div;
2303   -};
2304   -
2305   -BaseFormatPanel.prototype.getUnit = function () {
2306   - var unit = this.editorUi.editor.graph.view.unit;
2307   -
2308   - switch (unit) {
2309   - case mxConstants.POINTS:
2310   - return "pt";
2311   - case mxConstants.INCHES:
2312   - return '"';
2313   - case mxConstants.MILLIMETERS:
2314   - return "mm";
2315   - case mxConstants.METERS:
2316   - return "m";
2317   - }
2318   -};
2319   -
2320   -BaseFormatPanel.prototype.inUnit = function (pixels) {
2321   - return this.editorUi.editor.graph.view.formatUnitText(pixels);
2322   -};
2323   -
2324   -BaseFormatPanel.prototype.fromUnit = function (value) {
2325   - var unit = this.editorUi.editor.graph.view.unit;
2326   -
2327   - switch (unit) {
2328   - case mxConstants.POINTS:
2329   - return value;
2330   - case mxConstants.INCHES:
2331   - return value * mxConstants.PIXELS_PER_INCH;
2332   - case mxConstants.MILLIMETERS:
2333   - return value * mxConstants.PIXELS_PER_MM;
2334   - case mxConstants.METERS:
2335   - return value * mxConstants.PIXELS_PER_MM * 1000;
2336   - }
2337   -};
2338   -
2339   -BaseFormatPanel.prototype.isFloatUnit = function () {
2340   - return this.editorUi.editor.graph.view.unit != mxConstants.POINTS;
2341   -};
2342   -
2343   -BaseFormatPanel.prototype.getUnitStep = function () {
2344   - var unit = this.editorUi.editor.graph.view.unit;
2345   -
2346   - switch (unit) {
2347   - case mxConstants.POINTS:
2348   - return 1;
2349   - case mxConstants.INCHES:
2350   - return 0.1;
2351   - case mxConstants.MILLIMETERS:
2352   - return 0.5;
2353   - case mxConstants.METERS:
2354   - return 0.001;
2355   - }
2356   -};
2357   -
2358   -/**
2359   - *
2360   - */
2361   -ArrangePanel.prototype.addGeometry = function (container) {
2362   - var panel = this;
2363   - var ui = this.editorUi;
2364   - var graph = ui.editor.graph;
2365   - var model = graph.getModel();
2366   - var rect = ui.getSelectionState();
2367   -
2368   - var div = this.createPanel();
2369   - div.style.paddingBottom = "8px";
2370   -
2371   - var span = document.createElement("div");
2372   - span.style.position = "absolute";
2373   - span.style.width = "50px";
2374   - span.style.marginTop = "0px";
2375   - span.style.fontWeight = "bold";
2376   - mxUtils.write(span, mxResources.get("size"));
2377   - div.appendChild(span);
2378   -
2379   - var widthUpdate, heightUpdate, leftUpdate, topUpdate;
2380   - var width = this.addUnitInput(
2381   - div,
2382   - this.getUnit(),
2383   - 87,
2384   - 52,
2385   - function () {
2386   - widthUpdate.apply(this, arguments);
2387   - },
2388   - this.getUnitStep(),
2389   - null,
2390   - null,
2391   - this.isFloatUnit(),
2392   - );
2393   - var height = this.addUnitInput(
2394   - div,
2395   - this.getUnit(),
2396   - 16,
2397   - 52,
2398   - function () {
2399   - heightUpdate.apply(this, arguments);
2400   - },
2401   - this.getUnitStep(),
2402   - null,
2403   - null,
2404   - this.isFloatUnit(),
2405   - );
2406   -
2407   - var autosizeBtn = document.createElement("div");
2408   - autosizeBtn.className = "geSprite geSprite-fit";
2409   - autosizeBtn.setAttribute(
2410   - "title",
2411   - mxResources.get("autosize") +
2412   - " (" +
2413   - this.editorUi.actions.get("autosize").shortcut +
2414   - ")",
2415   - );
2416   - autosizeBtn.style.position = "relative";
2417   - autosizeBtn.style.cursor = "pointer";
2418   - autosizeBtn.style.marginTop = "-3px";
2419   - autosizeBtn.style.border = "0px";
2420   - autosizeBtn.style.left = "42px";
2421   - mxUtils.setOpacity(autosizeBtn, 50);
2422   -
2423   - mxEvent.addListener(autosizeBtn, "mouseenter", function () {
2424   - mxUtils.setOpacity(autosizeBtn, 100);
2425   - });
2426   -
2427   - mxEvent.addListener(autosizeBtn, "mouseleave", function () {
2428   - mxUtils.setOpacity(autosizeBtn, 50);
2429   - });
2430   -
2431   - mxEvent.addListener(autosizeBtn, "click", function () {
2432   - ui.actions.get("autosize").funct();
2433   - });
2434   -
2435   - div.appendChild(autosizeBtn);
2436   -
2437   - if (rect.row) {
2438   - width.style.visibility = "hidden";
2439   - width.nextSibling.style.visibility = "hidden";
2440   - } else {
2441   - this.addLabel(div, mxResources.get("width"), 87);
2442   - }
2443   -
2444   - this.addLabel(div, mxResources.get("height"), 16);
2445   - mxUtils.br(div);
2446   -
2447   - var wrapper = document.createElement("div");
2448   - wrapper.style.paddingTop = "8px";
2449   - wrapper.style.paddingRight = "20px";
2450   - wrapper.style.whiteSpace = "nowrap";
2451   - wrapper.style.textAlign = "right";
2452   - var opt = this.createCellOption(
2453   - mxResources.get("constrainProportions"),
2454   - mxConstants.STYLE_ASPECT,
2455   - null,
2456   - "fixed",
2457   - "null",
2458   - );
2459   - opt.style.width = "210px";
2460   - wrapper.appendChild(opt);
2461   -
2462   - if (!rect.cell && !rect.row) {
2463   - div.appendChild(wrapper);
2464   - } else {
2465   - autosizeBtn.style.visibility = "hidden";
2466   - }
2467   -
2468   - var constrainCheckbox = opt.getElementsByTagName("input")[0];
2469   - this.addKeyHandler(width, listener);
2470   - this.addKeyHandler(height, listener);
2471   -
2472   - widthUpdate = this.addGeometryHandler(width, function (geo, value, cell) {
2473   - if (graph.isTableCell(cell)) {
2474   - graph.setTableColumnWidth(cell, value - geo.width, true);
2475   -
2476   - // Blocks processing in caller
2477   - return true;
2478   - } else if (geo.width > 0) {
2479   - var value = Math.max(1, panel.fromUnit(value));
2480   -
2481   - if (constrainCheckbox.checked) {
2482   - geo.height = Math.round((geo.height * value * 100) / geo.width) / 100;
2483   - }
2484   -
2485   - geo.width = value;
2486   - }
2487   - });
2488   - heightUpdate = this.addGeometryHandler(height, function (geo, value, cell) {
2489   - if (graph.isTableCell(cell)) {
2490   - cell = graph.model.getParent(cell);
2491   - }
2492   -
2493   - if (graph.isTableRow(cell)) {
2494   - graph.setTableRowHeight(cell, value - geo.height);
2495   -
2496   - // Blocks processing in caller
2497   - return true;
2498   - } else if (geo.height > 0) {
2499   - var value = Math.max(1, panel.fromUnit(value));
2500   -
2501   - if (constrainCheckbox.checked) {
2502   - geo.width = Math.round((geo.width * value * 100) / geo.height) / 100;
2503   - }
2504   -
2505   - geo.height = value;
2506   - }
2507   - });
2508   -
2509   - if (rect.resizable || rect.row || rect.cell) {
2510   - container.appendChild(div);
2511   - }
2512   -
2513   - var div2 = this.createPanel();
2514   - div2.style.paddingBottom = "30px";
2515   -
2516   - var span = document.createElement("div");
2517   - span.style.position = "absolute";
2518   - span.style.width = "70px";
2519   - span.style.marginTop = "0px";
2520   - span.style.fontWeight = "bold";
2521   - mxUtils.write(span, mxResources.get("position"));
2522   - div2.appendChild(span);
2523   -
2524   - var left = this.addUnitInput(
2525   - div2,
2526   - this.getUnit(),
2527   - 87,
2528   - 52,
2529   - function () {
2530   - leftUpdate.apply(this, arguments);
2531   - },
2532   - this.getUnitStep(),
2533   - null,
2534   - null,
2535   - this.isFloatUnit(),
2536   - );
2537   - var top = this.addUnitInput(
2538   - div2,
2539   - this.getUnit(),
2540   - 16,
2541   - 52,
2542   - function () {
2543   - topUpdate.apply(this, arguments);
2544   - },
2545   - this.getUnitStep(),
2546   - null,
2547   - null,
2548   - this.isFloatUnit(),
2549   - );
2550   -
2551   - mxUtils.br(div2);
2552   -
2553   - this.addLabel(div2, mxResources.get("left"), 87);
2554   - this.addLabel(div2, mxResources.get("top"), 16);
2555   -
2556   - var listener = mxUtils.bind(this, function (sender, evt, force) {
2557   - rect = ui.getSelectionState();
2558   -
2559   - if (
2560   - !rect.containsLabel &&
2561   - rect.vertices.length == graph.getSelectionCount() &&
2562   - rect.width != null &&
2563   - rect.height != null
2564   - ) {
2565   - div.style.display = "";
2566   -
2567   - if (force || document.activeElement != width) {
2568   - width.value =
2569   - this.inUnit(rect.width) +
2570   - (rect.width == "" ? "" : " " + this.getUnit());
2571   - }
2572   -
2573   - if (force || document.activeElement != height) {
2574   - height.value =
2575   - this.inUnit(rect.height) +
2576   - (rect.height == "" ? "" : " " + this.getUnit());
2577   - }
2578   - } else {
2579   - div.style.display = "none";
2580   - }
2581   -
2582   - if (
2583   - rect.vertices.length == graph.getSelectionCount() &&
2584   - rect.x != null &&
2585   - rect.y != null
2586   - ) {
2587   - div2.style.display = "";
2588   -
2589   - if (force || document.activeElement != left) {
2590   - left.value =
2591   - this.inUnit(rect.x) + (rect.x == "" ? "" : " " + this.getUnit());
2592   - }
2593   -
2594   - if (force || document.activeElement != top) {
2595   - top.value =
2596   - this.inUnit(rect.y) + (rect.y == "" ? "" : " " + this.getUnit());
2597   - }
2598   - } else {
2599   - div2.style.display = "none";
2600   - }
2601   - });
2602   -
2603   - this.addKeyHandler(left, listener);
2604   - this.addKeyHandler(top, listener);
2605   -
2606   - model.addListener(mxEvent.CHANGE, listener);
2607   - this.listeners.push({
2608   - destroy: function () {
2609   - model.removeListener(listener);
2610   - },
2611   - });
2612   - listener();
2613   -
2614   - leftUpdate = this.addGeometryHandler(left, function (geo, value) {
2615   - value = panel.fromUnit(value);
2616   -
2617   - if (geo.relative) {
2618   - geo.offset.x = value;
2619   - } else {
2620   - geo.x = value;
2621   - }
2622   - });
2623   - topUpdate = this.addGeometryHandler(top, function (geo, value) {
2624   - value = panel.fromUnit(value);
2625   -
2626   - if (geo.relative) {
2627   - geo.offset.y = value;
2628   - } else {
2629   - geo.y = value;
2630   - }
2631   - });
2632   -
2633   - if (rect.movable) {
2634   - if (
2635   - rect.edges.length == 0 &&
2636   - rect.vertices.length == 1 &&
2637   - model.isEdge(model.getParent(rect.vertices[0]))
2638   - ) {
2639   - var geo = graph.getCellGeometry(rect.vertices[0]);
2640   -
2641   - if (geo != null && geo.relative) {
2642   - var btn = mxUtils.button(
2643   - mxResources.get("center"),
2644   - mxUtils.bind(this, function (evt) {
2645   - model.beginUpdate();
2646   - try {
2647   - geo = geo.clone();
2648   - geo.x = 0;
2649   - geo.y = 0;
2650   - geo.offset = new mxPoint();
2651   - model.setGeometry(rect.vertices[0], geo);
2652   - } finally {
2653   - model.endUpdate();
2654   - }
2655   - }),
2656   - );
2657   -
2658   - btn.setAttribute("title", mxResources.get("center"));
2659   - btn.style.width = "210px";
2660   - btn.style.position = "absolute";
2661   - mxUtils.br(div2);
2662   - mxUtils.br(div2);
2663   - div2.appendChild(btn);
2664   - }
2665   - }
2666   - container.appendChild(div2);
2667   - }
2668   -};
2669   -
2670   -/**
2671   - *
2672   - */
2673   -ArrangePanel.prototype.addGeometryHandler = function (input, fn) {
2674   - var ui = this.editorUi;
2675   - var graph = ui.editor.graph;
2676   - var initialValue = null;
2677   - var panel = this;
2678   -
2679   - function update(evt) {
2680   - if (input.value != "") {
2681   - var value = parseFloat(input.value);
2682   -
2683   - if (isNaN(value)) {
2684   - input.value = initialValue + " " + panel.getUnit();
2685   - } else if (value != initialValue) {
2686   - graph.getModel().beginUpdate();
2687   - try {
2688   - var cells = ui.getSelectionState().cells;
2689   -
2690   - for (var i = 0; i < cells.length; i++) {
2691   - if (graph.getModel().isVertex(cells[i])) {
2692   - var geo = graph.getCellGeometry(cells[i]);
2693   -
2694   - if (geo != null) {
2695   - geo = geo.clone();
2696   -
2697   - if (!fn(geo, value, cells[i])) {
2698   - var state = graph.view.getState(cells[i]);
2699   -
2700   - if (state != null && graph.isRecursiveVertexResize(state)) {
2701   - graph.resizeChildCells(cells[i], geo);
2702   - }
2703   -
2704   - graph.getModel().setGeometry(cells[i], geo);
2705   - graph.constrainChildCells(cells[i]);
2706   - }
2707   - }
2708   - }
2709   - }
2710   - } finally {
2711   - graph.getModel().endUpdate();
2712   - }
2713   -
2714   - initialValue = value;
2715   - input.value = value + " " + panel.getUnit();
2716   - }
2717   - }
2718   -
2719   - mxEvent.consume(evt);
2720   - }
2721   -
2722   - mxEvent.addListener(input, "blur", update);
2723   - mxEvent.addListener(input, "change", update);
2724   - mxEvent.addListener(input, "focus", function () {
2725   - initialValue = input.value;
2726   - });
2727   -
2728   - return update;
2729   -};
2730   -
2731   -ArrangePanel.prototype.addEdgeGeometryHandler = function (input, fn) {
2732   - var ui = this.editorUi;
2733   - var graph = ui.editor.graph;
2734   - var initialValue = null;
2735   -
2736   - function update(evt) {
2737   - if (input.value != "") {
2738   - var value = parseFloat(input.value);
2739   -
2740   - if (isNaN(value)) {
2741   - input.value = initialValue + " pt";
2742   - } else if (value != initialValue) {
2743   - graph.getModel().beginUpdate();
2744   - try {
2745   - var cells = ui.getSelectionState().cells;
2746   -
2747   - for (var i = 0; i < cells.length; i++) {
2748   - if (graph.getModel().isEdge(cells[i])) {
2749   - var geo = graph.getCellGeometry(cells[i]);
2750   -
2751   - if (geo != null) {
2752   - geo = geo.clone();
2753   - fn(geo, value);
2754   -
2755   - graph.getModel().setGeometry(cells[i], geo);
2756   - }
2757   - }
2758   - }
2759   - } finally {
2760   - graph.getModel().endUpdate();
2761   - }
2762   -
2763   - initialValue = value;
2764   - input.value = value + " pt";
2765   - }
2766   - }
2767   -
2768   - mxEvent.consume(evt);
2769   - }
2770   -
2771   - mxEvent.addListener(input, "blur", update);
2772   - mxEvent.addListener(input, "change", update);
2773   - mxEvent.addListener(input, "focus", function () {
2774   - initialValue = input.value;
2775   - });
2776   -
2777   - return update;
2778   -};
2779   -
2780   -/**
2781   - *
2782   - */
2783   -ArrangePanel.prototype.addEdgeGeometry = function (container) {
2784   - var ui = this.editorUi;
2785   - var graph = ui.editor.graph;
2786   - var rect = ui.getSelectionState();
2787   - var div = this.createPanel();
2788   -
2789   - var span = document.createElement("div");
2790   - span.style.position = "absolute";
2791   - span.style.width = "70px";
2792   - span.style.marginTop = "0px";
2793   - span.style.fontWeight = "bold";
2794   - mxUtils.write(span, mxResources.get("width"));
2795   - div.appendChild(span);
2796   -
2797   - var widthUpdate, xtUpdate, ytUpdate, xsUpdate, ysUpdate;
2798   - var width = this.addUnitInput(div, "pt", 12, 44, function () {
2799   - widthUpdate.apply(this, arguments);
2800   - });
2801   -
2802   - mxUtils.br(div);
2803   - this.addKeyHandler(width, listener);
2804   -
2805   - var widthUpdate = mxUtils.bind(this, function (evt) {
2806   - // Maximum stroke width is 999
2807   - var value = parseInt(width.value);
2808   - value = Math.min(999, Math.max(1, isNaN(value) ? 1 : value));
2809   -
2810   - if (
2811   - value !=
2812   - mxUtils.getValue(
2813   - rect.style,
2814   - "width",
2815   - mxCellRenderer.defaultShapes["flexArrow"].prototype.defaultWidth,
2816   - )
2817   - ) {
2818   - var cells = ui.getSelectionState().cells;
2819   - graph.setCellStyles("width", value, cells);
2820   - ui.fireEvent(
2821   - new mxEventObject(
2822   - "styleChanged",
2823   - "keys",
2824   - ["width"],
2825   - "values",
2826   - [value],
2827   - "cells",
2828   - cells,
2829   - ),
2830   - );
2831   - }
2832   -
2833   - width.value = value + " pt";
2834   - mxEvent.consume(evt);
2835   - });
2836   -
2837   - mxEvent.addListener(width, "blur", widthUpdate);
2838   - mxEvent.addListener(width, "change", widthUpdate);
2839   -
2840   - container.appendChild(div);
2841   -
2842   - var divs = this.createPanel();
2843   - divs.style.paddingBottom = "30px";
2844   -
2845   - var span = document.createElement("div");
2846   - span.style.position = "absolute";
2847   - span.style.width = "70px";
2848   - span.style.marginTop = "0px";
2849   - mxUtils.write(span, mxResources.get("linestart"));
2850   - divs.appendChild(span);
2851   -
2852   - var xs = this.addUnitInput(divs, "pt", 87, 52, function () {
2853   - xsUpdate.apply(this, arguments);
2854   - });
2855   - var ys = this.addUnitInput(divs, "pt", 16, 52, function () {
2856   - ysUpdate.apply(this, arguments);
2857   - });
2858   -
2859   - mxUtils.br(divs);
2860   - this.addLabel(divs, mxResources.get("left"), 87);
2861   - this.addLabel(divs, mxResources.get("top"), 16);
2862   - container.appendChild(divs);
2863   - this.addKeyHandler(xs, listener);
2864   - this.addKeyHandler(ys, listener);
2865   -
2866   - var divt = this.createPanel();
2867   - divt.style.paddingBottom = "30px";
2868   -
2869   - var span = document.createElement("div");
2870   - span.style.position = "absolute";
2871   - span.style.width = "70px";
2872   - span.style.marginTop = "0px";
2873   - mxUtils.write(span, mxResources.get("lineend"));
2874   - divt.appendChild(span);
2875   -
2876   - var xt = this.addUnitInput(divt, "pt", 87, 52, function () {
2877   - xtUpdate.apply(this, arguments);
2878   - });
2879   - var yt = this.addUnitInput(divt, "pt", 16, 52, function () {
2880   - ytUpdate.apply(this, arguments);
2881   - });
2882   -
2883   - mxUtils.br(divt);
2884   - this.addLabel(divt, mxResources.get("left"), 87);
2885   - this.addLabel(divt, mxResources.get("top"), 16);
2886   - container.appendChild(divt);
2887   - this.addKeyHandler(xt, listener);
2888   - this.addKeyHandler(yt, listener);
2889   -
2890   - var listener = mxUtils.bind(this, function (sender, evt, force) {
2891   - rect = ui.getSelectionState();
2892   - var cell = rect.cells[0];
2893   -
2894   - if (rect.style.shape == "link" || rect.style.shape == "flexArrow") {
2895   - div.style.display = "";
2896   -
2897   - if (force || document.activeElement != width) {
2898   - var value = mxUtils.getValue(
2899   - rect.style,
2900   - "width",
2901   - mxCellRenderer.defaultShapes["flexArrow"].prototype.defaultWidth,
2902   - );
2903   - width.value = value + " pt";
2904   - }
2905   - } else {
2906   - div.style.display = "none";
2907   - }
2908   -
2909   - if (rect.cells.length == 1 && graph.model.isEdge(cell)) {
2910   - var geo = graph.model.getGeometry(cell);
2911   -
2912   - if (
2913   - geo.sourcePoint != null &&
2914   - graph.model.getTerminal(cell, true) == null
2915   - ) {
2916   - xs.value = geo.sourcePoint.x;
2917   - ys.value = geo.sourcePoint.y;
2918   - } else {
2919   - divs.style.display = "none";
2920   - }
2921   -
2922   - if (
2923   - geo.targetPoint != null &&
2924   - graph.model.getTerminal(cell, false) == null
2925   - ) {
2926   - xt.value = geo.targetPoint.x;
2927   - yt.value = geo.targetPoint.y;
2928   - } else {
2929   - divt.style.display = "none";
2930   - }
2931   - } else {
2932   - divs.style.display = "none";
2933   - divt.style.display = "none";
2934   - }
2935   - });
2936   -
2937   - xsUpdate = this.addEdgeGeometryHandler(xs, function (geo, value) {
2938   - geo.sourcePoint.x = value;
2939   - });
2940   -
2941   - ysUpdate = this.addEdgeGeometryHandler(ys, function (geo, value) {
2942   - geo.sourcePoint.y = value;
2943   - });
2944   -
2945   - xtUpdate = this.addEdgeGeometryHandler(xt, function (geo, value) {
2946   - geo.targetPoint.x = value;
2947   - });
2948   -
2949   - ytUpdate = this.addEdgeGeometryHandler(yt, function (geo, value) {
2950   - geo.targetPoint.y = value;
2951   - });
2952   -
2953   - graph.getModel().addListener(mxEvent.CHANGE, listener);
2954   - this.listeners.push({
2955   - destroy: function () {
2956   - graph.getModel().removeListener(listener);
2957   - },
2958   - });
2959   - listener();
2960   -};
2961   -
2962   -/**
2963   - * Adds the label menu items to the given menu and parent.
2964   - */
2965   -TextFormatPanel = function (format, editorUi, container) {
2966   - BaseFormatPanel.call(this, format, editorUi, container);
2967   - this.init();
2968   -};
2969   -
2970   -mxUtils.extend(TextFormatPanel, BaseFormatPanel);
2971   -
2972   -/**
2973   - * Adds the label menu items to the given menu and parent.
2974   - */
2975   -TextFormatPanel.prototype.init = function () {
2976   - this.container.style.borderBottom = "none";
2977   - this.addFont(this.container);
2978   -};
2979   -
2980   -/**
2981   - * Adds the label menu items to the given menu and parent.
2982   - */
2983   -TextFormatPanel.prototype.addFont = function (container) {
2984   - var ui = this.editorUi;
2985   - var editor = ui.editor;
2986   - var graph = editor.graph;
2987   - var ss = ui.getSelectionState();
2988   -
2989   - var title = this.createTitle(mxResources.get("font"));
2990   - title.style.paddingLeft = "14px";
2991   - title.style.paddingTop = "10px";
2992   - title.style.paddingBottom = "6px";
2993   - container.appendChild(title);
2994   -
2995   - var stylePanel = this.createPanel();
2996   - stylePanel.style.paddingTop = "2px";
2997   - stylePanel.style.paddingBottom = "2px";
2998   - stylePanel.style.position = "relative";
2999   - stylePanel.style.marginLeft = "-2px";
3000   - stylePanel.style.borderWidth = "0px";
3001   - stylePanel.className = "geToolbarContainer";
3002   -
3003   - if (graph.cellEditor.isContentEditing()) {
3004   - var cssPanel = stylePanel.cloneNode();
3005   -
3006   - var cssMenu = this.editorUi.toolbar.addMenu(
3007   - mxResources.get("style"),
3008   - mxResources.get("style"),
3009   - true,
3010   - "formatBlock",
3011   - cssPanel,
3012   - null,
3013   - true,
3014   - );
3015   - cssMenu.style.color = "rgb(112, 112, 112)";
3016   - cssMenu.style.whiteSpace = "nowrap";
3017   - cssMenu.style.overflow = "hidden";
3018   - cssMenu.style.margin = "0px";
3019   - this.addArrow(cssMenu);
3020   - cssMenu.style.width = "200px";
3021   - cssMenu.style.height = "15px";
3022   -
3023   - var arrow = cssMenu.getElementsByTagName("div")[0];
3024   - arrow.style.cssFloat = "right";
3025   - container.appendChild(cssPanel);
3026   - }
3027   -
3028   - container.appendChild(stylePanel);
3029   -
3030   - var colorPanel = this.createPanel();
3031   - colorPanel.style.marginTop = "8px";
3032   - colorPanel.style.borderTop = "1px solid #c0c0c0";
3033   - colorPanel.style.paddingTop = "6px";
3034   - colorPanel.style.paddingBottom = "6px";
3035   -
3036   - var fontMenu = this.editorUi.toolbar.addMenu(
3037   - "Helvetica",
3038   - mxResources.get("fontFamily"),
3039   - true,
3040   - "fontFamily",
3041   - stylePanel,
3042   - null,
3043   - true,
3044   - );
3045   - fontMenu.style.color = "rgb(112, 112, 112)";
3046   - fontMenu.style.whiteSpace = "nowrap";
3047   - fontMenu.style.overflow = "hidden";
3048   - fontMenu.style.margin = "0px";
3049   -
3050   - this.addArrow(fontMenu);
3051   - fontMenu.style.width = "200px";
3052   - fontMenu.style.height = "15px";
3053   -
3054   - var stylePanel2 = stylePanel.cloneNode(false);
3055   - stylePanel2.style.marginLeft = "-3px";
3056   - var fontStyleItems = this.editorUi.toolbar.addItems(
3057   - ["bold", "italic", "underline"],
3058   - stylePanel2,
3059   - true,
3060   - );
3061   - fontStyleItems[0].setAttribute(
3062   - "title",
3063   - mxResources.get("bold") +
3064   - " (" +
3065   - this.editorUi.actions.get("bold").shortcut +
3066   - ")",
3067   - );
3068   - fontStyleItems[1].setAttribute(
3069   - "title",
3070   - mxResources.get("italic") +
3071   - " (" +
3072   - this.editorUi.actions.get("italic").shortcut +
3073   - ")",
3074   - );
3075   - fontStyleItems[2].setAttribute(
3076   - "title",
3077   - mxResources.get("underline") +
3078   - " (" +
3079   - this.editorUi.actions.get("underline").shortcut +
3080   - ")",
3081   - );
3082   -
3083   - var verticalItem = this.editorUi.toolbar.addItems(
3084   - ["vertical"],
3085   - stylePanel2,
3086   - true,
3087   - )[0];
3088   -
3089   - container.appendChild(stylePanel2);
3090   -
3091   - this.styleButtons(fontStyleItems);
3092   - this.styleButtons([verticalItem]);
3093   -
3094   - var stylePanel3 = stylePanel.cloneNode(false);
3095   - stylePanel3.style.marginLeft = "-3px";
3096   - stylePanel3.style.paddingBottom = "0px";
3097   -
3098   - // Helper function to return a wrapper function does not pass any arguments
3099   - var callFn = function (fn) {
3100   - return function () {
3101   - return fn();
3102   - };
3103   - };
3104   -
3105   - var left = this.editorUi.toolbar.addButton(
3106   - "geSprite-left",
3107   - mxResources.get("left"),
3108   - graph.cellEditor.isContentEditing()
3109   - ? function (evt) {
3110   - graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt);
3111   - ui.fireEvent(
3112   - new mxEventObject(
3113   - "styleChanged",
3114   - "keys",
3115   - [mxConstants.STYLE_ALIGN],
3116   - "values",
3117   - [mxConstants.ALIGN_LEFT],
3118   - "cells",
3119   - ss.cells,
3120   - ),
3121   - );
3122   - }
3123   - : callFn(
3124   - this.editorUi.menus.createStyleChangeFunction(
3125   - [mxConstants.STYLE_ALIGN],
3126   - [mxConstants.ALIGN_LEFT],
3127   - ),
3128   - ),
3129   - stylePanel3,
3130   - );
3131   - var center = this.editorUi.toolbar.addButton(
3132   - "geSprite-center",
3133   - mxResources.get("center"),
3134   - graph.cellEditor.isContentEditing()
3135   - ? function (evt) {
3136   - graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt);
3137   - ui.fireEvent(
3138   - new mxEventObject(
3139   - "styleChanged",
3140   - "keys",
3141   - [mxConstants.STYLE_ALIGN],
3142   - "values",
3143   - [mxConstants.ALIGN_CENTER],
3144   - "cells",
3145   - ss.cells,
3146   - ),
3147   - );
3148   - }
3149   - : callFn(
3150   - this.editorUi.menus.createStyleChangeFunction(
3151   - [mxConstants.STYLE_ALIGN],
3152   - [mxConstants.ALIGN_CENTER],
3153   - ),
3154   - ),
3155   - stylePanel3,
3156   - );
3157   - var right = this.editorUi.toolbar.addButton(
3158   - "geSprite-right",
3159   - mxResources.get("right"),
3160   - graph.cellEditor.isContentEditing()
3161   - ? function (evt) {
3162   - graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt);
3163   - ui.fireEvent(
3164   - new mxEventObject(
3165   - "styleChanged",
3166   - "keys",
3167   - [mxConstants.STYLE_ALIGN],
3168   - "values",
3169   - [mxConstants.ALIGN_RIGHT],
3170   - "cells",
3171   - ss.cells,
3172   - ),
3173   - );
3174   - }
3175   - : callFn(
3176   - this.editorUi.menus.createStyleChangeFunction(
3177   - [mxConstants.STYLE_ALIGN],
3178   - [mxConstants.ALIGN_RIGHT],
3179   - ),
3180   - ),
3181   - stylePanel3,
3182   - );
3183   -
3184   - this.styleButtons([left, center, right]);
3185   -
3186   - // Quick hack for strikethrough
3187   - // TODO: Add translations and toggle state
3188   - if (graph.cellEditor.isContentEditing()) {
3189   - var strike = this.editorUi.toolbar.addButton(
3190   - "geSprite-removeformat",
3191   - mxResources.get("strikethrough"),
3192   - function () {
3193   - document.execCommand("strikeThrough", false, null);
3194   - },
3195   - stylePanel2,
3196   - );
3197   - this.styleButtons([strike]);
3198   -
3199   - strike.firstChild.style.background =
3200   - "url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjR2MjRIMFYweiIvPjwvZGVmcz48Y2xpcFBhdGggaWQ9ImIiPjx1c2UgeGxpbms6aHJlZj0iI2EiIG92ZXJmbG93PSJ2aXNpYmxlIi8+PC9jbGlwUGF0aD48cGF0aCBjbGlwLXBhdGg9InVybCgjYikiIGZpbGw9IiMwMTAxMDEiIGQ9Ik03LjI0IDguNzVjLS4yNi0uNDgtLjM5LTEuMDMtLjM5LTEuNjcgMC0uNjEuMTMtMS4xNi40LTEuNjcuMjYtLjUuNjMtLjkzIDEuMTEtMS4yOS40OC0uMzUgMS4wNS0uNjMgMS43LS44My42Ni0uMTkgMS4zOS0uMjkgMi4xOC0uMjkuODEgMCAxLjU0LjExIDIuMjEuMzQuNjYuMjIgMS4yMy41NCAxLjY5Ljk0LjQ3LjQuODMuODggMS4wOCAxLjQzLjI1LjU1LjM4IDEuMTUuMzggMS44MWgtMy4wMWMwLS4zMS0uMDUtLjU5LS4xNS0uODUtLjA5LS4yNy0uMjQtLjQ5LS40NC0uNjgtLjItLjE5LS40NS0uMzMtLjc1LS40NC0uMy0uMS0uNjYtLjE2LTEuMDYtLjE2LS4zOSAwLS43NC4wNC0xLjAzLjEzLS4yOS4wOS0uNTMuMjEtLjcyLjM2LS4xOS4xNi0uMzQuMzQtLjQ0LjU1LS4xLjIxLS4xNS40My0uMTUuNjYgMCAuNDguMjUuODguNzQgMS4yMS4zOC4yNS43Ny40OCAxLjQxLjdINy4zOWMtLjA1LS4wOC0uMTEtLjE3LS4xNS0uMjV6TTIxIDEydi0ySDN2Mmg5LjYyYy4xOC4wNy40LjE0LjU1LjIuMzcuMTcuNjYuMzQuODcuNTEuMjEuMTcuMzUuMzYuNDMuNTcuMDcuMi4xMS40My4xMS42OSAwIC4yMy0uMDUuNDUtLjE0LjY2LS4wOS4yLS4yMy4zOC0uNDIuNTMtLjE5LjE1LS40Mi4yNi0uNzEuMzUtLjI5LjA4LS42My4xMy0xLjAxLjEzLS40MyAwLS44My0uMDQtMS4xOC0uMTNzLS42Ni0uMjMtLjkxLS40MmMtLjI1LS4xOS0uNDUtLjQ0LS41OS0uNzUtLjE0LS4zMS0uMjUtLjc2LS4yNS0xLjIxSDYuNGMwIC41NS4wOCAxLjEzLjI0IDEuNTguMTYuNDUuMzcuODUuNjUgMS4yMS4yOC4zNS42LjY2Ljk4LjkyLjM3LjI2Ljc4LjQ4IDEuMjIuNjUuNDQuMTcuOS4zIDEuMzguMzkuNDguMDguOTYuMTMgMS40NC4xMy44IDAgMS41My0uMDkgMi4xOC0uMjhzMS4yMS0uNDUgMS42Ny0uNzljLjQ2LS4zNC44Mi0uNzcgMS4wNy0xLjI3cy4zOC0xLjA3LjM4LTEuNzFjMC0uNi0uMS0xLjE0LS4zMS0xLjYxLS4wNS0uMTEtLjExLS4yMy0uMTctLjMzSDIxeiIvPjwvc3ZnPg==)";
3201   - strike.firstChild.style.backgroundPosition = "2px 2px";
3202   - strike.firstChild.style.backgroundSize = "18px 18px";
3203   -
3204   - this.styleButtons([strike]);
3205   - }
3206   -
3207   - var top = this.editorUi.toolbar.addButton(
3208   - "geSprite-top",
3209   - mxResources.get("top"),
3210   - callFn(
3211   - this.editorUi.menus.createStyleChangeFunction(
3212   - [mxConstants.STYLE_VERTICAL_ALIGN],
3213   - [mxConstants.ALIGN_TOP],
3214   - ),
3215   - ),
3216   - stylePanel3,
3217   - );
3218   - var middle = this.editorUi.toolbar.addButton(
3219   - "geSprite-middle",
3220   - mxResources.get("middle"),
3221   - callFn(
3222   - this.editorUi.menus.createStyleChangeFunction(
3223   - [mxConstants.STYLE_VERTICAL_ALIGN],
3224   - [mxConstants.ALIGN_MIDDLE],
3225   - ),
3226   - ),
3227   - stylePanel3,
3228   - );
3229   - var bottom = this.editorUi.toolbar.addButton(
3230   - "geSprite-bottom",
3231   - mxResources.get("bottom"),
3232   - callFn(
3233   - this.editorUi.menus.createStyleChangeFunction(
3234   - [mxConstants.STYLE_VERTICAL_ALIGN],
3235   - [mxConstants.ALIGN_BOTTOM],
3236   - ),
3237   - ),
3238   - stylePanel3,
3239   - );
3240   -
3241   - this.styleButtons([top, middle, bottom]);
3242   -
3243   - container.appendChild(stylePanel3);
3244   -
3245   - // Hack for updating UI state below based on current text selection
3246   - // currentTable is the current selected DOM table updated below
3247   - var sub, sup, full, tableWrapper, currentTable, tableCell, tableRow;
3248   -
3249   - if (graph.cellEditor.isContentEditing()) {
3250   - top.style.display = "none";
3251   - middle.style.display = "none";
3252   - bottom.style.display = "none";
3253   - verticalItem.style.display = "none";
3254   -
3255   - full = this.editorUi.toolbar.addButton(
3256   - "geSprite-justifyfull",
3257   - mxResources.get("block"),
3258   - function () {
3259   - if (full.style.opacity == 1) {
3260   - document.execCommand("justifyfull", false, null);
3261   - }
3262   - },
3263   - stylePanel3,
3264   - );
3265   - full.style.marginRight = "9px";
3266   - full.style.opacity = 1;
3267   -
3268   - this.styleButtons([
3269   - full,
3270   - (sub = this.editorUi.toolbar.addButton(
3271   - "geSprite-subscript",
3272   - mxResources.get("subscript") + " (" + Editor.ctrlKey + "+,)",
3273   - function () {
3274   - document.execCommand("subscript", false, null);
3275   - },
3276   - stylePanel3,
3277   - )),
3278   - (sup = this.editorUi.toolbar.addButton(
3279   - "geSprite-superscript",
3280   - mxResources.get("superscript") + " (" + Editor.ctrlKey + "+.)",
3281   - function () {
3282   - document.execCommand("superscript", false, null);
3283   - },
3284   - stylePanel3,
3285   - )),
3286   - ]);
3287   - sub.style.marginLeft = "10px";
3288   -
3289   - var tmp = stylePanel3.cloneNode(false);
3290   - tmp.style.paddingTop = "4px";
3291   - var btns = [
3292   - this.editorUi.toolbar.addButton(
3293   - "geSprite-orderedlist",
3294   - mxResources.get("numberedList"),
3295   - function () {
3296   - document.execCommand("insertorderedlist", false, null);
3297   - },
3298   - tmp,
3299   - ),
3300   - this.editorUi.toolbar.addButton(
3301   - "geSprite-unorderedlist",
3302   - mxResources.get("bulletedList"),
3303   - function () {
3304   - document.execCommand("insertunorderedlist", false, null);
3305   - },
3306   - tmp,
3307   - ),
3308   - this.editorUi.toolbar.addButton(
3309   - "geSprite-outdent",
3310   - mxResources.get("decreaseIndent"),
3311   - function () {
3312   - document.execCommand("outdent", false, null);
3313   - },
3314   - tmp,
3315   - ),
3316   - this.editorUi.toolbar.addButton(
3317   - "geSprite-indent",
3318   - mxResources.get("increaseIndent"),
3319   - function () {
3320   - document.execCommand("indent", false, null);
3321   - },
3322   - tmp,
3323   - ),
3324   - this.editorUi.toolbar.addButton(
3325   - "geSprite-removeformat",
3326   - mxResources.get("removeFormat"),
3327   - function () {
3328   - document.execCommand("removeformat", false, null);
3329   - },
3330   - tmp,
3331   - ),
3332   - this.editorUi.toolbar.addButton(
3333   - "geSprite-code",
3334   - mxResources.get("html"),
3335   - function () {
3336   - graph.cellEditor.toggleViewMode();
3337   - },
3338   - tmp,
3339   - ),
3340   - ];
3341   - this.styleButtons(btns);
3342   - btns[btns.length - 2].style.marginLeft = "10px";
3343   -
3344   - container.appendChild(tmp);
3345   - } else {
3346   - fontStyleItems[2].style.marginRight = "12px";
3347   - right.style.marginRight = "12px";
3348   - }
3349   -
3350   - // Label position
3351   - var stylePanel4 = stylePanel.cloneNode(false);
3352   - stylePanel4.style.marginLeft = "0px";
3353   - stylePanel4.style.paddingTop = "8px";
3354   - stylePanel4.style.paddingBottom = "4px";
3355   - stylePanel4.style.fontWeight = "normal";
3356   -
3357   - mxUtils.write(stylePanel4, mxResources.get("position"));
3358   -
3359   - // Adds label position options
3360   - var positionSelect = document.createElement("select");
3361   - positionSelect.style.position = "absolute";
3362   - positionSelect.style.left = "126px";
3363   - positionSelect.style.width = "98px";
3364   - positionSelect.style.border = "1px solid rgb(160, 160, 160)";
3365   - positionSelect.style.borderRadius = "4px";
3366   - positionSelect.style.marginTop = "-2px";
3367   -
3368   - var directions = [
3369   - "topLeft",
3370   - "top",
3371   - "topRight",
3372   - "left",
3373   - "center",
3374   - "right",
3375   - "bottomLeft",
3376   - "bottom",
3377   - "bottomRight",
3378   - ];
3379   - var lset = {
3380   - topLeft: [
3381   - mxConstants.ALIGN_LEFT,
3382   - mxConstants.ALIGN_TOP,
3383   - mxConstants.ALIGN_RIGHT,
3384   - mxConstants.ALIGN_BOTTOM,
3385   - ],
3386   - top: [
3387   - mxConstants.ALIGN_CENTER,
3388   - mxConstants.ALIGN_TOP,
3389   - mxConstants.ALIGN_CENTER,
3390   - mxConstants.ALIGN_BOTTOM,
3391   - ],
3392   - topRight: [
3393   - mxConstants.ALIGN_RIGHT,
3394   - mxConstants.ALIGN_TOP,
3395   - mxConstants.ALIGN_LEFT,
3396   - mxConstants.ALIGN_BOTTOM,
3397   - ],
3398   - left: [
3399   - mxConstants.ALIGN_LEFT,
3400   - mxConstants.ALIGN_MIDDLE,
3401   - mxConstants.ALIGN_RIGHT,
3402   - mxConstants.ALIGN_MIDDLE,
3403   - ],
3404   - center: [
3405   - mxConstants.ALIGN_CENTER,
3406   - mxConstants.ALIGN_MIDDLE,
3407   - mxConstants.ALIGN_CENTER,
3408   - mxConstants.ALIGN_MIDDLE,
3409   - ],
3410   - right: [
3411   - mxConstants.ALIGN_RIGHT,
3412   - mxConstants.ALIGN_MIDDLE,
3413   - mxConstants.ALIGN_LEFT,
3414   - mxConstants.ALIGN_MIDDLE,
3415   - ],
3416   - bottomLeft: [
3417   - mxConstants.ALIGN_LEFT,
3418   - mxConstants.ALIGN_BOTTOM,
3419   - mxConstants.ALIGN_RIGHT,
3420   - mxConstants.ALIGN_TOP,
3421   - ],
3422   - bottom: [
3423   - mxConstants.ALIGN_CENTER,
3424   - mxConstants.ALIGN_BOTTOM,
3425   - mxConstants.ALIGN_CENTER,
3426   - mxConstants.ALIGN_TOP,
3427   - ],
3428   - bottomRight: [
3429   - mxConstants.ALIGN_RIGHT,
3430   - mxConstants.ALIGN_BOTTOM,
3431   - mxConstants.ALIGN_LEFT,
3432   - mxConstants.ALIGN_TOP,
3433   - ],
3434   - };
3435   -
3436   - for (var i = 0; i < directions.length; i++) {
3437   - var positionOption = document.createElement("option");
3438   - positionOption.setAttribute("value", directions[i]);
3439   - mxUtils.write(positionOption, mxResources.get(directions[i]));
3440   - positionSelect.appendChild(positionOption);
3441   - }
3442   -
3443   - stylePanel4.appendChild(positionSelect);
3444   -
3445   - // Writing direction
3446   - var stylePanel5 = stylePanel.cloneNode(false);
3447   - stylePanel5.style.marginLeft = "0px";
3448   - stylePanel5.style.paddingTop = "4px";
3449   - stylePanel5.style.paddingBottom = "4px";
3450   - stylePanel5.style.fontWeight = "normal";
3451   -
3452   - mxUtils.write(stylePanel5, mxResources.get("writingDirection"));
3453   -
3454   - // Adds writing direction options
3455   - // LATER: Handle reselect of same option in all selects (change event
3456   - // is not fired for same option so have opened state on click) and
3457   - // handle multiple different styles for current selection
3458   - var dirSelect = document.createElement("select");
3459   - dirSelect.style.position = "absolute";
3460   - dirSelect.style.border = "1px solid rgb(160, 160, 160)";
3461   - dirSelect.style.left = "126px";
3462   - dirSelect.style.width = "98px";
3463   - dirSelect.style.borderRadius = "4px";
3464   - dirSelect.style.marginTop = "-2px";
3465   -
3466   - // NOTE: For automatic we use the value null since automatic
3467   - // requires the text to be non formatted and non-wrapped
3468   - var dirs = ["automatic", "leftToRight", "rightToLeft"];
3469   - var dirSet = {
3470   - automatic: null,
3471   - leftToRight: mxConstants.TEXT_DIRECTION_LTR,
3472   - rightToLeft: mxConstants.TEXT_DIRECTION_RTL,
3473   - };
3474   -
3475   - for (var i = 0; i < dirs.length; i++) {
3476   - var dirOption = document.createElement("option");
3477   - dirOption.setAttribute("value", dirs[i]);
3478   - mxUtils.write(dirOption, mxResources.get(dirs[i]));
3479   - dirSelect.appendChild(dirOption);
3480   - }
3481   -
3482   - stylePanel5.appendChild(dirSelect);
3483   -
3484   - if (!graph.isEditing()) {
3485   - container.appendChild(stylePanel4);
3486   -
3487   - mxEvent.addListener(positionSelect, "change", function (evt) {
3488   - graph.getModel().beginUpdate();
3489   - try {
3490   - var vals = lset[positionSelect.value];
3491   -
3492   - if (vals != null) {
3493   - graph.setCellStyles(
3494   - mxConstants.STYLE_LABEL_POSITION,
3495   - vals[0],
3496   - ss.cells,
3497   - );
3498   - graph.setCellStyles(
3499   - mxConstants.STYLE_VERTICAL_LABEL_POSITION,
3500   - vals[1],
3501   - ss.cells,
3502   - );
3503   - graph.setCellStyles(mxConstants.STYLE_ALIGN, vals[2], ss.cells);
3504   - graph.setCellStyles(
3505   - mxConstants.STYLE_VERTICAL_ALIGN,
3506   - vals[3],
3507   - ss.cells,
3508   - );
3509   - }
3510   - } finally {
3511   - graph.getModel().endUpdate();
3512   - }
3513   -
3514   - mxEvent.consume(evt);
3515   - });
3516   -
3517   - // LATER: Update dir in text editor while editing and update style with label
3518   - // NOTE: The tricky part is handling and passing on the auto value
3519   - container.appendChild(stylePanel5);
3520   -
3521   - mxEvent.addListener(dirSelect, "change", function (evt) {
3522   - graph.setCellStyles(
3523   - mxConstants.STYLE_TEXT_DIRECTION,
3524   - dirSet[dirSelect.value],
3525   - ss.cells,
3526   - );
3527   - mxEvent.consume(evt);
3528   - });
3529   - }
3530   -
3531   - // Fontsize
3532   - var input = document.createElement("input");
3533   - input.style.position = "absolute";
3534   - input.style.border = "1px solid rgb(160, 160, 160)";
3535   - input.style.textAlign = "right";
3536   - input.style.marginTop = "4px";
3537   - input.style.left = "161px";
3538   - input.style.width = "53px";
3539   - input.style.borderRadius = "4px";
3540   - input.style.height = "23px";
3541   - input.style.boxSizing = "border-box";
3542   - stylePanel2.appendChild(input);
3543   -
3544   - // Workaround for font size 4 if no text is selected is update font size below
3545   - // after first character was entered (as the font element is lazy created)
3546   - var pendingFontSize = null;
3547   -
3548   - var inputUpdate = this.installInputHandler(
3549   - input,
3550   - mxConstants.STYLE_FONTSIZE,
3551   - Menus.prototype.defaultFontSize,
3552   - 1,
3553   - 999,
3554   - " pt",
3555   - function (fontSize) {
3556   - // IE does not support containsNode
3557   - // KNOWN: Fixes font size issues but bypasses undo
3558   - if (window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11) {
3559   - var selection = window.getSelection();
3560   - var container =
3561   - selection.rangeCount > 0
3562   - ? selection.getRangeAt(0).commonAncestorContainer
3563   - : graph.cellEditor.textarea;
3564   -
3565   - function updateSize(elt, ignoreContains) {
3566   - if (
3567   - graph.cellEditor.textarea != null &&
3568   - elt != graph.cellEditor.textarea &&
3569   - graph.cellEditor.textarea.contains(elt) &&
3570   - (ignoreContains || selection.containsNode(elt, true))
3571   - ) {
3572   - if (elt.nodeName == "FONT") {
3573   - elt.removeAttribute("size");
3574   - elt.style.fontSize = fontSize + "px";
3575   - } else {
3576   - var css = mxUtils.getCurrentStyle(elt);
3577   -
3578   - if (css.fontSize != fontSize + "px") {
3579   - if (
3580   - mxUtils.getCurrentStyle(elt.parentNode).fontSize !=
3581   - fontSize + "px"
3582   - ) {
3583   - elt.style.fontSize = fontSize + "px";
3584   - } else {
3585   - elt.style.fontSize = "";
3586   - }
3587   - }
3588   - }
3589   - }
3590   -
3591   - ui.fireEvent(
3592   - new mxEventObject(
3593   - "styleChanged",
3594   - "keys",
3595   - [mxConstants.STYLE_FONTSIZE],
3596   - "values",
3597   - [fontSize],
3598   - "cells",
3599   - ss.cells,
3600   - ),
3601   - );
3602   - }
3603   -
3604   - // Wraps text node or mixed selection with leading text in a font element
3605   - if (
3606   - container == graph.cellEditor.textarea ||
3607   - container.nodeType != mxConstants.NODETYPE_ELEMENT
3608   - ) {
3609   - document.execCommand("fontSize", false, "1");
3610   - }
3611   -
3612   - if (container != graph.cellEditor.textarea) {
3613   - container = container.parentNode;
3614   - }
3615   -
3616   - if (
3617   - container != null &&
3618   - container.nodeType == mxConstants.NODETYPE_ELEMENT
3619   - ) {
3620   - var elts = container.getElementsByTagName("*");
3621   - updateSize(container);
3622   -
3623   - for (var i = 0; i < elts.length; i++) {
3624   - updateSize(elts[i]);
3625   - }
3626   - }
3627   -
3628   - input.value = fontSize + " pt";
3629   - } else if (window.getSelection || document.selection) {
3630   - // Checks selection
3631   - var par = null;
3632   -
3633   - if (document.selection) {
3634   - par = document.selection.createRange().parentElement();
3635   - } else {
3636   - var selection = window.getSelection();
3637   -
3638   - if (selection.rangeCount > 0) {
3639   - par = selection.getRangeAt(0).commonAncestorContainer;
3640   - }
3641   - }
3642   -
3643   - // Node.contains does not work for text nodes in IE11
3644   - function isOrContains(container, node) {
3645   - while (node != null) {
3646   - if (node === container) {
3647   - return true;
3648   - }
3649   -
3650   - node = node.parentNode;
3651   - }
3652   -
3653   - return false;
3654   - }
3655   -
3656   - if (par != null && isOrContains(graph.cellEditor.textarea, par)) {
3657   - pendingFontSize = fontSize;
3658   -
3659   - // Workaround for can't set font size in px is to change font size afterwards
3660   - document.execCommand("fontSize", false, "4");
3661   - var elts = graph.cellEditor.textarea.getElementsByTagName("font");
3662   -
3663   - for (var i = 0; i < elts.length; i++) {
3664   - if (elts[i].getAttribute("size") == "4") {
3665   - elts[i].removeAttribute("size");
3666   - elts[i].style.fontSize = pendingFontSize + "px";
3667   -
3668   - // Overrides fontSize in input with the one just assigned as a workaround
3669   - // for potential fontSize values of parent elements that don't match
3670   - window.setTimeout(function () {
3671   - input.value = pendingFontSize + " pt";
3672   - pendingFontSize = null;
3673   - }, 0);
3674   -
3675   - break;
3676   - }
3677   - }
3678   - }
3679   - }
3680   - },
3681   - true,
3682   - );
3683   -
3684   - var stepper = this.createStepper(
3685   - input,
3686   - inputUpdate,
3687   - 1,
3688   - 10,
3689   - true,
3690   - Menus.prototype.defaultFontSize,
3691   - );
3692   - stepper.style.display = input.style.display;
3693   - stepper.style.marginTop = "4px";
3694   - stepper.style.left = "214px";
3695   -
3696   - stylePanel2.appendChild(stepper);
3697   -
3698   - var arrow = fontMenu.getElementsByTagName("div")[0];
3699   - arrow.style.cssFloat = "right";
3700   -
3701   - var bgColorApply = null;
3702   - var currentBgColor = graph.shapeBackgroundColor;
3703   -
3704   - var fontColorApply = null;
3705   - var currentFontColor = graph.shapeForegroundColor;
3706   -
3707   - var bgPanel = graph.cellEditor.isContentEditing()
3708   - ? this.createColorOption(
3709   - mxResources.get("backgroundColor"),
3710   - function () {
3711   - return currentBgColor;
3712   - },
3713   - function (color) {
3714   - document.execCommand(
3715   - "backcolor",
3716   - false,
3717   - color != mxConstants.NONE ? color : "transparent",
3718   - );
3719   - ui.fireEvent(
3720   - new mxEventObject(
3721   - "styleChanged",
3722   - "keys",
3723   - [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
3724   - "values",
3725   - [color],
3726   - "cells",
3727   - ss.cells,
3728   - ),
3729   - );
3730   - },
3731   - graph.shapeBackgroundColor,
3732   - {
3733   - install: function (apply) {
3734   - bgColorApply = apply;
3735   - },
3736   - destroy: function () {
3737   - bgColorApply = null;
3738   - },
3739   - },
3740   - null,
3741   - true,
3742   - )
3743   - : this.createCellColorOption(
3744   - mxResources.get("backgroundColor"),
3745   - mxConstants.STYLE_LABEL_BACKGROUNDCOLOR,
3746   - "default",
3747   - null,
3748   - function (color) {
3749   - graph.updateLabelElements(ss.cells, function (elt) {
3750   - elt.style.backgroundColor = null;
3751   - });
3752   - },
3753   - graph.shapeBackgroundColor,
3754   - );
3755   - bgPanel.style.fontWeight = "bold";
3756   -
3757   - var borderPanel = this.createCellColorOption(
3758   - mxResources.get("borderColor"),
3759   - mxConstants.STYLE_LABEL_BORDERCOLOR,
3760   - "default",
3761   - null,
3762   - null,
3763   - graph.shapeForegroundColor,
3764   - );
3765   - borderPanel.style.fontWeight = "bold";
3766   -
3767   - var defs =
3768   - ss.vertices.length >= 1
3769   - ? graph.stylesheet.getDefaultVertexStyle()
3770   - : graph.stylesheet.getDefaultEdgeStyle();
3771   -
3772   - var panel = graph.cellEditor.isContentEditing()
3773   - ? this.createColorOption(
3774   - mxResources.get("fontColor"),
3775   - function () {
3776   - return currentFontColor;
3777   - },
3778   - function (color) {
3779   - if (mxClient.IS_FF) {
3780   - // Workaround for Firefox that adds the font element around
3781   - // anchor elements which ignore inherited colors is to move
3782   - // the font element inside anchor elements
3783   - var tmp = graph.cellEditor.textarea.getElementsByTagName("font");
3784   - var oldFonts = [];
3785   -
3786   - for (var i = 0; i < tmp.length; i++) {
3787   - oldFonts.push({
3788   - node: tmp[i],
3789   - color: tmp[i].getAttribute("color"),
3790   - });
3791   - }
3792   -
3793   - document.execCommand(
3794   - "forecolor",
3795   - false,
3796   - color != mxConstants.NONE ? color : "transparent",
3797   - );
3798   - ui.fireEvent(
3799   - new mxEventObject(
3800   - "styleChanged",
3801   - "keys",
3802   - [mxConstants.STYLE_FONTCOLOR],
3803   - "values",
3804   - [color],
3805   - "cells",
3806   - ss.cells,
3807   - ),
3808   - );
3809   -
3810   - // Finds the new or changed font element
3811   - var newFonts =
3812   - graph.cellEditor.textarea.getElementsByTagName("font");
3813   -
3814   - for (var i = 0; i < newFonts.length; i++) {
3815   - if (
3816   - i >= oldFonts.length ||
3817   - newFonts[i] != oldFonts[i].node ||
3818   - (newFonts[i] == oldFonts[i].node &&
3819   - newFonts[i].getAttribute("color") != oldFonts[i].color)
3820   - ) {
3821   - var child = newFonts[i].firstChild;
3822   -
3823   - // Moves the font element to inside the anchor element and adopts all children
3824   - if (
3825   - child != null &&
3826   - child.nodeName == "A" &&
3827   - child.nextSibling == null &&
3828   - child.firstChild != null
3829   - ) {
3830   - var parent = newFonts[i].parentNode;
3831   - parent.insertBefore(child, newFonts[i]);
3832   - var tmp = child.firstChild;
3833   -
3834   - while (tmp != null) {
3835   - var next = tmp.nextSibling;
3836   - newFonts[i].appendChild(tmp);
3837   - tmp = next;
3838   - }
3839   -
3840   - child.appendChild(newFonts[i]);
3841   - }
3842   -
3843   - break;
3844   - }
3845   - }
3846   - } else {
3847   - document.execCommand(
3848   - "forecolor",
3849   - false,
3850   - color != mxConstants.NONE ? color : "transparent",
3851   - );
3852   - ui.fireEvent(
3853   - new mxEventObject(
3854   - "styleChanged",
3855   - "keys",
3856   - [mxConstants.STYLE_FONTCOLOR],
3857   - "values",
3858   - [color],
3859   - "cells",
3860   - ss.cells,
3861   - ),
3862   - );
3863   - }
3864   - },
3865   - defs[mxConstants.STYLE_FONTCOLOR] != null
3866   - ? defs[mxConstants.STYLE_FONTCOLOR]
3867   - : graph.shapeForegroundColor,
3868   - {
3869   - install: function (apply) {
3870   - fontColorApply = apply;
3871   - },
3872   - destroy: function () {
3873   - fontColorApply = null;
3874   - },
3875   - },
3876   - null,
3877   - true,
3878   - )
3879   - : this.createCellColorOption(
3880   - mxResources.get("fontColor"),
3881   - mxConstants.STYLE_FONTCOLOR,
3882   - "default",
3883   - function (color) {
3884   - if (color == mxConstants.NONE) {
3885   - bgPanel.style.display = "none";
3886   - } else {
3887   - bgPanel.style.display = "";
3888   - }
3889   -
3890   - borderPanel.style.display = bgPanel.style.display;
3891   - },
3892   - function (color) {
3893   - if (color == mxConstants.NONE) {
3894   - graph.setCellStyles(mxConstants.STYLE_NOLABEL, "1", ss.cells);
3895   - } else {
3896   - graph.setCellStyles(mxConstants.STYLE_NOLABEL, null, ss.cells);
3897   - }
3898   -
3899   - graph.setCellStyles(mxConstants.STYLE_FONTCOLOR, color, ss.cells);
3900   -
3901   - graph.updateLabelElements(ss.cells, function (elt) {
3902   - elt.removeAttribute("color");
3903   - elt.style.color = null;
3904   - });
3905   - },
3906   - graph.shapeForegroundColor,
3907   - );
3908   - panel.style.fontWeight = "bold";
3909   -
3910   - colorPanel.appendChild(panel);
3911   - colorPanel.appendChild(bgPanel);
3912   -
3913   - if (!graph.cellEditor.isContentEditing()) {
3914   - colorPanel.appendChild(borderPanel);
3915   - }
3916   -
3917   - container.appendChild(colorPanel);
3918   -
3919   - var extraPanel = this.createPanel();
3920   - extraPanel.style.paddingTop = "2px";
3921   - extraPanel.style.paddingBottom = "4px";
3922   -
3923   - var wwCells = graph.filterSelectionCells(
3924   - mxUtils.bind(this, function (cell) {
3925   - var state = graph.view.getState(cell);
3926   -
3927   - return (
3928   - state == null ||
3929   - graph.isAutoSizeState(state) ||
3930   - graph.getModel().isEdge(cell) ||
3931   - (!graph.isTableRow(cell) &&
3932   - !graph.isTableCell(cell) &&
3933   - !graph.isCellResizable(cell))
3934   - );
3935   - }),
3936   - );
3937   -
3938   - var wwOpt = this.createCellOption(
3939   - mxResources.get("wordWrap"),
3940   - mxConstants.STYLE_WHITE_SPACE,
3941   - null,
3942   - "wrap",
3943   - "null",
3944   - null,
3945   - null,
3946   - true,
3947   - wwCells,
3948   - );
3949   - wwOpt.style.fontWeight = "bold";
3950   -
3951   - // Word wrap in edge labels only supported via labelWidth style
3952   - if (wwCells.length > 0) {
3953   - extraPanel.appendChild(wwOpt);
3954   - }
3955   -
3956   - // Delegates switch of style to formattedText action as it also convertes newlines
3957   - var htmlOpt = this.createCellOption(
3958   - mxResources.get("formattedText"),
3959   - "html",
3960   - 0,
3961   - null,
3962   - null,
3963   - null,
3964   - ui.actions.get("formattedText"),
3965   - );
3966   - htmlOpt.style.fontWeight = "bold";
3967   - extraPanel.appendChild(htmlOpt);
3968   -
3969   - var spacingPanel = this.createPanel();
3970   - spacingPanel.style.paddingTop = "10px";
3971   - spacingPanel.style.paddingBottom = "28px";
3972   - spacingPanel.style.fontWeight = "normal";
3973   -
3974   - var span = document.createElement("div");
3975   - span.style.position = "absolute";
3976   - span.style.width = "70px";
3977   - span.style.marginTop = "0px";
3978   - span.style.fontWeight = "bold";
3979   - mxUtils.write(span, mxResources.get("spacing"));
3980   - spacingPanel.appendChild(span);
3981   -
3982   - var topUpdate, globalUpdate, leftUpdate, bottomUpdate, rightUpdate;
3983   - var topSpacing = this.addUnitInput(spacingPanel, "pt", 87, 52, function () {
3984   - topUpdate.apply(this, arguments);
3985   - });
3986   - var globalSpacing = this.addUnitInput(
3987   - spacingPanel,
3988   - "pt",
3989   - 16,
3990   - 52,
3991   - function () {
3992   - globalUpdate.apply(this, arguments);
3993   - },
3994   - );
3995   -
3996   - mxUtils.br(spacingPanel);
3997   - this.addLabel(spacingPanel, mxResources.get("top"), 87);
3998   - this.addLabel(spacingPanel, mxResources.get("global"), 16);
3999   - mxUtils.br(spacingPanel);
4000   - mxUtils.br(spacingPanel);
4001   -
4002   - var leftSpacing = this.addUnitInput(spacingPanel, "pt", 158, 52, function () {
4003   - leftUpdate.apply(this, arguments);
4004   - });
4005   - var bottomSpacing = this.addUnitInput(
4006   - spacingPanel,
4007   - "pt",
4008   - 87,
4009   - 52,
4010   - function () {
4011   - bottomUpdate.apply(this, arguments);
4012   - },
4013   - );
4014   - var rightSpacing = this.addUnitInput(spacingPanel, "pt", 16, 52, function () {
4015   - rightUpdate.apply(this, arguments);
4016   - });
4017   -
4018   - mxUtils.br(spacingPanel);
4019   - this.addLabel(spacingPanel, mxResources.get("left"), 158);
4020   - this.addLabel(spacingPanel, mxResources.get("bottom"), 87);
4021   - this.addLabel(spacingPanel, mxResources.get("right"), 16);
4022   -
4023   - if (!graph.cellEditor.isContentEditing()) {
4024   - container.appendChild(extraPanel);
4025   - container.appendChild(
4026   - this.createRelativeOption(
4027   - mxResources.get("opacity"),
4028   - mxConstants.STYLE_TEXT_OPACITY,
4029   - ),
4030   - );
4031   - container.appendChild(spacingPanel);
4032   - } else {
4033   - var selState = null;
4034   - var lineHeightInput = null;
4035   -
4036   - container.appendChild(
4037   - this.createRelativeOption(
4038   - mxResources.get("lineheight"),
4039   - null,
4040   - null,
4041   - function (input) {
4042   - var value = input.value == "" ? 120 : parseInt(input.value);
4043   - value = Math.max(0, isNaN(value) ? 120 : value);
4044   -
4045   - if (selState != null) {
4046   - graph.cellEditor.restoreSelection(selState);
4047   - selState = null;
4048   - }
4049   -
4050   - var selectedElement = graph.getSelectedElement();
4051   - var node = selectedElement;
4052   -
4053   - while (
4054   - node != null &&
4055   - node.nodeType != mxConstants.NODETYPE_ELEMENT
4056   - ) {
4057   - node = node.parentNode;
4058   - }
4059   -
4060   - if (
4061   - node != null &&
4062   - node == graph.cellEditor.textarea &&
4063   - graph.cellEditor.textarea.firstChild != null
4064   - ) {
4065   - if (graph.cellEditor.textarea.firstChild.nodeName != "P") {
4066   - graph.cellEditor.textarea.innerHTML =
4067   - "<p>" + graph.cellEditor.textarea.innerHTML + "</p>";
4068   - }
4069   -
4070   - node = graph.cellEditor.textarea.firstChild;
4071   - }
4072   -
4073   - if (
4074   - node != null &&
4075   - graph.cellEditor.textarea != null &&
4076   - node != graph.cellEditor.textarea &&
4077   - graph.cellEditor.textarea.contains(node)
4078   - ) {
4079   - node.style.lineHeight = value / 100;
4080   - }
4081   -
4082   - input.value = value + " %";
4083   - },
4084   - function (input) {
4085   - // Used in CSS handler to update current value
4086   - lineHeightInput = input;
4087   -
4088   - // KNOWN: Arrow up/down clear selection text in quirks/IE 8
4089   - // Text size via arrow button limits to 16 in IE11. Why?
4090   - mxEvent.addListener(input, "mousedown", function () {
4091   - if (document.activeElement == graph.cellEditor.textarea) {
4092   - selState = graph.cellEditor.saveSelection();
4093   - }
4094   - });
4095   -
4096   - mxEvent.addListener(input, "touchstart", function () {
4097   - if (document.activeElement == graph.cellEditor.textarea) {
4098   - selState = graph.cellEditor.saveSelection();
4099   - }
4100   - });
4101   -
4102   - input.value = "120 %";
4103   - },
4104   - ),
4105   - );
4106   -
4107   - var insertPanel = stylePanel.cloneNode(false);
4108   - insertPanel.style.paddingLeft = "0px";
4109   - var insertBtns = this.editorUi.toolbar.addItems(
4110   - ["link", "image"],
4111   - insertPanel,
4112   - true,
4113   - );
4114   -
4115   - var btns = [
4116   - this.editorUi.toolbar.addButton(
4117   - "geSprite-horizontalrule",
4118   - mxResources.get("insertHorizontalRule"),
4119   - function () {
4120   - document.execCommand("inserthorizontalrule", false);
4121   - },
4122   - insertPanel,
4123   - ),
4124   - this.editorUi.toolbar.addMenuFunctionInContainer(
4125   - insertPanel,
4126   - "geSprite-table",
4127   - mxResources.get("table"),
4128   - false,
4129   - mxUtils.bind(this, function (menu) {
4130   - this.editorUi.menus.addInsertTableItem(menu, null, null, false);
4131   - }),
4132   - ),
4133   - ];
4134   - this.styleButtons(insertBtns);
4135   - this.styleButtons(btns);
4136   -
4137   - var wrapper2 = this.createPanel();
4138   - wrapper2.style.paddingTop = "10px";
4139   - wrapper2.style.paddingBottom = "10px";
4140   - wrapper2.appendChild(this.createTitle(mxResources.get("insert")));
4141   - wrapper2.appendChild(insertPanel);
4142   - container.appendChild(wrapper2);
4143   -
4144   - var tablePanel = stylePanel.cloneNode(false);
4145   - tablePanel.style.paddingLeft = "0px";
4146   -
4147   - var btns = [
4148   - this.editorUi.toolbar.addButton(
4149   - "geSprite-insertcolumnbefore",
4150   - mxResources.get("insertColumnBefore"),
4151   - mxUtils.bind(this, function () {
4152   - try {
4153   - if (currentTable != null) {
4154   - graph.insertColumn(
4155   - currentTable,
4156   - tableCell != null ? tableCell.cellIndex : 0,
4157   - );
4158   - }
4159   - } catch (e) {
4160   - this.editorUi.handleError(e);
4161   - }
4162   - }),
4163   - tablePanel,
4164   - ),
4165   - this.editorUi.toolbar.addButton(
4166   - "geSprite-insertcolumnafter",
4167   - mxResources.get("insertColumnAfter"),
4168   - mxUtils.bind(this, function () {
4169   - try {
4170   - if (currentTable != null) {
4171   - graph.insertColumn(
4172   - currentTable,
4173   - tableCell != null ? tableCell.cellIndex + 1 : -1,
4174   - );
4175   - }
4176   - } catch (e) {
4177   - this.editorUi.handleError(e);
4178   - }
4179   - }),
4180   - tablePanel,
4181   - ),
4182   - this.editorUi.toolbar.addButton(
4183   - "geSprite-deletecolumn",
4184   - mxResources.get("deleteColumn"),
4185   - mxUtils.bind(this, function () {
4186   - try {
4187   - if (currentTable != null && tableCell != null) {
4188   - graph.deleteColumn(currentTable, tableCell.cellIndex);
4189   - }
4190   - } catch (e) {
4191   - this.editorUi.handleError(e);
4192   - }
4193   - }),
4194   - tablePanel,
4195   - ),
4196   - this.editorUi.toolbar.addButton(
4197   - "geSprite-insertrowbefore",
4198   - mxResources.get("insertRowBefore"),
4199   - mxUtils.bind(this, function () {
4200   - try {
4201   - if (currentTable != null && tableRow != null) {
4202   - graph.insertRow(currentTable, tableRow.sectionRowIndex);
4203   - }
4204   - } catch (e) {
4205   - this.editorUi.handleError(e);
4206   - }
4207   - }),
4208   - tablePanel,
4209   - ),
4210   - this.editorUi.toolbar.addButton(
4211   - "geSprite-insertrowafter",
4212   - mxResources.get("insertRowAfter"),
4213   - mxUtils.bind(this, function () {
4214   - try {
4215   - if (currentTable != null && tableRow != null) {
4216   - graph.insertRow(currentTable, tableRow.sectionRowIndex + 1);
4217   - }
4218   - } catch (e) {
4219   - this.editorUi.handleError(e);
4220   - }
4221   - }),
4222   - tablePanel,
4223   - ),
4224   - this.editorUi.toolbar.addButton(
4225   - "geSprite-deleterow",
4226   - mxResources.get("deleteRow"),
4227   - mxUtils.bind(this, function () {
4228   - try {
4229   - if (currentTable != null && tableRow != null) {
4230   - graph.deleteRow(currentTable, tableRow.sectionRowIndex);
4231   - }
4232   - } catch (e) {
4233   - this.editorUi.handleError(e);
4234   - }
4235   - }),
4236   - tablePanel,
4237   - ),
4238   - ];
4239   - this.styleButtons(btns);
4240   - btns[2].style.marginRight = "10px";
4241   -
4242   - var wrapper3 = this.createPanel();
4243   - wrapper3.style.paddingTop = "10px";
4244   - wrapper3.style.paddingBottom = "10px";
4245   - wrapper3.appendChild(this.createTitle(mxResources.get("table")));
4246   - wrapper3.appendChild(tablePanel);
4247   -
4248   - var tablePanel2 = stylePanel.cloneNode(false);
4249   - tablePanel2.style.paddingLeft = "0px";
4250   -
4251   - var btns = [
4252   - this.editorUi.toolbar.addButton(
4253   - "geSprite-strokecolor",
4254   - mxResources.get("borderColor"),
4255   - mxUtils.bind(this, function (evt) {
4256   - if (currentTable != null) {
4257   - // Converts rgb(r,g,b) values
4258   - var color = currentTable.style.borderColor.replace(
4259   - /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
4260   - function ($0, $1, $2, $3) {
4261   - return (
4262   - "#" +
4263   - ("0" + Number($1).toString(16)).substr(-2) +
4264   - ("0" + Number($2).toString(16)).substr(-2) +
4265   - ("0" + Number($3).toString(16)).substr(-2)
4266   - );
4267   - },
4268   - );
4269   - this.editorUi.pickColor(color, function (newColor) {
4270   - var targetElt =
4271   - tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))
4272   - ? tableCell
4273   - : currentTable;
4274   -
4275   - graph.processElements(targetElt, function (elt) {
4276   - elt.style.border = null;
4277   - });
4278   -
4279   - if (newColor == null || newColor == mxConstants.NONE) {
4280   - targetElt.removeAttribute("border");
4281   - targetElt.style.border = "";
4282   - targetElt.style.borderCollapse = "";
4283   - } else {
4284   - targetElt.setAttribute("border", "1");
4285   - targetElt.style.border = "1px solid " + newColor;
4286   - targetElt.style.borderCollapse = "collapse";
4287   - }
4288   - });
4289   - }
4290   - }),
4291   - tablePanel2,
4292   - ),
4293   - this.editorUi.toolbar.addButton(
4294   - "geSprite-fillcolor",
4295   - mxResources.get("backgroundColor"),
4296   - mxUtils.bind(this, function (evt) {
4297   - // Converts rgb(r,g,b) values
4298   - if (currentTable != null) {
4299   - var color = currentTable.style.backgroundColor.replace(
4300   - /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
4301   - function ($0, $1, $2, $3) {
4302   - return (
4303   - "#" +
4304   - ("0" + Number($1).toString(16)).substr(-2) +
4305   - ("0" + Number($2).toString(16)).substr(-2) +
4306   - ("0" + Number($3).toString(16)).substr(-2)
4307   - );
4308   - },
4309   - );
4310   - this.editorUi.pickColor(color, function (newColor) {
4311   - var targetElt =
4312   - tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))
4313   - ? tableCell
4314   - : currentTable;
4315   -
4316   - graph.processElements(targetElt, function (elt) {
4317   - elt.style.backgroundColor = null;
4318   - });
4319   -
4320   - if (newColor == null || newColor == mxConstants.NONE) {
4321   - targetElt.style.backgroundColor = "";
4322   - } else {
4323   - targetElt.style.backgroundColor = newColor;
4324   - }
4325   - });
4326   - }
4327   - }),
4328   - tablePanel2,
4329   - ),
4330   - this.editorUi.toolbar.addButton(
4331   - "geSprite-fit",
4332   - mxResources.get("spacing"),
4333   - function () {
4334   - if (currentTable != null) {
4335   - var value = currentTable.getAttribute("cellPadding") || 0;
4336   -
4337   - var dlg = new FilenameDialog(
4338   - ui,
4339   - value,
4340   - mxResources.get("apply"),
4341   - mxUtils.bind(this, function (newValue) {
4342   - if (newValue != null && newValue.length > 0) {
4343   - currentTable.setAttribute("cellPadding", newValue);
4344   - } else {
4345   - currentTable.removeAttribute("cellPadding");
4346   - }
4347   - }),
4348   - mxResources.get("spacing"),
4349   - );
4350   - ui.showDialog(dlg.container, 300, 80, true, true);
4351   - dlg.init();
4352   - }
4353   - },
4354   - tablePanel2,
4355   - ),
4356   - this.editorUi.toolbar.addButton(
4357   - "geSprite-left",
4358   - mxResources.get("left"),
4359   - function () {
4360   - if (currentTable != null) {
4361   - currentTable.setAttribute("align", "left");
4362   - }
4363   - },
4364   - tablePanel2,
4365   - ),
4366   - this.editorUi.toolbar.addButton(
4367   - "geSprite-center",
4368   - mxResources.get("center"),
4369   - function () {
4370   - if (currentTable != null) {
4371   - currentTable.setAttribute("align", "center");
4372   - }
4373   - },
4374   - tablePanel2,
4375   - ),
4376   - this.editorUi.toolbar.addButton(
4377   - "geSprite-right",
4378   - mxResources.get("right"),
4379   - function () {
4380   - if (currentTable != null) {
4381   - currentTable.setAttribute("align", "right");
4382   - }
4383   - },
4384   - tablePanel2,
4385   - ),
4386   - ];
4387   - this.styleButtons(btns);
4388   - btns[2].style.marginRight = "10px";
4389   -
4390   - wrapper3.appendChild(tablePanel2);
4391   - container.appendChild(wrapper3);
4392   -
4393   - tableWrapper = wrapper3;
4394   - }
4395   -
4396   - function setSelected(elt, selected) {
4397   - elt.style.backgroundImage = selected
4398   - ? Editor.isDarkMode()
4399   - ? "linear-gradient(rgb(0 161 241) 0px, rgb(0, 97, 146) 100%)"
4400   - : "linear-gradient(#c5ecff 0px,#87d4fb 100%)"
4401   - : "";
4402   - }
4403   -
4404   - var listener = mxUtils.bind(this, function (sender, evt, force) {
4405   - ss = ui.getSelectionState();
4406   - var fontStyle = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSTYLE, 0);
4407   - setSelected(
4408   - fontStyleItems[0],
4409   - (fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD,
4410   - );
4411   - setSelected(
4412   - fontStyleItems[1],
4413   - (fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC,
4414   - );
4415   - setSelected(
4416   - fontStyleItems[2],
4417   - (fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE,
4418   - );
4419   - fontMenu.firstChild.nodeValue = mxUtils.getValue(
4420   - ss.style,
4421   - mxConstants.STYLE_FONTFAMILY,
4422   - Menus.prototype.defaultFont,
4423   - );
4424   -
4425   - setSelected(
4426   - verticalItem,
4427   - mxUtils.getValue(ss.style, mxConstants.STYLE_HORIZONTAL, "1") == "0",
4428   - );
4429   -
4430   - if (force || document.activeElement != input) {
4431   - var tmp = parseFloat(
4432   - mxUtils.getValue(
4433   - ss.style,
4434   - mxConstants.STYLE_FONTSIZE,
4435   - Menus.prototype.defaultFontSize,
4436   - ),
4437   - );
4438   - input.value = isNaN(tmp) ? "" : tmp + " pt";
4439   - }
4440   -
4441   - var align = mxUtils.getValue(
4442   - ss.style,
4443   - mxConstants.STYLE_ALIGN,
4444   - mxConstants.ALIGN_CENTER,
4445   - );
4446   - setSelected(left, align == mxConstants.ALIGN_LEFT);
4447   - setSelected(center, align == mxConstants.ALIGN_CENTER);
4448   - setSelected(right, align == mxConstants.ALIGN_RIGHT);
4449   -
4450   - var valign = mxUtils.getValue(
4451   - ss.style,
4452   - mxConstants.STYLE_VERTICAL_ALIGN,
4453   - mxConstants.ALIGN_MIDDLE,
4454   - );
4455   - setSelected(top, valign == mxConstants.ALIGN_TOP);
4456   - setSelected(middle, valign == mxConstants.ALIGN_MIDDLE);
4457   - setSelected(bottom, valign == mxConstants.ALIGN_BOTTOM);
4458   -
4459   - var pos = mxUtils.getValue(
4460   - ss.style,
4461   - mxConstants.STYLE_LABEL_POSITION,
4462   - mxConstants.ALIGN_CENTER,
4463   - );
4464   - var vpos = mxUtils.getValue(
4465   - ss.style,
4466   - mxConstants.STYLE_VERTICAL_LABEL_POSITION,
4467   - mxConstants.ALIGN_MIDDLE,
4468   - );
4469   -
4470   - if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_TOP) {
4471   - positionSelect.value = "topLeft";
4472   - } else if (
4473   - pos == mxConstants.ALIGN_CENTER &&
4474   - vpos == mxConstants.ALIGN_TOP
4475   - ) {
4476   - positionSelect.value = "top";
4477   - } else if (
4478   - pos == mxConstants.ALIGN_RIGHT &&
4479   - vpos == mxConstants.ALIGN_TOP
4480   - ) {
4481   - positionSelect.value = "topRight";
4482   - } else if (
4483   - pos == mxConstants.ALIGN_LEFT &&
4484   - vpos == mxConstants.ALIGN_BOTTOM
4485   - ) {
4486   - positionSelect.value = "bottomLeft";
4487   - } else if (
4488   - pos == mxConstants.ALIGN_CENTER &&
4489   - vpos == mxConstants.ALIGN_BOTTOM
4490   - ) {
4491   - positionSelect.value = "bottom";
4492   - } else if (
4493   - pos == mxConstants.ALIGN_RIGHT &&
4494   - vpos == mxConstants.ALIGN_BOTTOM
4495   - ) {
4496   - positionSelect.value = "bottomRight";
4497   - } else if (pos == mxConstants.ALIGN_LEFT) {
4498   - positionSelect.value = "left";
4499   - } else if (pos == mxConstants.ALIGN_RIGHT) {
4500   - positionSelect.value = "right";
4501   - } else {
4502   - positionSelect.value = "center";
4503   - }
4504   -
4505   - var dir = mxUtils.getValue(
4506   - ss.style,
4507   - mxConstants.STYLE_TEXT_DIRECTION,
4508   - mxConstants.DEFAULT_TEXT_DIRECTION,
4509   - );
4510   -
4511   - if (dir == mxConstants.TEXT_DIRECTION_RTL) {
4512   - dirSelect.value = "rightToLeft";
4513   - } else if (dir == mxConstants.TEXT_DIRECTION_LTR) {
4514   - dirSelect.value = "leftToRight";
4515   - } else if (dir == mxConstants.TEXT_DIRECTION_AUTO) {
4516   - dirSelect.value = "automatic";
4517   - }
4518   -
4519   - if (force || document.activeElement != globalSpacing) {
4520   - var tmp = parseFloat(
4521   - mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING, 2),
4522   - );
4523   - globalSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
4524   - }
4525   -
4526   - if (force || document.activeElement != topSpacing) {
4527   - var tmp = parseFloat(
4528   - mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_TOP, 0),
4529   - );
4530   - topSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
4531   - }
4532   -
4533   - if (force || document.activeElement != rightSpacing) {
4534   - var tmp = parseFloat(
4535   - mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_RIGHT, 0),
4536   - );
4537   - rightSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
4538   - }
4539   -
4540   - if (force || document.activeElement != bottomSpacing) {
4541   - var tmp = parseFloat(
4542   - mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_BOTTOM, 0),
4543   - );
4544   - bottomSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
4545   - }
4546   -
4547   - if (force || document.activeElement != leftSpacing) {
4548   - var tmp = parseFloat(
4549   - mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_LEFT, 0),
4550   - );
4551   - leftSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
4552   - }
4553   - });
4554   -
4555   - globalUpdate = this.installInputHandler(
4556   - globalSpacing,
4557   - mxConstants.STYLE_SPACING,
4558   - 2,
4559   - -999,
4560   - 999,
4561   - " pt",
4562   - );
4563   - topUpdate = this.installInputHandler(
4564   - topSpacing,
4565   - mxConstants.STYLE_SPACING_TOP,
4566   - 0,
4567   - -999,
4568   - 999,
4569   - " pt",
4570   - );
4571   - rightUpdate = this.installInputHandler(
4572   - rightSpacing,
4573   - mxConstants.STYLE_SPACING_RIGHT,
4574   - 0,
4575   - -999,
4576   - 999,
4577   - " pt",
4578   - );
4579   - bottomUpdate = this.installInputHandler(
4580   - bottomSpacing,
4581   - mxConstants.STYLE_SPACING_BOTTOM,
4582   - 0,
4583   - -999,
4584   - 999,
4585   - " pt",
4586   - );
4587   - leftUpdate = this.installInputHandler(
4588   - leftSpacing,
4589   - mxConstants.STYLE_SPACING_LEFT,
4590   - 0,
4591   - -999,
4592   - 999,
4593   - " pt",
4594   - );
4595   -
4596   - this.addKeyHandler(input, listener);
4597   - this.addKeyHandler(globalSpacing, listener);
4598   - this.addKeyHandler(topSpacing, listener);
4599   - this.addKeyHandler(rightSpacing, listener);
4600   - this.addKeyHandler(bottomSpacing, listener);
4601   - this.addKeyHandler(leftSpacing, listener);
4602   -
4603   - graph.getModel().addListener(mxEvent.CHANGE, listener);
4604   - this.listeners.push({
4605   - destroy: function () {
4606   - graph.getModel().removeListener(listener);
4607   - },
4608   - });
4609   - listener();
4610   -
4611   - if (graph.cellEditor.isContentEditing()) {
4612   - var updating = false;
4613   -
4614   - var updateCssHandler = function () {
4615   - if (!updating) {
4616   - updating = true;
4617   -
4618   - window.setTimeout(function () {
4619   - var node = graph.getSelectedEditingElement();
4620   -
4621   - if (node != null) {
4622   - function getRelativeLineHeight(fontSize, css, elt) {
4623   - if (elt.style != null && css != null) {
4624   - var lineHeight = css.lineHeight;
4625   -
4626   - if (
4627   - elt.style.lineHeight != null &&
4628   - elt.style.lineHeight.substring(
4629   - elt.style.lineHeight.length - 1,
4630   - ) == "%"
4631   - ) {
4632   - return parseInt(elt.style.lineHeight) / 100;
4633   - } else {
4634   - return lineHeight.substring(lineHeight.length - 2) == "px"
4635   - ? parseFloat(lineHeight) / fontSize
4636   - : parseInt(lineHeight);
4637   - }
4638   - } else {
4639   - return "";
4640   - }
4641   - }
4642   -
4643   - function getAbsoluteFontSize(css) {
4644   - var fontSize = css != null ? css.fontSize : null;
4645   -
4646   - if (
4647   - fontSize != null &&
4648   - fontSize.substring(fontSize.length - 2) == "px"
4649   - ) {
4650   - return parseFloat(fontSize);
4651   - } else {
4652   - return mxConstants.DEFAULT_FONTSIZE;
4653   - }
4654   - }
4655   -
4656   - var css = mxUtils.getCurrentStyle(node);
4657   - var fontSize = getAbsoluteFontSize(css);
4658   - var lineHeight = getRelativeLineHeight(fontSize, css, node);
4659   -
4660   - // Finds common font size
4661   - var elts = node.getElementsByTagName("*");
4662   -
4663   - // IE does not support containsNode
4664   - if (
4665   - elts.length > 0 &&
4666   - window.getSelection &&
4667   - !mxClient.IS_IE &&
4668   - !mxClient.IS_IE11
4669   - ) {
4670   - var selection = window.getSelection();
4671   -
4672   - for (var i = 0; i < elts.length; i++) {
4673   - if (selection.containsNode(elts[i], true)) {
4674   - temp = mxUtils.getCurrentStyle(elts[i]);
4675   - fontSize = Math.max(getAbsoluteFontSize(temp), fontSize);
4676   - var lh = getRelativeLineHeight(fontSize, temp, elts[i]);
4677   -
4678   - if (lh != lineHeight || isNaN(lh)) {
4679   - lineHeight = "";
4680   - }
4681   - }
4682   - }
4683   - }
4684   -
4685   - function hasParentOrOnlyChild(name) {
4686   - if (
4687   - graph.getParentByName(node, name, graph.cellEditor.textarea) !=
4688   - null
4689   - ) {
4690   - return true;
4691   - } else {
4692   - var child = node;
4693   -
4694   - while (child != null && child.childNodes.length == 1) {
4695   - child = child.childNodes[0];
4696   -
4697   - if (child.nodeName == name) {
4698   - return true;
4699   - }
4700   - }
4701   - }
4702   -
4703   - return false;
4704   - }
4705   -
4706   - function isEqualOrPrefixed(str, value) {
4707   - if (str != null && value != null) {
4708   - if (str == value) {
4709   - return true;
4710   - } else if (str.length > value.length + 1) {
4711   - return (
4712   - str.substring(str.length - value.length - 1, str.length) ==
4713   - "-" + value
4714   - );
4715   - }
4716   - }
4717   -
4718   - return false;
4719   - }
4720   -
4721   - if (css != null) {
4722   - setSelected(
4723   - fontStyleItems[0],
4724   - css.fontWeight == "bold" ||
4725   - css.fontWeight > 400 ||
4726   - hasParentOrOnlyChild("B") ||
4727   - hasParentOrOnlyChild("STRONG"),
4728   - );
4729   - setSelected(
4730   - fontStyleItems[1],
4731   - css.fontStyle == "italic" ||
4732   - hasParentOrOnlyChild("I") ||
4733   - hasParentOrOnlyChild("EM"),
4734   - );
4735   - setSelected(fontStyleItems[2], hasParentOrOnlyChild("U"));
4736   - setSelected(sup, hasParentOrOnlyChild("SUP"));
4737   - setSelected(sub, hasParentOrOnlyChild("SUB"));
4738   -
4739   - if (!graph.cellEditor.isTableSelected()) {
4740   - var align =
4741   - graph.cellEditor.align ||
4742   - mxUtils.getValue(
4743   - ss.style,
4744   - mxConstants.STYLE_ALIGN,
4745   - mxConstants.ALIGN_CENTER,
4746   - );
4747   -
4748   - if (isEqualOrPrefixed(css.textAlign, "justify")) {
4749   - setSelected(
4750   - full,
4751   - isEqualOrPrefixed(css.textAlign, "justify"),
4752   - );
4753   - setSelected(left, false);
4754   - setSelected(center, false);
4755   - setSelected(right, false);
4756   - } else {
4757   - setSelected(full, false);
4758   - setSelected(left, align == mxConstants.ALIGN_LEFT);
4759   - setSelected(center, align == mxConstants.ALIGN_CENTER);
4760   - setSelected(right, align == mxConstants.ALIGN_RIGHT);
4761   - }
4762   - } else {
4763   - setSelected(full, isEqualOrPrefixed(css.textAlign, "justify"));
4764   - setSelected(left, isEqualOrPrefixed(css.textAlign, "left"));
4765   - setSelected(center, isEqualOrPrefixed(css.textAlign, "center"));
4766   - setSelected(right, isEqualOrPrefixed(css.textAlign, "right"));
4767   - }
4768   -
4769   - currentTable = graph.getParentByName(
4770   - node,
4771   - "TABLE",
4772   - graph.cellEditor.textarea,
4773   - );
4774   - tableRow =
4775   - currentTable == null
4776   - ? null
4777   - : graph.getParentByName(node, "TR", currentTable);
4778   - tableCell =
4779   - currentTable == null
4780   - ? null
4781   - : graph.getParentByNames(node, ["TD", "TH"], currentTable);
4782   - tableWrapper.style.display = currentTable != null ? "" : "none";
4783   -
4784   - if (document.activeElement != input) {
4785   - if (
4786   - node.nodeName == "FONT" &&
4787   - node.getAttribute("size") == "4" &&
4788   - pendingFontSize != null
4789   - ) {
4790   - node.removeAttribute("size");
4791   - node.style.fontSize = pendingFontSize + " pt";
4792   - pendingFontSize = null;
4793   - } else {
4794   - input.value = isNaN(fontSize) ? "" : fontSize + " pt";
4795   - }
4796   -
4797   - var lh = parseFloat(lineHeight);
4798   -
4799   - if (!isNaN(lh)) {
4800   - lineHeightInput.value = Math.round(lh * 100) + " %";
4801   - } else {
4802   - lineHeightInput.value = "100 %";
4803   - }
4804   - }
4805   -
4806   - // Updates the color picker for the current font
4807   - if (fontColorApply != null) {
4808   - if (
4809   - css.color == "rgba(0, 0, 0, 0)" ||
4810   - css.color == "transparent"
4811   - ) {
4812   - currentFontColor = mxConstants.NONE;
4813   - } else {
4814   - currentFontColor = mxUtils.rgba2hex(css.color);
4815   - }
4816   -
4817   - fontColorApply(currentFontColor, true);
4818   - }
4819   -
4820   - if (bgColorApply != null) {
4821   - if (
4822   - css.backgroundColor == "rgba(0, 0, 0, 0)" ||
4823   - css.backgroundColor == "transparent"
4824   - ) {
4825   - currentBgColor = mxConstants.NONE;
4826   - } else {
4827   - currentBgColor = mxUtils.rgba2hex(css.backgroundColor);
4828   - }
4829   -
4830   - bgColorApply(currentBgColor, true);
4831   - }
4832   -
4833   - // Workaround for firstChild is null or not an object
4834   - // in the log which seems to be IE8- only / 29.01.15
4835   - if (fontMenu.firstChild != null) {
4836   - fontMenu.firstChild.nodeValue = Graph.stripQuotes(
4837   - css.fontFamily,
4838   - );
4839   - }
4840   - }
4841   - }
4842   -
4843   - updating = false;
4844   - }, 0);
4845   - }
4846   - };
4847   -
4848   - if (
4849   - mxClient.IS_FF ||
4850   - mxClient.IS_EDGE ||
4851   - mxClient.IS_IE ||
4852   - mxClient.IS_IE11
4853   - ) {
4854   - mxEvent.addListener(
4855   - graph.cellEditor.textarea,
4856   - "DOMSubtreeModified",
4857   - updateCssHandler,
4858   - );
4859   - }
4860   -
4861   - mxEvent.addListener(graph.cellEditor.textarea, "input", updateCssHandler);
4862   - mxEvent.addListener(
4863   - graph.cellEditor.textarea,
4864   - "touchend",
4865   - updateCssHandler,
4866   - );
4867   - mxEvent.addListener(graph.cellEditor.textarea, "mouseup", updateCssHandler);
4868   - mxEvent.addListener(graph.cellEditor.textarea, "keyup", updateCssHandler);
4869   - this.listeners.push({
4870   - destroy: function () {
4871   - // No need to remove listener since textarea is destroyed after edit
4872   - },
4873   - });
4874   - updateCssHandler();
4875   - }
4876   -
4877   - return container;
4878   -};
4879   -
4880   -/**
4881   - * 数据绑定格式化面板
4882   - */
4883   -DataFormatPanel = function (format, editorUi, container) {
4884   - BaseFormatPanel.call(this, format, editorUi, container);
4885   - this.init();
4886   -};
4887   -
4888   -mxUtils.extend(DataFormatPanel, BaseFormatPanel);
4889   -
4890   -/**
4891   - * 数据绑定面板初始化
4892   - */
4893   -DataFormatPanel.prototype.init = function () {
4894   - this.container.style.borderBottom = "none";
4895   - this.addDataFont(this.container);
4896   -};
4897   -
4898   -// TODO 数据绑定
4899   -DataFormatPanel.prototype.addDataFont = function (container) {
4900   - const ui = this.editorUi;
4901   - const editor = ui.editor;
4902   - const graph = editor.graph;
4903   - const ss = ui.getSelectionState();
4904   - const vertices = ss.vertices || []
4905   - const sidebarInstance = ui.sidebar
4906   - console.log(vertices)
4907   - console.log(ui)
4908   -
4909   - const hasModifyNotSave = editor.status
4910   -
4911   - /**
4912   - * @description 不是单一节点则不进入数据绑定
4913   - */
4914   - if (!isSingleNode(vertices)) return
4915   -
4916   - // 组态id
4917   - const configurationId = getRequest().configurationId;
4918   - // 当前内容页的id
4919   - const currentPageId = ui.currentPage.node;
4920   -
4921   - // 图形的id
4922   - const graphId = vertices[0].id;
4923   -
4924   - // 解构全局属性layui要用到的模块
4925   - const { layer, form, jquery: $, colorpicker, upload, element } = layui;
4926   -
4927   - const CONTAINER_FILTER = 'containerFilter'
4928   - $(container).addClass('layui-form').attr('lay-filter', CONTAINER_FILTER)
4929   -
4930   - /**
4931   - * @description 创建面版
4932   - */
4933   - const createPanel = this.createPanel
4934   -
4935   - /**
4936   - * @description 创建标题
4937   - */
4938   - const createTitle = this.createTitle
4939   -
4940   -
4941   - /**
4942   - * @description 选中节点信息来源
4943   - * @param {string} nodeInfo.id - 节点ID
4944   - */
4945   - const nodeInfo = getNodeInfo(vertices)
4946   -
4947   -
4948   - /**
4949   - * @description 组织树
4950   - * @type {*[]}
4951   - */
4952   - let treeList = []
4953   -
4954   - /**
4955   - * @description 当前选中的组织树节点
4956   - * @type {null | string}
4957   - */
4958   - let currentCheckedOrgNode = null
4959   -
4960   - /**
4961   - * @description 当前节点绑定数据
4962   - * @type {null | {act: [], event: [], dataSources: []}}
4963   - */
4964   - let currentNodeData = null
4965   -
4966   - /**
4967   - * @description 覆盖当前节点数据
4968   - * @param {'act' | 'dataSources' | 'event'} key
4969   - * @param {string}
4970   - */
4971   - function overrideCurrentData(key, uuid = 'id', value = {}) {
4972   - if (!currentNodeData[key]) currentNodeData[key] = []
4973   - const index = currentNodeData[key].findIndex(item => item[uuid] === value[uuid])
4974   - ~index ? currentNodeData[key][index] = value : currentNodeData[key].push(value)
4975   - }
4976   -
4977   - /**
4978   - * @description 保存页面信息
4979   - */
4980   - async function autoSaveGraphInfo() {
4981   - if (!hasModifyNotSave) return
4982   - ui.actions.get(
4983   - (ui.currentFile.mode == null || !ui.currentFile.isEditable())
4984   - ? 'saveAs'
4985   - : 'save')
4986   - .funct();
4987   - }
4988   -
4989   - /**
4990   - * @description 获取弹出层绑定信息
4991   - * @param {'DOWN' | 'UP' | 'SINGLE' | 'DOUBLE' | 'DISPLAY' | 'FLASH' | 'ROTATE' | 'IMAGE'} type - 类型
4992   - * @param {'event' | 'act' } category - 类别
4993   - */
4994   - function getLayerBindInfo(category, type) {
4995   - if (currentNodeData) {
4996   - return currentNodeData[category]?.find(item => item.type === type) || {}
4997   - }
4998   - return {}
4999   - }
5000   -
5001   - const enumCategory = {
5002   - ACT: 'act',
5003   - EVENT: 'event',
5004   - DATA_SOURCE: 'dataSources',
5005   - }
5006   -
5007   - const enumInteractionType = {
5008   - DOWN: 'DOWN',
5009   - UP: 'UP',
5010   - SINGLE: 'SINGLE',
5011   - DOUBLE: 'DOUBLE',
5012   - }
5013   -
5014   - const enumDynamicEffectType = {
5015   - DISPLAY: 'DISPLAY',
5016   - FLASH: 'FLASH',
5017   - ROTATE: 'ROTATE',
5018   - IMAGE: 'IMAGE',
5019   - SWITCH: 'SWITCH',
5020   - RUNNING: 'RUNNING'
5021   - }
5022   -
5023   - const interactionList = [
5024   - {
5025   - label: "按下",
5026   - type: enumInteractionType.DOWN,
5027   - category: enumCategory.EVENT,
5028   - },
5029   - {
5030   - label: "抬起",
5031   - type: enumInteractionType.UP,
5032   - category: enumCategory.EVENT,
5033   - },
5034   - {
5035   - label: "单击",
5036   - type: enumInteractionType.SINGLE,
5037   - category: enumCategory.EVENT,
5038   - },
5039   - {
5040   - label: "双击",
5041   - type: enumInteractionType.DOUBLE,
5042   - category: enumCategory.EVENT,
5043   - },
5044   - ];
5045   -
5046   - const dynamicEffectList = [
5047   - {
5048   - label: "闪烁",
5049   - type: enumDynamicEffectType.FLASH,
5050   - category: enumCategory.ACT,
5051   - },
5052   - {
5053   - label: "显示/隐藏",
5054   - type: enumDynamicEffectType.DISPLAY,
5055   - category: enumCategory.ACT,
5056   - },
5057   - {
5058   - label: "旋转",
5059   - type: enumDynamicEffectType.ROTATE,
5060   - category: enumCategory.ACT,
5061   - }
5062   - ];
5063   -
5064   - const enumDataSourceConst = {
5065   - ORG_ID: 'orgId',
5066   - DEVICE_ID: 'deviceId',
5067   - SLAVE_DEVICE_ID: 'slaveDeviceId',
5068   - ATTR: 'attr',
5069   - GATEWAY: 'GATEWAY',
5070   - ADDITIONAL: 'additional'
5071   - }
5072   -
5073   - /**
5074   - * @description 刷新页面 用于在其他位置调用更新数据面板的操作,默认是个空函数,在生成数据源面板中进行了拓展
5075   - */
5076   - function echoRefreshFn() {
5077   - }
5078   -
5079   - /**
5080   - * @description 用于在其他位置获取数据源绑定的数据,在生成数据源面板中进行了改写
5081   - * @return {{orgId: string, attr: string, deviceId: string, slaveDeviceId: string}}
5082   - */
5083   - function getDataSourceBindValue() {
5084   -
5085   - }
5086   -
5087   -
5088   - // 获取url的请求参数函数
5089   - function getRequest() {
5090   - let url = location.search; //获取url中"?"符后的字串
5091   - let theRequest = new Object();
5092   - if (url.indexOf("?") != -1) {
5093   - var str = url.substring(1);
5094   - string = str.split("&");
5095   - for (var i = 0; i < string.length; i++) {
5096   - theRequest[string[i].split("=")[0]] = decodeURI(string[i].split("=")[1]);
5097   - }
5098   - }
5099   - return theRequest;
5100   - }
5101   -
5102   - /**
5103   - * @description 单一节点
5104   - */
5105   - function isSingleNode(vertices) {
5106   - return Array.isArray(vertices) && vertices.length === 1
5107   - }
5108   -
5109   - /**
5110   - * @description 获取节点信息
5111   - * @returns {{id: string}} - 当前选中节点源信息
5112   - */
5113   - function getNodeInfo(node) {
5114   - if (isSingleNode(node)) {
5115   - return node[0]
5116   - }
5117   - return {}
5118   - }
5119   -
5120   - /**
5121   - * @description 初始化节点
5122   - */
5123   - async function initNode() {
5124   - const basicAttr = sidebarInstance.enumCellBasicAttribute
5125   - const permissionKey = sidebarInstance.enumPermissionPanel
5126   - const { LINE_CHART, BAR_CHART, DASHBOARD_CHART } = Sidebar.prototype.enumComponentType
5127   -
5128   - const renderMapping = {
5129   - [permissionKey.DATA_SOURCE]: createDataSourcePanel,
5130   - [permissionKey.LINE_CHART_EXPAND]: createChartBindPanel.bind(this, LINE_CHART),
5131   - [permissionKey.BAR_CHART_EXPAND]: createChartBindPanel.bind(this, BAR_CHART),
5132   - [permissionKey.DASHBOARD_CHART_EXPAND]: createChartBindPanel.bind(this, DASHBOARD_CHART),
5133   - [permissionKey.INTERACTION]: createInteractionPanel,
5134   - [permissionKey.DYNAMIC_EFFECT]: createDynamicEffectPanel,
5135   - [permissionKey.VAR_IMAGE]: createVarImagePanel,
5136   - [permissionKey.VIDEO]: createVideoBindPanel,
5137   - [permissionKey.SWITCH_STATE_SETTING]: createSwitchStateSettingPanel,
5138   - [permissionKey.ONLY_SINGLE_EVENT]: createParamsSettingButtonPanel,
5139   - [permissionKey.RUNNING_AND_STOP]: createRunningAndStopPanel
5140   - }
5141   -
5142   -
5143   - function permissionRender() {
5144   - try {
5145   - const cell = vertices[0]
5146   - const permission = graph.getAttributeForCell(cell, basicAttr.COMPONENT_TYPE)
5147   - const needDisplayPanel = sidebarInstance.getComponentPermission(permission)
5148   - for (const key of needDisplayPanel) {
5149   - renderMapping[key]()
5150   - }
5151   - if (needDisplayPanel.length) createSubmitPanel()
5152   - UseLayUi.nextTick(() => form.render())
5153   - } catch (e) {
5154   - throw Error('component permission setting has some problem, please check your component permission bind on "Sidebar.prototype.init" method setComponentPermission')
5155   - }
5156   - }
5157   -
5158   - permissionRender()
5159   - await getNodeBindInfo()
5160   - }
5161   -
5162   - initNode();
5163   -
5164   -
5165   - /**
5166   - * @description 获取节点绑定信息
5167   - */
5168   - async function getNodeBindInfo() {
5169   - const { id } = nodeInfo
5170   - const [err, res] = await to(ConfigurationNodeApi.getConfigurationInfo('NODE', id))
5171   - currentNodeData = res
5172   - if (echoRefreshFn && typeof echoRefreshFn === 'function') echoRefreshFn()
5173   - await echoActionType()
5174   - }
5175   -
5176   - /**
5177   - * @description 回显动效类型
5178   - */
5179   - async function echoActionType() {
5180   - const act = currentNodeData.act ?? []
5181   - const event = currentNodeData.event ?? []
5182   - const actionType = {}
5183   -
5184   - const hasExistEl = $(`.layui-form[lay-filter="${CONTAINER_FILTER}"]`).find('input[type="checkbox"]')
5185   - $(hasExistEl).each((i) => {
5186   - $(hasExistEl[i]).attr('disabled', true)
5187   - })
5188   -
5189   - for (const item of act) {
5190   - const flag = !item.condition || !item.condition?.length
5191   - $(`.interaction__container input[name="${item.type}"]`).attr('disabled', flag)
5192   - actionType[item.type] = item.enabled
5193   - }
5194   - for (const item of event) {
5195   - const flag = !item.content
5196   - $(`.interaction__container input[name="${item.type}"]`).attr('disabled', flag)
5197   - actionType[item.type] = item.enabled
5198   - }
5199   -
5200   - form.val(CONTAINER_FILTER, actionType)
5201   - }
5202   -
5203   - /**
5204   - * @description 生成操作节点
5205   - * @param {object[]} list
5206   - */
5207   - function generateActionEventNode(list) {
5208   - const eventList = []
5209   - const eventNodeCls = 'interaction__container'
5210   - for (const item of list) {
5211   - const checkbox = UseLayUi.createCheckBox({
5212   - dataSource: item,
5213   - layFilter: item.type,
5214   - valueField: 'type',
5215   - labelField: 'label',
5216   - })
5217   - const template = `
5218   - <div class="${eventNodeCls}">
5219   - <div>${checkbox}</div>
5220   - <i id="${item.type}"></i>
5221   - </div>`
5222   - eventList.push(template)
5223   - }
5224   - return eventList
5225   - }
5226   -
5227   - /**
5228   - * @description 创建数据面板
5229   - */
5230   - function createDataSourcePanel() {
5231   - const fragment = document.createDocumentFragment()
5232   - const defaultPanel = createPanel()
5233   - const title = createTitle('数据源')
5234   - $(defaultPanel).addClass('override__panel--default')
5235   - $(title).css({ padding: '6px 0 6px 6px' })
5236   -
5237   -
5238   - async function mount() {
5239   - const { component, echoDataSource, getValue } = generateDataSourceComponent({ validate: false })
5240   - $(fragment).append(title).append(component)
5241   - $(container).append(fragment)
5242   -
5243   - /**
5244   - * @description 回显数据
5245   - * @type {Function}
5246   - */
5247   - const refreshFn = echoRefreshFn
5248   - echoRefreshFn = function () {
5249   - refreshFn.apply(this)
5250   - const { dataSources: [dataSource] = [] } = currentNodeData || {}
5251   - echoDataSource(dataSource)
5252   - form.render(null, CONTAINER_FILTER)
5253   - }
5254   -
5255   - // 改写获取数据源绑定的值
5256   - getDataSourceBindValue = getValue
5257   - }
5258   -
5259   - mount()
5260   - }
5261   -
5262   - function createLineChartPanel() {
5263   - const { LINE_CHART } = Sidebar.prototype.enumComponentType
5264   - createChartBindPanel(true)
5265   - }
5266   -
5267   - function createBarChartPanel() {
5268   - const { LINE_CHART } = Sidebar.prototype.enumComponentType
5269   -
5270   - createChartBindPanel(false)
5271   - }
5272   -
5273   - function createDashboardPanel() {
5274   - const { LINE_CHART } = Sidebar.prototype.enumComponentType
5275   -
5276   - }
5277   - /**
5278   - * @description 创建视频绑定面板
5279   - */
5280   - function createVideoBindPanel() {
5281   -
5282   - const enumConst = {
5283   - ORG_ID: 'orgId',
5284   - RECORD_ID: 'id',
5285   - VIDEO_URL: 'videoUrl',
5286   - ACCESSMODE: 'accessMode',
5287   - VIDEO_FLAG: 'videoComponentFlag'
5288   - }
5289   -
5290   - const enumActionEL = {
5291   - VIDEO_FILTER: 'videoFilter',
5292   - PANEL_EL: 'videoPanelControl',
5293   - ORG_EL: 'orgTreeEl'
5294   - }
5295   -
5296   - const fragment = document.createDocumentFragment()
5297   - const title = createTitle('视频绑定')
5298   - $(title).addClass('override__title--default')
5299   -
5300   - const defaultPanel = createPanel()
5301   - $(defaultPanel).addClass('override__panel--default')
5302   - $(defaultPanel).append(`<div id="${enumActionEL.ORG_EL}" class="video-panel-org__override"></div>`)
5303   - $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.ACCESSMODE}" /></div>`)
5304   - $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.VIDEO_FLAG}" value="true" /></div>`)
5305   - $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.VIDEO_URL}" /></div>`)
5306   -
5307   - const videoBindSelect = UseLayUi.createSelect({
5308   - label: '视频流',
5309   - layFilter: enumActionEL.VIDEO_FILTER,
5310   - className: 'data-source__component-select',
5311   - bindValueFiled: enumConst.RECORD_ID
5312   - })
5313   - $(defaultPanel).append(`<div id="${enumActionEL.PANEL_EL}">${videoBindSelect}</div>`)
5314   -
5315   - fragment.append(title)
5316   - fragment.append(defaultPanel)
5317   - $(container).append(fragment)
5318   -
5319   - function init() {
5320   -
5321   - let orgId = null;
5322   -
5323   - let recordOptions = []
5324   -
5325   - let treeList = []
5326   -
5327   - const refreshFN = echoRefreshFn
5328   - echoRefreshFn = async function () {
5329   - refreshFN.apply(this, arguments)
5330   - await echoData()
5331   - }
5332   - async function echoData() {
5333   - const { videoUrl, orgId: organizationId, accessMode, id } = currentNodeData?.dataSources?.[0]?.additional || {}
5334   - orgId = organizationId
5335   - await getStreamingMediaByOrgId()
5336   - form.val(CONTAINER_FILTER, { videoUrl, accessMode, id })
5337   - UseLayUi.nextTick(() => {
5338   - const node = UseLayUi.findTreeObjectByField(treeList, organizationId)
5339   - $(`#${enumActionEL.ORG_EL} input[name="${enumConst.ORG_ID}"]`).val(organizationId).parent().find('span').html(node?.name)
5340   - })
5341   - }
5342   -
5343   -
5344   -
5345   - /**
5346   - * @description 创建组织树
5347   - */
5348   - async function createOrgTreeSelect() {
5349   - const [err, res] = await to(ConfigurationNodeApi.getOrgTree())
5350   - treeList = res
5351   - if (err) return
5352   - UseLayUi.createTreeSelect({
5353   - elem: `#${enumActionEL.ORG_EL}`,
5354   - layFilter: enumConst.ORG_ID,
5355   - label: '组织',
5356   - singleUsage: false,
5357   - layVerify: 'required',
5358   - layVerType: 'tips',
5359   - treeProps: {
5360   - data: res,
5361   - onlyIconControl: true,
5362   - click(node) {
5363   - orgId = node.data.id
5364   - getStreamingMediaByOrgId()
5365   - form.val(CONTAINER_FILTER, {
5366   - [enumConst.RECORD_ID]: null
5367   - })
5368   - },
5369   - },
5370   - })
5371   - }
5372   -
5373   - async function getStreamingMediaByOrgId() {
5374   - const [err, res] = await to(ConfigurationNodeApi.getStreamingMediaList(orgId))
5375   - recordOptions = res.items
5376   - const options = UseLayUi.generateOptionTemplate({ dataSource: res.items || [] })
5377   - $(`#${enumActionEL.PANEL_EL} select[name="${enumConst.RECORD_ID}"]`).html(options)
5378   - form.render()
5379   - }
5380   -
5381   - function createLinsten() {
5382   - form.on(`select(${enumActionEL.VIDEO_FILTER})`, event => {
5383   - const { value } = event
5384   - const item = recordOptions.find(item => item.id === value)
5385   - form.val(CONTAINER_FILTER, {
5386   - [enumConst.ACCESSMODE]: item[enumConst.ACCESSMODE],
5387   - [enumConst.VIDEO_URL]: item[enumConst.VIDEO_URL],
5388   - })
5389   - })
5390   - }
5391   -
5392   - createOrgTreeSelect()
5393   - createLinsten()
5394   - }
5395   -
5396   - init()
5397   - }
5398   -
5399   - /**
5400   - * @description 创建开关组件的状态设置面板
5401   - */
5402   - function createSwitchStateSettingPanel() {
5403   - dynamicEffectList.length = 0
5404   - dynamicEffectList.push({
5405   - label: '状态设置',
5406   - type: enumDynamicEffectType.SWITCH,
5407   - category: enumCategory.ACT,
5408   - })
5409   - createDynamicEffectPanel()
5410   - createParamsSettingButtonPanel()
5411   - }
5412   -
5413   - /**
5414   - * @description 参数设置按钮面板创建
5415   - */
5416   - function createParamsSettingButtonPanel() {
5417   - const singleClick = interactionList.find(item => item.type === enumInteractionType.SINGLE)
5418   - interactionList.length = 0
5419   - interactionList.push(singleClick)
5420   - createInteractionPanel()
5421   - }
5422   -
5423   - /**
5424   - * @description 水流动效
5425   - */
5426   - function createRunningAndStopPanel() {
5427   - dynamicEffectList.push({
5428   - label: '水流动效',
5429   - type: enumDynamicEffectType.RUNNING,
5430   - category: enumCategory.ACT
5431   - })
5432   - }
5433   -
5434   - /**
5435   - * @description 是否是折线图
5436   - * @param {boolean} isLineChart
5437   - */
5438   - function createChartBindPanel(chartType) {
5439   - const fragment = document.createDocumentFragment()
5440   - const chartBindContainer = document.createElement('div')
5441   - chartBindContainer.setAttribute('class', 'chart-panel__style')
5442   - chartBindContainer.style.padding = '10px'
5443   - const title = createTitle('展示类型')
5444   - $(title).addClass('override__title--default')
5445   -
5446   - const enumActionEL = {
5447   - SCOPE_FILTER: 'bindChartScopeFilter',
5448   -
5449   - INTERVAL_EL: 'bindChartIntervalSelect',
5450   -
5451   - UNIT_EL: 'bindChartUnit'
5452   - }
5453   - const { LINE_CHART, BAR_CHART, DASHBOARD_CHART } = Sidebar.prototype.enumComponentType
5454   -
5455   - const enumBindKey = HandleDataSource.enumConst
5456   - const enumDataType = HandleDataSource.enumDataBindType
5457   - const enumConst = {
5458   - DATA_TYPE: enumBindKey.DATA_TYPE,
5459   -
5460   - REAL: enumDataType.REAL,
5461   -
5462   - HISTORY: enumDataType.HISTORY,
5463   -
5464   - /**
5465   - * @description 范围
5466   - */
5467   - EFFECT_SCOPE: enumBindKey.EFFECT_SCOPE,
5468   -
5469   - /**
5470   - * @description 聚合
5471   - */
5472   - AGG: enumBindKey.AGG,
5473   -
5474   - /**
5475   - * @description 间隔
5476   - */
5477   - INTERVAL: enumBindKey.INTERVAL,
5478   -
5479   - /**
5480   - * @description 单位
5481   - */
5482   - UNIT: enumBindKey.UNIT
5483   - }
5484   -
5485   - const enumTimeUnit = {
5486   - SECOND: 'second',
5487   - MINUTE: 'MINUTE',
5488   - HOUR: 'HOUR',
5489   - DAY: 'DAY',
5490   - }
5491   -
5492   - const unitMapping = {
5493   - [enumTimeUnit.SECOND]: '秒',
5494   - [enumTimeUnit.MINUTE]: '分',
5495   - [enumTimeUnit.HOUR]: '小时',
5496   - [enumTimeUnit.DAY]: '天',
5497   - }
5498   -
5499   - const unitConversion = {
5500   - [enumTimeUnit.SECOND]: 1 * 1000,
5501   - [enumTimeUnit.MINUTE]: 1 * 60 * 1000,
5502   - [enumTimeUnit.HOUR]: 1 * 60 * 60 * 1000,
5503   - [enumTimeUnit.DAY]: 1 * 60 * 60 * 24 * 1000,
5504   - }
5505   -
5506   - const defaultIntervalOptions = [
5507   - {
5508   - id: 1,
5509   - unit: enumTimeUnit.SECOND,
5510   - linkage: [
5511   - { id: 1, unit: enumTimeUnit.SECOND }
5512   - ]
5513   - },
5514   - {
5515   - id: 5,
5516   - unit: enumTimeUnit.SECOND,
5517   - linkage: [
5518   - { id: 1, unit: enumTimeUnit.SECOND }
5519   - ]
5520   - },
5521   - {
5522   - id: 10,
5523   - unit: enumTimeUnit.SECOND,
5524   - linkage: [
5525   - { id: 1, unit: enumTimeUnit.SECOND }
5526   - ]
5527   - },
5528   - {
5529   - id: 15,
5530   - unit: enumTimeUnit.SECOND,
5531   - linkage: [
5532   - { id: 1, unit: enumTimeUnit.SECOND }
5533   - ]
5534   - },
5535   - {
5536   - id: 30,
5537   - unit: enumTimeUnit.SECOND,
5538   - linkage: [
5539   - { id: 1, unit: enumTimeUnit.SECOND }
5540   - ]
5541   - },
5542   - {
5543   - id: 1,
5544   - unit: enumTimeUnit.MINUTE,
5545   - linkage: [
5546   - { id: 1, unit: enumTimeUnit.SECOND },
5547   - { id: 5, unit: enumTimeUnit.SECOND },
5548   - ]
5549   - },
5550   - {
5551   - id: 2,
5552   - unit: enumTimeUnit.MINUTE,
5553   - linkage: [
5554   - { id: 1, unit: enumTimeUnit.SECOND },
5555   - { id: 5, unit: enumTimeUnit.SECOND },
5556   - { id: 10, unit: enumTimeUnit.SECOND },
5557   - { id: 15, unit: enumTimeUnit.SECOND },
5558   - ]
5559   - },
5560   - {
5561   - id: 5,
5562   - unit: enumTimeUnit.MINUTE,
5563   - linkage: [
5564   - { id: 1, unit: enumTimeUnit.SECOND },
5565   - { id: 5, unit: enumTimeUnit.SECOND },
5566   - { id: 10, unit: enumTimeUnit.SECOND },
5567   - { id: 15, unit: enumTimeUnit.SECOND },
5568   - { id: 30, unit: enumTimeUnit.SECOND },
5569   - ]
5570   - },
5571   - {
5572   - id: 10,
5573   - unit: enumTimeUnit.MINUTE,
5574   - linkage: [
5575   - { id: 5, unit: enumTimeUnit.SECOND },
5576   - { id: 10, unit: enumTimeUnit.SECOND },
5577   - { id: 15, unit: enumTimeUnit.SECOND },
5578   - { id: 30, unit: enumTimeUnit.SECOND },
5579   - { id: 1, unit: enumTimeUnit.MINUTE },
5580   - ]
5581   - },
5582   - {
5583   - id: 15,
5584   - unit: enumTimeUnit.MINUTE,
5585   - linkage: [
5586   - { id: 5, unit: enumTimeUnit.SECOND },
5587   - { id: 10, unit: enumTimeUnit.SECOND },
5588   - { id: 15, unit: enumTimeUnit.SECOND },
5589   - { id: 30, unit: enumTimeUnit.SECOND },
5590   - { id: 1, unit: enumTimeUnit.MINUTE },
5591   - { id: 2, unit: enumTimeUnit.MINUTE },
5592   - ]
5593   - },
5594   - {
5595   - id: 30,
5596   - unit: enumTimeUnit.MINUTE,
5597   - linkage: [
5598   - { id: 5, unit: enumTimeUnit.SECOND },
5599   - { id: 10, unit: enumTimeUnit.SECOND },
5600   - { id: 15, unit: enumTimeUnit.SECOND },
5601   - { id: 30, unit: enumTimeUnit.SECOND },
5602   - { id: 1, unit: enumTimeUnit.MINUTE },
5603   - { id: 2, unit: enumTimeUnit.MINUTE },
5604   - ]
5605   - },
5606   - {
5607   - id: 1,
5608   - unit: enumTimeUnit.HOUR,
5609   - linkage: [
5610   - { id: 10, unit: enumTimeUnit.SECOND },
5611   - { id: 15, unit: enumTimeUnit.SECOND },
5612   - { id: 30, unit: enumTimeUnit.SECOND },
5613   - { id: 1, unit: enumTimeUnit.MINUTE },
5614   - { id: 2, unit: enumTimeUnit.MINUTE },
5615   - { id: 5, unit: enumTimeUnit.MINUTE },
5616   - ]
5617   - },
5618   - {
5619   - id: 2,
5620   - unit: enumTimeUnit.HOUR,
5621   - linkage: [
5622   - { id: 15, unit: enumTimeUnit.SECOND },
5623   - { id: 30, unit: enumTimeUnit.SECOND },
5624   - { id: 1, unit: enumTimeUnit.MINUTE },
5625   - { id: 2, unit: enumTimeUnit.MINUTE },
5626   - { id: 5, unit: enumTimeUnit.MINUTE },
5627   - { id: 10, unit: enumTimeUnit.MINUTE },
5628   - { id: 15, unit: enumTimeUnit.MINUTE },
5629   - ]
5630   - },
5631   - {
5632   - id: 5,
5633   - unit: enumTimeUnit.HOUR,
5634   - linkage: [
5635   - { id: 1, unit: enumTimeUnit.MINUTE },
5636   - { id: 2, unit: enumTimeUnit.MINUTE },
5637   - { id: 5, unit: enumTimeUnit.MINUTE },
5638   - { id: 10, unit: enumTimeUnit.MINUTE },
5639   - { id: 15, unit: enumTimeUnit.MINUTE },
5640   - { id: 30, unit: enumTimeUnit.MINUTE },
5641   - ]
5642   - },
5643   - {
5644   - id: 10,
5645   - unit: enumTimeUnit.HOUR,
5646   - linkage: [
5647   - { id: 2, unit: enumTimeUnit.MINUTE },
5648   - { id: 5, unit: enumTimeUnit.MINUTE },
5649   - { id: 10, unit: enumTimeUnit.MINUTE },
5650   - { id: 15, unit: enumTimeUnit.MINUTE },
5651   - { id: 30, unit: enumTimeUnit.MINUTE },
5652   - { id: 1, unit: enumTimeUnit.HOUR },
5653   - ]
5654   - },
5655   - {
5656   - id: 12,
5657   - unit: enumTimeUnit.HOUR,
5658   - linkage: [
5659   - { id: 2, unit: enumTimeUnit.MINUTE },
5660   - { id: 5, unit: enumTimeUnit.MINUTE },
5661   - { id: 10, unit: enumTimeUnit.MINUTE },
5662   - { id: 15, unit: enumTimeUnit.MINUTE },
5663   - { id: 30, unit: enumTimeUnit.MINUTE },
5664   - { id: 1, unit: enumTimeUnit.HOUR },
5665   - ]
5666   - },
5667   - {
5668   - id: 1,
5669   - unit: enumTimeUnit.DAY,
5670   - linkage: [
5671   - { id: 5, unit: enumTimeUnit.MINUTE },
5672   - { id: 10, unit: enumTimeUnit.MINUTE },
5673   - { id: 15, unit: enumTimeUnit.MINUTE },
5674   - { id: 30, unit: enumTimeUnit.MINUTE },
5675   - { id: 1, unit: enumTimeUnit.HOUR },
5676   - { id: 2, unit: enumTimeUnit.HOUR },
5677   - ]
5678   - },
5679   - {
5680   - id: 7,
5681   - unit: enumTimeUnit.DAY,
5682   - linkage: [
5683   - { id: 30, unit: enumTimeUnit.MINUTE },
5684   - { id: 1, unit: enumTimeUnit.HOUR },
5685   - { id: 2, unit: enumTimeUnit.HOUR },
5686   - { id: 5, unit: enumTimeUnit.HOUR },
5687   - { id: 10, unit: enumTimeUnit.HOUR },
5688   - { id: 12, unit: enumTimeUnit.HOUR },
5689   - { id: 1, unit: enumTimeUnit.DAY },
5690   - ]
5691   - },
5692   - {
5693   - id: 30,
5694   - unit: enumTimeUnit.DAY,
5695   - linkage: [
5696   - { id: 2, unit: enumTimeUnit.HOUR },
5697   - { id: 5, unit: enumTimeUnit.HOUR },
5698   - { id: 10, unit: enumTimeUnit.HOUR },
5699   - { id: 12, unit: enumTimeUnit.HOUR },
5700   - { id: 1, unit: enumTimeUnit.DAY },
5701   - ]
5702   - },
5703   - ].map(item => {
5704   - return {
5705   - id: item.id * unitConversion[item.unit],
5706   - name: item.id + unitMapping[item.unit],
5707   - linkage: item.linkage.map(item => {
5708   - return {
5709   - id: item.id * unitConversion[item.unit],
5710   - name: item.id + unitMapping[item.unit],
5711   - }
5712   - })
5713   - }
5714   - })
5715   -
5716   - const aggergationOptions = [
5717   - { id: 'AVG', name: '平均值' },
5718   - { id: 'MIN', name: '最小值' },
5719   - { id: 'MAX', name: '最大值' },
5720   - { id: 'SUM', name: '求和' },
5721   - { id: 'COUNT', name: '计数' },
5722   - { id: 'NONE', name: '空' },
5723   - ]
5724   -
5725   - function generateDataType() {
5726   - const realOption = (checked) => `<input type="radio" name="${enumConst.DATA_TYPE}" value="${enumConst.REAL}" title="实时" ${checked ? 'checked' : ''}>`
5727   - const historyOption = (checked) => `<input type="radio" name="${enumConst.DATA_TYPE}" value="${enumConst.HISTORY}" title="历史" ${checked ? 'checked' : ''}>`
5728   -
5729   - if (chartType === LINE_CHART) {
5730   - return realOption() + historyOption(true)
5731   - } else if (chartType === BAR_CHART) {
5732   - return historyOption(true)
5733   - } else if (chartType === DASHBOARD_CHART) {
5734   - return realOption(true)
5735   - }
5736   - return realOption() + historyOption(true)
5737   - }
5738   -
5739   - function createSwitchBindTypeRadio() {
5740   - return `
5741   - <div class="layui-form-item">
5742   - <label class="layui-form-label">数据类型</label>
5743   - <div class="layui-input-block">
5744   - ${generateDataType()}
5745   - </div>
5746   - </div>`
5747   - }
5748   -
5749   - function createQueryScopeSelect() {
5750   - const template = UseLayUi.generateOptionTemplate({
5751   - dataSource: defaultIntervalOptions,
5752   - addPlaceholderOption: false
5753   - })
5754   - return `
5755   - <div class="layui-form-item">
5756   - <label class="layui-form-label">时间周期</label>
5757   - <div class="layui-input-block">
5758   - <select name="${enumConst.EFFECT_SCOPE}" lay-filter="${enumActionEL.SCOPE_FILTER}">
5759   - ${template}
5760   - </select>
5761   - </div>
5762   - </div>`
5763   - }
5764   -
5765   - function createAggregationSelect() {
5766   - const template = UseLayUi.generateOptionTemplate({
5767   - dataSource: aggergationOptions,
5768   - addPlaceholderOption: false
5769   - })
5770   - return `
5771   - <div class="layui-form-item">
5772   - <label class="layui-form-label">聚合方式</label>
5773   - <div class="layui-input-block">
5774   - <select name="${enumConst.AGG}">
5775   - ${template}
5776   - </select>
5777   - </div>
5778   - </div>`
5779   - }
5780   -
5781   - function createIntervalSelect() {
5782   - return `
5783   - <div class="layui-form-item">
5784   - <label class="layui-form-label">间隔时间</label>
5785   - <div class="layui-input-block">
5786   - <select id="${enumActionEL.INTERVAL_EL}" name="${enumConst.INTERVAL}" lay-filter="${enumConst.INTERVAL}">
5787   - <option value="1000">1</option>
5788   - </select>
5789   - </div>
5790   - </div>`
5791   - }
5792   -
5793   - function createUnitInput() {
5794   - return `
5795   - <div class="layui-form-item">
5796   - <label class="layui-form-label">单位</label>
5797   - <div class="layui-input-block" style="flex: 1;">
5798   - <input id="${enumActionEL.UNIT_EL}" class="layui-input" value="°C" name="${enumConst.UNIT}" lay-filter="${enumConst.UNIT}" />
5799   - </div>
5800   - </div>`
5801   - }
5802   -
5803   - function generatorEventlisten() {
5804   - form.on(`select(${enumActionEL.SCOPE_FILTER})`, event => {
5805   - const value = event.value || 0
5806   - linkageIntervalSelect(value)
5807   - })
5808   - }
5809   -
5810   - function linkageIntervalSelect(value) {
5811   - const options = defaultIntervalOptions.find(item => Number(item.id) === Number(value))?.linkage
5812   - const template = UseLayUi.generateOptionTemplate({
5813   - dataSource: options,
5814   - addPlaceholderOption: false
5815   - })
5816   - $(`#${enumActionEL.INTERVAL_EL}`).html(template)
5817   - form.render('select')
5818   - }
5819   -
5820   - /**
5821   - * @description 回显
5822   - */
5823   - function echoData() {
5824   - const { dataSources = [] } = currentNodeData
5825   - const { additional = {} } = dataSources[0] || {}
5826   - const { [enumBindKey.EFFECT_SCOPE]: effectScope = 1000 } = additional
5827   - linkageIntervalSelect(effectScope)
5828   - form.val(CONTAINER_FILTER, additional)
5829   - }
5830   -
5831   - const refresh = echoRefreshFn
5832   - echoRefreshFn = function () {
5833   - refresh.apply(this, arguments)
5834   - echoData()
5835   - }
5836   -
5837   - fragment.append(title)
5838   - $(chartBindContainer).append(createSwitchBindTypeRadio())
5839   - $(chartBindContainer).append(createQueryScopeSelect())
5840   - $(chartBindContainer).append(createAggregationSelect())
5841   - $(chartBindContainer).append(createIntervalSelect())
5842   - chartType === DASHBOARD_CHART && $(chartBindContainer).append(createUnitInput())
5843   - fragment.append(chartBindContainer)
5844   - $(container).append(fragment)
5845   - generatorEventlisten()
5846   - }
5847   -
5848   - /**
5849   - * @description 创建数据交互模块
5850   - */
5851   - function createInteractionPanel() {
5852   - const fragment = document.createDocumentFragment()
5853   - const title = createTitle('数据交互')
5854   - $(title).addClass('override__title--default')
5855   - fragment.append(title)
5856   - generateActionEventNode(interactionList).forEach(item => {
5857   - const panel = createPanel()
5858   - $(panel).addClass('override__panel--default').append(item)
5859   - $(fragment).append(panel)
5860   - })
5861   - $(container).append(fragment)
5862   - }
5863   -
5864   -
5865   - /**
5866   - * @description 创建动效面版
5867   - */
5868   - function createDynamicEffectPanel() {
5869   - const fragment = document.createDocumentFragment()
5870   - const title = createTitle('数据动效')
5871   - $(title).addClass('override__title--default')
5872   - fragment.append(title)
5873   - generateActionEventNode(dynamicEffectList).forEach(item => {
5874   - const panel = createPanel()
5875   - $(panel).addClass('override__panel--default').append(item)
5876   - $(fragment).append(panel)
5877   - })
5878   - $(container).append(fragment)
5879   - }
5880   -
5881   - /**
5882   - * @description 变量图片动效面板
5883   - */
5884   - function createVarImagePanel() {
5885   - dynamicEffectList.push({
5886   - label: '设置变量值图片',
5887   - type: enumDynamicEffectType.IMAGE,
5888   - category: enumCategory.ACT,
5889   - })
5890   - createDynamicEffectPanel()
5891   - }
5892   -
5893   - /**
5894   - * @description 创建提交按钮
5895   - */
5896   - function createSubmitPanel() {
5897   - const panel = createPanel()
5898   - $(panel).addClass('data-source__submit-panel').append(`<button type="button" lay-submit lay-filter="formDataSource" class="layui-btn">保存</button>`)
5899   - $(container).append(panel)
5900   - form.on('submit(formDataSource)', async function (data) {
5901   - if (!hasSavePermission()) {
5902   - UseLayUi.topErrorMsg('没有权限')
5903   - return
5904   - }
5905   - const { field } = data
5906   - const value = getValueOnSubmit(field)
5907   - await to(autoSaveGraphInfo())
5908   - const [err, res] = await to(ConfigurationNodeApi.updateNodeInfo(value))
5909   - if (err) return
5910   - UseLayUi.successMsg()
5911   - await getNodeBindInfo()
5912   - return false;
5913   - });
5914   - }
5915   -
5916   - function getValueOnSubmit(field) {
5917   - const basicAttr = sidebarInstance.enumCellBasicAttribute
5918   - const componentType = sidebarInstance.enumComponentType
5919   -
5920   - const renderMapping = {
5921   - [componentType.VAR_IMAGE]: getSubmitValue,
5922   - [componentType.CHARTS]: getSubmitValue,
5923   - [componentType.TITLE]: getSubmitValue,
5924   - [componentType.VARIABLE]: getSubmitValue,
5925   - [componentType.LINE]: getSubmitValue,
5926   - [componentType.REAL_TIME]: getSubmitValue,
5927   - [componentType.LINE_CHART]: getSubmitValue,
5928   - [componentType.BAR_CHART]: getSubmitValue,
5929   - [componentType.DASHBOARD_CHART]: getSubmitValue,
5930   - [componentType.DEFAULT]: getSubmitValue,
5931   - [componentType.VIDEO]: getVideoSubmitValue,
5932   - [componentType.SWITCH]: getSwitchSubmitValue,
5933   - [componentType.PARAMS_SETTING_BUTTON]: getSwitchSubmitValue,
5934   - [componentType.IMAGE]: getSubmitValue
5935   - }
5936   -
5937   - const cell = vertices[0]
5938   - const type = graph.getAttributeForCell(cell, basicAttr.COMPONENT_TYPE)
5939   - return renderMapping[type]?.(field) || {}
5940   -
5941   - function getSubmitValue(field) {
5942   - const ENABLED_FLAG = 'on'
5943   - const additionalKey = HandleDataSource.enumConst
5944   -
5945   - const value = {
5946   - configurationId,
5947   - contentId: currentPageId.id,
5948   - nodeId: graphId,
5949   - [enumCategory.ACT]: [],
5950   - [enumCategory.EVENT]: [],
5951   - [enumCategory.DATA_SOURCE]: {
5952   - [enumDataSourceConst.ORG_ID]: field[enumDataSourceConst.ORG_ID],
5953   - [enumDataSourceConst.DEVICE_ID]: field[enumDataSourceConst.DEVICE_ID],
5954   - [enumDataSourceConst.SLAVE_DEVICE_ID]: field[enumDataSourceConst.SLAVE_DEVICE_ID] ? field[enumDataSourceConst.SLAVE_DEVICE_ID] : '',
5955   - [enumDataSourceConst.ATTR]: field[enumDataSourceConst.ATTR],
5956   - [enumDataSourceConst.ADDITIONAL]: field[additionalKey.DATA_TYPE] ? {
5957   - [additionalKey.AGG]: field[additionalKey.AGG],
5958   - [additionalKey.DATA_TYPE]: field[additionalKey.DATA_TYPE],
5959   - [additionalKey.INTERVAL]: field[additionalKey.INTERVAL],
5960   - [additionalKey.EFFECT_SCOPE]: field[additionalKey.EFFECT_SCOPE],
5961   - ...(field[additionalKey.UNIT] ? { [additionalKey.UNIT]: field[additionalKey.UNIT] } : {})
5962   - } : null
5963   - },
5964   - }
5965   - const allType = [...interactionList, ...dynamicEffectList]
5966   - for (const item of allType) {
5967   - if (field[item.type] === ENABLED_FLAG) {
5968   - const enableItem = currentNodeData[item.category].find(each => each.type === item.type)
5969   - if (!enableItem) continue
5970   - value[item.category].push({
5971   - type: item.type,
5972   - enabled: true,
5973   - })
5974   - } else {
5975   - value[item.category].push({
5976   - type: item.type,
5977   - enabled: false,
5978   - })
5979   - }
5980   - }
5981   -
5982   - return value
5983   - }
5984   -
5985   - function getVideoSubmitValue() {
5986   - const value = {
5987   - configurationId,
5988   - contentId: currentPageId.id,
5989   - nodeId: graphId,
5990   - [enumCategory.DATA_SOURCE]: {
5991   - [enumDataSourceConst.ORG_ID]: 'b4dd6e2b-6e0f-413c-bf5a-70133bd571e8',
5992   - [enumDataSourceConst.DEVICE_ID]: '6d9043f0-f1f7-11ec-98ad-a9680487d1e0',
5993   - [enumDataSourceConst.ATTR]: 'attr',
5994   - [enumDataSourceConst.ADDITIONAL]: field
5995   - },
5996   - }
5997   - return value
5998   - }
5999   -
6000   - /**
6001   - * @description 处理开关组件的保存值
6002   - * @returns
6003   - */
6004   - function getSwitchSubmitValue(field) {
6005   - const dataSources = getDataSourceBindValue()
6006   - const enableStatus = getEnableStatus(field)
6007   - return { configurationId, contentId: currentPageId.id, nodeId: graphId, dataSources, ...enableStatus }
6008   - }
6009   -
6010   -
6011   - /**
6012   - * @description 获取开启状态
6013   - */
6014   - function getEnableStatus(field = {}) {
6015   - const ENABLED_FLAG = 'on'
6016   - const value = {}
6017   - const hasExistEl = $(`.layui-form[lay-filter="${CONTAINER_FILTER}"]`).find('input[type="checkbox"]')
6018   -
6019   - // 筛选页面中存在的数据动效事件交互复选框
6020   - const allState = []
6021   - $(hasExistEl).each((i) => {
6022   - const state = $(hasExistEl[i]).attr('name')
6023   - allState.push(state)
6024   - })
6025   - const allType = [...interactionList, ...dynamicEffectList].filter(item => allState.includes(item.type))
6026   -
6027   - for (const item of allType) {
6028   - !value[item.category] && (value[item.category] = [])
6029   - value[item.category].push({
6030   - type: item.type,
6031   - enabled: field[item.type] === ENABLED_FLAG,
6032   - })
6033   - }
6034   - return value
6035   - }
6036   - }
6037   -
6038   - /**
6039   - * @description 处理设置变量图片
6040   - */
6041   - function handleSettingVarImage(event) {
6042   -
6043   - const enumActionEl = {
6044   - /**
6045   - * @description layer 保存按钮
6046   - */
6047   - LAYER_SUBMIT_FILTER: 'varImageLayerFilter',
6048   -
6049   - /**
6050   - * @description 上传图片layer 按钮控制
6051   - */
6052   - IMAGE_LAYER_FILTER: 'uploadImageLayerFilter',
6053   -
6054   - /**
6055   - * @description 行控制
6056   - */
6057   - ROW_FILTER: 'varImageTableRowFilter',
6058   -
6059   - /**
6060   - * @description 颜色控制
6061   - */
6062   - COLOR_PICKER_FILTER: 'varImageTableColorPickerFilter',
6063   -
6064   - /**
6065   - * @description 最小值控制
6066   - */
6067   - MIN_FILTER: 'varImageTableMinFilter',
6068   -
6069   - /**
6070   - * @description 最大值控制
6071   - */
6072   - MAX_FILTER: 'varImageTableMaxFilter',
6073   -
6074   - /**
6075   - * @description 表体
6076   - */
6077   - TABLE_BODY_EL: 'variableImageTable',
6078   -
6079   - /**
6080   - * @description 添加行控制
6081   - */
6082   - ADD_ROW_EL: 'variableImageTableAddRow',
6083   -
6084   - /**
6085   - * @description 设置图片控制
6086   - */
6087   - SET_IMG_EL: 'variableImageTableSetImgEl',
6088   -
6089   - /**
6090   - * @description 预览区域控制
6091   - */
6092   - PREVIEW_IMG_CONTAINER: 'img__container',
6093   -
6094   - /**
6095   - * @description 删除图片控制
6096   - */
6097   - DEL_PREVIEW_IMG: 'img__delete',
6098   -
6099   - /**
6100   - * @description 删除行控制
6101   - */
6102   - DEL_ROW_EL: 'variableImageTableDelRow',
6103   -
6104   - /**
6105   - * @description
6106   - */
6107   - DATA_SOURCE_COMP_EL: 'varImgDataSourceEl',
6108   -
6109   - /**
6110   - * @description 默认图片
6111   - */
6112   - DEFAULT_IMAGE_EL: 'defaultImageEl',
6113   -
6114   - /**
6115   - * @description 行预览
6116   - */
6117   - ROW_PREVIEW_IMG: 'rowPreviewImg',
6118   -
6119   - /**
6120   - * @description 默认图片filter
6121   - */
6122   - DEFAULT_IMAGE_FILTER: 'defaultImageFilter'
6123   - }
6124   -
6125   - const enumConst = HandleDynamicEffect.enumVarImageConst
6126   -
6127   - let addRowNumber = 0
6128   -
6129   - let getDataSourceValue = () => {
6130   - }
6131   -
6132   - const getRowFilter = (rowNumber) => `${enumActionEl.ROW_FILTER}${rowNumber}`
6133   -
6134   - /**
6135   - * @description 监听表格中的事件
6136   - */
6137   - function generatorEventListen() {
6138   - createInputListener()
6139   - createAddRowEvent()
6140   - createDelRowEvent()
6141   - }
6142   -
6143   - /**
6144   - * @description 删除行
6145   - */
6146   - function createDelRowEvent() {
6147   - $(`#${enumActionEl.TABLE_BODY_EL}`).on('click', `.${enumActionEl.DEL_ROW_EL}`, (event) => {
6148   - $(event.target).parents('tr').remove()
6149   - })
6150   - }
6151   -
6152   - /**
6153   - * @description 添加行事件
6154   - */
6155   - function createAddRowEvent() {
6156   - $(`#${enumActionEl.ADD_ROW_EL}`).on('click', () => {
6157   - addRecord()
6158   - })
6159   - }
6160   -
6161   - /**
6162   - * @description 创建输入验证
6163   - */
6164   - function createInputListener() {
6165   - $(`#${enumActionEl.TABLE_BODY_EL}`)
6166   - .on('input', `.${enumActionEl.MIN_FILTER}`, event => {
6167   - const minVal = $(event.target).val()
6168   - const maxVal = $(event.target).parents('tr').find(`input.${enumActionEl.MAX_FILTER}`).val()
6169   - if (maxVal !== '' && Number(minVal) > Number(maxVal)) {
6170   - layer.tips('输入值大于最大值', $(event.target), {
6171   - tips: 1,
6172   - });
6173   - }
6174   - })
6175   - .on('input', `.${enumActionEl.MAX_FILTER}`, event => {
6176   - const maxVal = $(event.target).val()
6177   - const minVal = $(event.target).parents('tr').find(`input.${enumActionEl.MIN_FILTER}`).val()
6178   - if (minVal !== '' && Number(maxVal) < Number(minVal)) {
6179   - layer.tips('输入值小于最小值', $(event.target), {
6180   - tips: 1,
6181   - });
6182   - }
6183   - })
6184   - }
6185   -
6186   - /**
6187   - * @description 添加记录
6188   - */
6189   - function addRecord() {
6190   - const rowFormFilter = getRowFilter(addRowNumber)
6191   - const content = `
6192   - <tr class="layui-form" lay-filter="${rowFormFilter}">
6193   - <td>
6194   - <div class="layui-form-item">
6195   - <input class="layui-input ${enumActionEl.MIN_FILTER}" autocomplete="off" type="number" name="${enumConst.MIN}" lay-filter="${enumConst.MIN}" lay-verType="tips" lay-verify="required" />
6196   - </div>
6197   - </td>
6198   - <td>
6199   - <div class="layui-form-item">
6200   - <input class="layui-input ${enumActionEl.MAX_FILTER}"" autocomplete="off" type="number" name="${enumConst.MAX}" lay-filter="${enumConst.MAX}" lay-verType="tips" lay-verify="required" />
6201   - </div>
6202   - </td>
6203   - <td>
6204   - <div class="${enumActionEl.ROW_PREVIEW_IMG}"></div>
6205   - </td>
6206   - <td style="text-align: center">
6207   - <button type="button" class="layui-btn layui-btn-primary layui-border-red ${enumActionEl.DEL_ROW_EL}">删除</button>
6208   - </td>
6209   - </tr>
6210   - `
6211   - $(`#${enumActionEl.TABLE_BODY_EL}`).append(content)
6212   - form.render()
6213   - const el = $(`#${enumActionEl.TABLE_BODY_EL} tr[lay-filter="${rowFormFilter}"] .${enumActionEl.ROW_PREVIEW_IMG}`)
6214   - generateUploadImgContainer({ el })
6215   - addRowNumber++
6216   - }
6217   -
6218   -
6219   - /**
6220   - * @description 回显数据
6221   - */
6222   - function echoFormData(info) {
6223   - const { condition = [] } = info
6224   - for (let index = 0; index < condition.length; index++) {
6225   - const item = condition[index]
6226   - if (item[enumConst.DEFAULT_IMAGE_FLAG]) continue
6227   - addRecord()
6228   - const rowFilter = getRowFilter(index)
6229   - $(`#${enumActionEl.TABLE_BODY_EL}`).find(`tr[lay-filter="${rowFilter}"] .${enumActionEl.PREVIEW_IMG_CONTAINER}>img`).attr('src', item[enumConst.IMAGE_GALLERY_IMAGE_PATH])
6230   - form.val(rowFilter, { ...item })
6231   - }
6232   - }
6233   -
6234   - function echoDefaultImage(info) {
6235   - const { condition } = info
6236   - const data = condition.find(item => item[enumConst.DEFAULT_IMAGE_FLAG])
6237   - if (data) {
6238   - $(`#${enumActionEl.DEFAULT_IMAGE_EL}`).find(`.${enumActionEl.PREVIEW_IMG_CONTAINER}>img`).attr('src', data[enumConst.IMAGE_GALLERY_IMAGE_PATH])
6239   - form.val(enumActionEl.DEFAULT_IMAGE_FILTER, { ...data })
6240   - }
6241   - }
6242   -
6243   - /**
6244   - * @description 验证最大最小值
6245   - * @param tableData
6246   - * @returns {boolean}
6247   - */
6248   - function validate(tableData) {
6249   - let validateFlag = true
6250   - for (let i = 0; i < tableData.length; i++) {
6251   - const { min, max } = tableData[i]
6252   - if (Number(min) > Number(max)) {
6253   - validateFlag = false
6254   - layer.tips('输入值大于最大值', $(`#${enumActionEl.TABLE_BODY_EL} tr`).eq(i).find(`input[name="${enumConst.MIN}"]`))
6255   - break
6256   - } else if (Number(max) < Number(min)) {
6257   - validateFlag = false
6258   - layer.tips('输入值小于最小值', $(`#${enumActionEl.TABLE_BODY_EL} tr`).eq(i).find(`input[name="${enumConst.MAX}"]`))
6259   - break
6260   - }
6261   - }
6262   - return validateFlag
6263   - }
6264   -
6265   - /**
6266   - * @description
6267   - */
6268   - async function submit(callback) {
6269   - if (!hasPermission()) return
6270   - const data = Array.from({ length: addRowNumber }).map((_, row) => form.val(getRowFilter(row))).filter(item => Object.keys(item).length)
6271   - const defaultImageConfig = form.val(enumActionEl.DEFAULT_IMAGE_FILTER)
6272   - defaultImageConfig[enumConst.DEFAULT_IMAGE_FLAG] = true
6273   - data.push(defaultImageConfig)
6274   - if (!validate(data)) return
6275   - const formVal = getDataSourceValue()
6276   - const formModel = {
6277   - configurationId,
6278   - contentId: currentPageId.id,
6279   - ...formVal,
6280   - id: graphId,
6281   - condition: data,
6282   - type: event.data.type,
6283   - }
6284   - await to(autoSaveGraphInfo())
6285   - const [err, res] = await to(ConfigurationNodeApi.updateNodeAct(formModel))
6286   - if (err) return
6287   - UseLayUi.successMsg()
6288   - callback()
6289   - }
6290   -
6291   - function createLayerForm(type) {
6292   - const content = `
6293   - <div class="layui-form" lay-filter="${enumActionEl.DEFAULT_IMAGE_FILTER}" style="display: flex; align-items: center; padding-top: 10px;">
6294   - <div style="width: 60px; padding: 9px 10px 9px 20px;">默认图片</div>
6295   - <div id="${enumActionEl.DEFAULT_IMAGE_EL}" style="padding: 0;"></div>
6296   - </div>
6297   - <div style="width: 300px; padding: 0 0 0 20px;" id="${enumActionEl.DATA_SOURCE_COMP_EL}"></div>
6298   - <div class="override__table" style="padding: 0 20px">
6299   - <table class="layui-table" >
6300   - <thead>
6301   - <tr>
6302   - <th style="text-align:center">最小值(>=)</th>
6303   - <th style="text-align:center">最大值(<=)</th>
6304   - <th style="text-align:center">对应图片</th>
6305   - <th style="text-align:center">操作</th>
6306   - </tr>
6307   - </thead>
6308   - <tbody id="${enumActionEl.TABLE_BODY_EL}"></tbody>
6309   - </table>
6310   - </div>
6311   - <div style="display:flex;justify-content:center;">
6312   - <button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="${enumActionEl.ADD_ROW_EL}">添加一条</button>
6313   - </div>
6314   - `
6315   -
6316   - layer.open({
6317   - title: '变量值图片功能',
6318   - type: 1,
6319   - content,
6320   - skin: 'event-layer__override',
6321   - area: '700px',
6322   - btn: ["保存", "取消"],
6323   - shade: ["0.7", "#fafafa"],
6324   - offset: '100px',
6325   - yes(index) {
6326   - form.on(`submit(${enumActionEl.LAYER_SUBMIT_FILTER})`, data => {
6327   - submit(() => {
6328   - layer.close(index)
6329   - getNodeBindInfo()
6330   - })
6331   - })
6332   - },
6333   - but2(index, layero) {
6334   - return false
6335   - },
6336   - async success(layero, index) {
6337   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
6338   - 'lay-submit': '',
6339   - 'lay-filter': enumActionEl.LAYER_SUBMIT_FILTER,
6340   - })
6341   - const { component, echoDataSource, getValue } = generateDataSourceComponent()
6342   - getDataSourceValue = getValue
6343   -
6344   - const el = $(`#${enumActionEl.DEFAULT_IMAGE_EL}`)
6345   - generateUploadImgContainer({ el })
6346   -
6347   - $(`#${enumActionEl.DATA_SOURCE_COMP_EL}`).append(component)
6348   - form.render()
6349   - const info = getLayerBindInfo('act', type)
6350   - const { condition = [] } = info
6351   - if (!condition.length) {
6352   - addRecord()
6353   - } else {
6354   - echoDataSource(info)
6355   - echoFormData(info)
6356   - echoDefaultImage(info)
6357   - }
6358   - generatorEventListen()
6359   - },
6360   - })
6361   - }
6362   -
6363   - createLayerForm(event.data.type)
6364   - }
6365   -
6366   - /**
6367   - * @description 处理数据交互 - down || up 按下与抬起
6368   - */
6369   - function handleDownOrUpEvent(event) {
6370   -
6371   - // 事件类型
6372   - const enumEventType = {
6373   - DOWN: "按下",
6374   - UP: "抬起",
6375   - SINGLE: "单击",
6376   - DOUBLE: "双击",
6377   - };
6378   -
6379   - const enumActionEl = {
6380   -
6381   - /**
6382   - * @description 表单控制 filter
6383   - */
6384   - FORM_FILTER: 'interactionFormFilter',
6385   -
6386   - /**
6387   - * @description 表体节点
6388   - */
6389   - DEVICE_DATA_BODY_EL: 'deviceDataTbody',
6390   -
6391   - /**
6392   - * @description 删除行节点
6393   - */
6394   - DEL_ROW_EL: 'deleteRow',
6395   -
6396   - /**
6397   - * @description 增加行节点
6398   - */
6399   - ADD_ROW_EL: 'addRow',
6400   -
6401   - /**
6402   - * @descripton
6403   - */
6404   - ROW_FILTER: 'interactionRowFilter',
6405   -
6406   - /**
6407   - * @description json editor
6408   - */
6409   - EDITOR_JSON: 'editor__json-',
6410   -
6411   - /**
6412   - * @description 弹出层保存 filter
6413   - */
6414   - LAYER_SUBMIT_FILTER: 'interactionLayerSubmit',
6415   -
6416   - /**
6417   - * @description ace builder
6418   - */
6419   - JSON: 'ace__builder-json',
6420   -
6421   - /**
6422   - * @description 组织树节点
6423   - */
6424   - ORG_EL: 'interactionOrgTree',
6425   - }
6426   -
6427   -
6428   - /**
6429   - * @description 所有设备选项
6430   - * @type {{id: string, name: string, deviceType: string}[]}
6431   - */
6432   - let allDeviceOptions = []
6433   -
6434   - let addRowNumber = 0
6435   -
6436   - /**
6437   - * @description 组织id
6438   - * @type {null}
6439   - */
6440   - let orgId = null
6441   -
6442   - const recordData = {
6443   - orgId: null,
6444   - enabled: false
6445   - }
6446   -
6447   - const getRowFilter = (rowNumber) => `${enumActionEl.ROW_FILTER}${rowNumber}`
6448   -
6449   - /**
6450   - * @description 枚举常量
6451   - * @enum DEVICE
6452   - */
6453   - const enumConst = {
6454   - /**
6455   - * @description 设备
6456   - */
6457   - DEVICE: 'deviceId',
6458   - /**
6459   - * @description 子设备
6460   - */
6461   - SLAVE_DEVICE: 'slaveDeviceId',
6462   - /**
6463   - * @description 变量
6464   - */
6465   - ATTR: 'attr',
6466   - /**
6467   - * @description 下发值
6468   - */
6469   - VALUE: 'value',
6470   -
6471   - /**
6472   - * @description 方式
6473   - */
6474   - WAY: 'way',
6475   -
6476   - /**
6477   - * @description 组织id
6478   - */
6479   - ORG_ID: 'orgId',
6480   - }
6481   -
6482   - const sendInstructionWay = {
6483   - ONE_WAY: 'oneway',
6484   - TWO_WAY: 'twoway',
6485   - }
6486   -
6487   - /**
6488   - * @description 创建回显数据 查询出所有网关设备和直连设备
6489   - */
6490   - async function getAllGatewayDeviceAndConnectionDevice() {
6491   - if (!recordData.orgId) return
6492   - const [err, res] = await to(ConfigurationNodeApi.getAllGatewayDeviceAndConnectionDevice(recordData.orgId))
6493   - allDeviceOptions = res
6494   - mountAllDeviceToSelect()
6495   - }
6496   -
6497   - /**
6498   - * @description 将设备选项挂载到节点中
6499   - */
6500   - function mountAllDeviceToSelect() {
6501   - const generateOption = UseLayUi.generateOptionTemplate({ dataSource: allDeviceOptions })
6502   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL}`).find(`select[name="${enumConst.DEVICE}"]`).html(generateOption)
6503   - UseLayUi.nextTick(() => form.render('select'))
6504   - }
6505   -
6506   - /**
6507   - * @description 创建JSON编辑器
6508   - * @param el
6509   - * @param datum
6510   - */
6511   - function createEditor(el, datum = {}) {
6512   - const editor = ace.edit(el, {
6513   - maxLines: 10, // 最大行数,超过会自动出现滚动条
6514   - minLines: 5, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
6515   - fontSize: 14, // 编辑器内字体大小
6516   - tabSize: 2, // 制表符设置为 4 个空格大小
6517   - });
6518   - editor.session.setMode("ace/mode/json");
6519   - editor.getSession().on('change', (event, editor) => {
6520   - $(`#${el}`).parent().find(`textarea[name="${enumConst.VALUE}"]`).val(editor.getValue())
6521   - })
6522   - editor.setValue(datum[enumConst.VALUE] ? datum[enumConst.VALUE] : "{}")
6523   - }
6524   -
6525   - /**
6526   - * @description 创建组织树
6527   - */
6528   - async function createOrgTreeSelect() {
6529   - const [err, res] = await to(ConfigurationNodeApi.getOrgTree())
6530   - treeList = res
6531   - if (err) return
6532   - UseLayUi.createTreeSelect({
6533   - elem: `#${enumActionEl.ORG_EL}`,
6534   - layFilter: enumConst.ORG_ID,
6535   - label: '组织',
6536   - singleUsage: false,
6537   - layVerify: 'required',
6538   - layVerType: 'tips',
6539   - treeProps: {
6540   - data: res,
6541   - onlyIconControl: true,
6542   - click(node) {
6543   - recordData.orgId = node.data.id
6544   - getAllGatewayDeviceAndConnectionDevice()
6545   - },
6546   - },
6547   - })
6548   - }
6549   -
6550   -
6551   -
6552   - /**
6553   - * @description 添加行
6554   - * @param datum
6555   - */
6556   - function addRecord(datum) {
6557   - const content = `
6558   - <tr class="layui-form" lay-filter="${getRowFilter(addRowNumber)}">
6559   - <td>
6560   - <select name="${enumConst.DEVICE}" lay-filter="${enumConst.DEVICE}" lay-verType="tips" lay-verify="required"></select>
6561   - </td>
6562   - <td>
6563   - <form action="" style="display: flex">
6564   - <div class="override__radio-default">
6565   - <input id="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAY}" type="radio" name="${enumConst.WAY}" lay-ignore value="${sendInstructionWay.ONE_WAY}" title="单向" checked="">
6566   - <label for="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAY}" class="override__radio-label">单向</label>
6567   - </div>
6568   - <div class="override__radio-default">
6569   - <input id="${getRowFilter(addRowNumber)}${sendInstructionWay.TWO_WAY}" type="radio" name="${enumConst.WAY}" lay-ignore value="${sendInstructionWay.TWO_WAY}" title="双向">
6570   - <label for="${getRowFilter(addRowNumber)}${sendInstructionWay.TWO_WAY}" class="override__radio-label">双向</label>
6571   - </div>
6572   - </form>
6573   - </td>
6574   - <td class="${enumActionEl.JSON}">
6575   - <div style="width: 100%;height: 100%;">
6576   - <div id="${enumActionEl.EDITOR_JSON}${addRowNumber}"></div>
6577   - <textarea style="display: none" name="${enumConst.VALUE}" placeholder="请输入命令" lay-verType="tips" class="layui-textarea"></textarea>
6578   - </div>
6579   - </td>
6580   - <td>
6581   - <button type="button" class="layui-btn layui-btn-primary layui-border-red ${enumActionEl.DEL_ROW_EL}">删除</button>
6582   - </td>
6583   - </tr>
6584   - `
6585   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL}`).append(content)
6586   - setDeviceOptions(addRowNumber)
6587   - createEditor(`${enumActionEl.EDITOR_JSON}${addRowNumber}`, datum)
6588   - form.render('select', getRowFilter(addRowNumber))
6589   - addRowNumber++
6590   - }
6591   -
6592   -
6593   - /**
6594   - * @description 删除行
6595   - */
6596   - function createDeleteRowListenEvent() {
6597   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL}`).on('click', `.${enumActionEl.DEL_ROW_EL}`, (event) => {
6598   - // $(event.target).parents('tr').find('editor')
6599   - $(event.target).parents('tr').remove()
6600   - })
6601   - }
6602   -
6603   - /**
6604   - * @description 新增行
6605   - */
6606   - function createAddRowListenEvent() {
6607   - $(`#${enumActionEl.ADD_ROW_EL}`).on('click', () => {
6608   - addRecord()
6609   - const generateOption = UseLayUi.generateOptionTemplate({ dataSource: allDeviceOptions })
6610   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL} tr`).last().find(`select[name="${enumConst.DEVICE}"]`).html(generateOption)
6611   - form.render('select')
6612   - })
6613   - }
6614   -
6615   - /**
6616   - * @description 设置设备选项
6617   - */
6618   - function setDeviceOptions(row) {
6619   - const generateOption = UseLayUi.generateOptionTemplate({ dataSource: allDeviceOptions })
6620   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL} tr[lay-filter="${getRowFilter(row)}"]`).find(`select[name="${enumConst.DEVICE}"]`).html(generateOption)
6621   - }
6622   -
6623   - /**
6624   - * @description 下拉选项挂载
6625   - */
6626   - function createSelectOptionMountEvent() {
6627   - $(`#${enumActionEl.DEVICE_DATA_BODY_EL}`).on('click', '.layui-form-select', event => {
6628   - const width = event.currentTarget.offsetWidth || 200
6629   - const height = event.currentTarget.offsetHeight || 38
6630   - const offset = $(event.currentTarget).offset()
6631   - $(event.currentTarget).find('dl').css({
6632   - position: 'fixed',
6633   - 'min-width': width + 'px',
6634   - top: offset.top + height + 'px',
6635   - left: offset.left + 'px'
6636   - })
6637   - })
6638   - }
6639   -
6640   - /**
6641   - * @description 生成事件监听
6642   - */
6643   - function generatorEventListen() {
6644   - createDeleteRowListenEvent()
6645   - createAddRowListenEvent()
6646   - createSelectOptionMountEvent()
6647   - }
6648   -
6649   - /**
6650   - * @description 回显表单数据
6651   - */
6652   - function echoFormData(info) {
6653   - const { content: { data = [] } = {} } = info
6654   - data.forEach((datum, index) => {
6655   - addRecord(datum)
6656   - form.val(getRowFilter(index), datum)
6657   - })
6658   - }
6659   -
6660   - /**
6661   - * @description 回显组织树
6662   - */
6663   - function echoOrgTree(id) {
6664   - recordData.orgId = id
6665   - const node = UseLayUi.findTreeObjectByField(treeList, id)
6666   - UseLayUi.nextTick(() => {
6667   - $(`#${enumActionEl.ORG_EL} input[name="${enumConst.ORG_ID}"]`).val(recordData.orgId).parent().find('span').html(node?.name)
6668   - })
6669   - }
6670   -
6671   - /**
6672   - * @description 判断是否为正确的JSON结构
6673   - * @param {string} string
6674   - * @returns
6675   - */
6676   - function isJson(string) {
6677   - if (typeof string === 'string') {
6678   - try {
6679   - const obj = JSON.parse(string)
6680   - if (typeof obj === 'object' && obj !== null) {
6681   - return true
6682   - }
6683   - } catch (e) {
6684   - return false
6685   - }
6686   - }
6687   - return false
6688   - }
6689   -
6690   - /**
6691   - * @description 表单验证
6692   - * @param tableData
6693   - * @returns {boolean}
6694   - */
6695   - function validate(tableData) {
6696   - let validateFlag = true
6697   -
6698   - const formModel = form.val(enumActionEl.FORM_FILTER)
6699   - if (!formModel[enumConst.ORG_ID]) return false
6700   -
6701   - for (let i = 0; i < tableData.length; i++) {
6702   - const { value } = tableData[i]
6703   - if (!isJson(value)) {
6704   - validateFlag = false
6705   - layer.tips('下发值不正确', $(`#${enumActionEl.DEVICE_DATA_BODY_EL} tr`).eq(i).find(`td.${enumActionEl.JSON}`), { tips: 1 })
6706   - break
6707   - }
6708   - }
6709   - return validateFlag
6710   - }
6711   -
6712   -
6713   -
6714   - /**
6715   - * @description 保存
6716   - */
6717   - async function submit(callback) {
6718   - if (!hasPermission()) return
6719   - const data = Array.from({ length: addRowNumber }).map((_, row) => form.val(getRowFilter(row))).filter(item => Object.keys(item).length)
6720   - if (!validate(data)) return
6721   - const formModal = {
6722   - ...recordData,
6723   - configurationId,
6724   - // orgId,
6725   - contentId: currentPageId.id,
6726   - id: graphId,
6727   - content: {
6728   - data,
6729   - },
6730   - type: event.data.type,
6731   - };
6732   - await to(autoSaveGraphInfo())
6733   - const [err, res] = await to(ConfigurationNodeApi.updateNodeEvent(formModal))
6734   - if (err) return
6735   - UseLayUi.successMsg()
6736   - callback()
6737   - }
6738   -
6739   - /**
6740   - * @description 创建弹出层表单
6741   - * @param event
6742   - */
6743   - function createLayerForm(type) {
6744   - const content = `
6745   - <form class="layui-form" lay-filter="${enumActionEl.FORM_FILTER}">
6746   - <div style="width:400px">
6747   - <div class="layui-form-item">
6748   - <label class="layui-form-label">事件</label>
6749   - <div class="layui-input-block">
6750   - <input type="text" name="event" class="layui-input" value="${enumEventType[type]}" disabled>
6751   - </div>
6752   - </div>
6753   - <div class="layui-form-item">
6754   - <label class="layui-form-label">动作</label>
6755   - <div class="layui-input-block">
6756   - <select name="action" lay-verify="required">
6757   - <option value="0" selected>给变量赋值</option>
6758   - </select>
6759   - </div>
6760   - </div>
6761   - <div class="layui-form-item">
6762   - <label class="layui-form-label">类型</label>
6763   - <div class="layui-input-block">
6764   - <input type="radio" name="type" value="1" title="联网设备" checked>
6765   - <input type="radio" name="type" value="2" title="产品/场景" disabled>
6766   - </div>
6767   - </div>
6768   - <div id="${enumActionEl.ORG_EL}"></div>
6769   - </div>
6770   - </form>
6771   - <div class="override__table">
6772   - <table class="layui-table" >
6773   - <thead>
6774   - <tr>
6775   - <th style="text-align:center">选择设备</th>
6776   - <th style="text-align:center">单向 / 双向</th>
6777   - <th style="text-align:center">下发值</th>
6778   - <th style="text-align:center">操作</th>
6779   - </tr>
6780   - </thead>
6781   - <tbody id="${enumActionEl.DEVICE_DATA_BODY_EL}"></tbody>
6782   - </table>
6783   - <div style="display:flex;justify-content:center;">
6784   - <button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="${enumActionEl.ADD_ROW_EL}">添加一条</button>
6785   - </div>
6786   - </div>`
6787   -
6788   - layer.open({
6789   - title: '创建交互',
6790   - content,
6791   - skin: 'event-layer__override',
6792   - // area: ["1100px", "700px"],
6793   - area: '1100px',
6794   - offset: '100px',
6795   - btn: ["保存", "取消"],
6796   - shade: ["0.7", "#fafafa"],
6797   - yes(index) {
6798   - form.on(`submit(${enumActionEl.LAYER_SUBMIT_FILTER})`, data => {
6799   - submit(() => {
6800   - layer.close(index)
6801   - getNodeBindInfo()
6802   - })
6803   - })
6804   - },
6805   - but2(index, layero) {
6806   - return false
6807   - },
6808   - async success(layero, index) {
6809   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
6810   - 'lay-submit': '',
6811   - 'lay-filter': enumActionEl.LAYER_SUBMIT_FILTER,
6812   - })
6813   - await createOrgTreeSelect()
6814   - const info = getLayerBindInfo('event', type)
6815   - const { content: { data = [] } = {}, orgId, enabled } = info
6816   - Object.assign(recordData, { orgId, enabled })
6817   - await getAllGatewayDeviceAndConnectionDevice()
6818   - if (!info || !data.length) {
6819   - addRecord()
6820   - } else {
6821   - echoFormData(info)
6822   - }
6823   - generatorEventListen()
6824   - form.render()
6825   - echoOrgTree(orgId)
6826   - },
6827   - })
6828   - }
6829   -
6830   - createLayerForm(event.data.type)
6831   - }
6832   -
6833   - /**
6834   - * @description 处理单击 or 双击事件
6835   - */
6836   - function handleClickOrDbClick(event) {
6837   - const basicAttr = sidebarInstance.enumCellBasicAttribute
6838   - const componentType = sidebarInstance.enumComponentType
6839   - const currentNodeType = nodeInfo.getAttribute(basicAttr.COMPONENT_TYPE)
6840   - const isControlComponent = [componentType.SWITCH, componentType.PARAMS_SETTING_BUTTON].includes(currentNodeType)
6841   -
6842   - const enumEventType = {
6843   - DOWN: "按下",
6844   - UP: "抬起",
6845   - SINGLE: "单击",
6846   - DOUBLE: "双击",
6847   - };
6848   -
6849   - /**
6850   - * @description
6851   - */
6852   - const enumConst = {
6853   - EVENT: 'event',
6854   - ACTION: 'actionType',
6855   - PAGE_VALUE: 'pageValue',
6856   - LINK_VALUE: 'linkValue',
6857   -
6858   - /**
6859   - * @description 下发指令
6860   - */
6861   - COMMAND: 'command',
6862   -
6863   - /**
6864   - * @description 属性占位符
6865   - */
6866   - ATTR_PLACEHOLDER: 'attrPlaceholder',
6867   -
6868   - WAY: 'way'
6869   - }
6870   -
6871   - /**
6872   - * @description 动作类型
6873   - */
6874   - const enumActionType = DispatchCenter.enumPageType
6875   -
6876   - const enumGetValue = {
6877   - [enumActionType.PAGE]: enumConst.PAGE_VALUE,
6878   - [enumActionType.LINK]: enumConst.LINK_VALUE,
6879   - }
6880   -
6881   - const enumWayType = {
6882   - ONE_WAY: 'oneway',
6883   - TWO_WAY: 'twoway'
6884   - }
6885   -
6886   - const enumActionEl = {
6887   - /**
6888   - * @description 表单 lay-filter
6889   - */
6890   - FORM_FILTER: 'formModelFilter',
6891   -
6892   - /**
6893   - * @description 动作 lay-filter
6894   - */
6895   - ACTION_SELECT_FILTER: 'actionSelectFilter',
6896   -
6897   - /**
6898   - * @description 链接 ID
6899   - */
6900   - LINK_EL_ID: 'staticlinkPage',
6901   -
6902   - /**
6903   - * @description 页面 ID
6904   - */
6905   - PAGE_EL_ID: 'dynamicInputPage',
6906   -
6907   - /**
6908   - * @description layer submit filter
6909   - */
6910   - LAYER_SUBMIT_FILTER: 'dynamicLinkLayerFilter',
6911   -
6912   - /**
6913   - * @description JSON 编辑器容器
6914   - */
6915   - EDITOR_CONTAINER: 'editorContainerEL',
6916   -
6917   - /**
6918   - * @description JSON 编辑器
6919   - */
6920   - EDITOR: 'EDITOR',
6921   -
6922   - WAY_SELECT: 'dynamicWaySelectEl'
6923   - }
6924   -
6925   - /**
6926   - * @description
6927   - */
6928   - const recordData = {
6929   - enabled: false
6930   - }
6931   -
6932   - /**
6933   - * @description 回显数据
6934   - */
6935   - function echoFormData(data) {
6936   - const { content = {} } = data
6937   - const val = {
6938   - [enumConst.ACTION]: content.type,
6939   - [enumGetValue[content.type]]: content.value,
6940   - [enumConst.WAY]: content[enumConst.WAY]
6941   - }
6942   - controlFormDisplay(content.type)
6943   - form.val(enumActionEl.FORM_FILTER, val)
6944   - }
6945   -
6946   - /**
6947   - * @description 控制form
6948   - * @param {enumActionType} value
6949   - */
6950   - function controlFormDisplay(value) {
6951   - if (value === enumActionType.PAGE) {
6952   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
6953   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'block' })
6954   - $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'none' })
6955   - $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'none' })
6956   - } else if (value === enumActionType.LINK) {
6957   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
6958   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'block' })
6959   - $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'none' })
6960   - $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'none' })
6961   - } else if (value === enumActionType.PARAMS_SETTING) {
6962   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
6963   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
6964   - $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'flex' })
6965   - $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'block' })
6966   - }
6967   - }
6968   -
6969   - /**
6970   - * @description 编辑数据交互
6971   - */
6972   - async function submit(callback) {
6973   - if (!hasPermission()) return
6974   - const formVal = form.val(enumActionEl.FORM_FILTER)
6975   - const isParamsSetting = formVal[enumConst.ACTION] === enumActionType.PARAMS_SETTING
6976   - const { COMPONENT_TYPE } = Sidebar.prototype.enumCellBasicAttribute
6977   - const { SWITCH } = Sidebar.prototype.enumComponentType
6978   - const isSwitchComponent = vertices[0].getAttribute(COMPONENT_TYPE) === SWITCH
6979   -
6980   - if (isParamsSetting && isSwitchComponent && (!currentNodeData.act || !currentNodeData.act.find(item => item.type === enumDynamicEffectType.SWITCH))) {
6981   - UseLayUi.topErrorMsg('请先配置数据动效中的状态设置')
6982   - return
6983   - }
6984   -
6985   - if (isParamsSetting) {
6986   - if (!isJson(formVal[enumConst.COMMAND])) {
6987   - UseLayUi.topErrorMsg('命令配置存在错误')
6988   - return
6989   - }
6990   - }
6991   -
6992   - const data = {
6993   - type: event.data.type,
6994   - configurationId,
6995   - contentId: currentPageId.id,
6996   - id: graphId,
6997   - orgId: 'b4dd6e2b-6e0f-413c-bf5a-70133bd571e8',
6998   - ...recordData,
6999   - content: {
7000   - type: formVal[enumConst.ACTION],
7001   - value: formVal[enumGetValue[formVal[enumConst.ACTION]]],
7002   - ...(isParamsSetting ? {
7003   - [enumConst.COMMAND]: formVal[enumConst.COMMAND],
7004   - [enumConst.WAY]: formVal[enumConst.WAY]
7005   - } : {}),
7006   - },
7007   - }
7008   - await to(autoSaveGraphInfo())
7009   - const [err, res] = await to(ConfigurationNodeApi.updateNodeEvent(data))
7010   - if (err) return
7011   - isControlComponent && overrideCurrentData('event', 'type', res)
7012   - isControlComponent && echoActionType()
7013   - UseLayUi.successMsg()
7014   - callback()
7015   - }
7016   -
7017   - /**
7018   - * @description 生成 动作选项
7019   - */
7020   - function generatorActionOptions() {
7021   - const options = [
7022   - { name: '打开链接', id: enumActionType.LINK },
7023   - { name: '打开页面', id: enumActionType.PAGE },
7024   - ...(isControlComponent ? [{ name: '参数设置', id: enumActionType.PARAMS_SETTING }] : []),
7025   - { name: '给变量赋值', id: enumActionType.PROPS, disabled: true },
7026   - ]
7027   - return UseLayUi.generateOptionTemplate({ dataSource: options, addPlaceholderOption: false })
7028   - }
7029   -
7030   - /**
7031   - * @description 生产页面选项
7032   - */
7033   - function generatorPageOptions() {
7034   - const options = ui.pages.map(item => ({ name: item.getName(), id: item.getId() }))
7035   - return UseLayUi.generateOptionTemplate({ dataSource: options, addPlaceholderOption: false })
7036   - }
7037   -
7038   - function generatorEventListen() {
7039   - form.on(`select(${enumActionEl.ACTION_SELECT_FILTER})`, (data) => {
7040   - const { value } = data
7041   - controlFormDisplay(value)
7042   - })
7043   - }
7044   -
7045   - function isJson(string) {
7046   - if (typeof string === 'string') {
7047   - try {
7048   - const obj = JSON.parse(string)
7049   - if (typeof obj === 'object' && obj !== null) {
7050   - return true
7051   - }
7052   - } catch (e) {
7053   - return false
7054   - }
7055   - }
7056   - return false
7057   - }
7058   -
7059   - function jsonParse(value) {
7060   - try {
7061   - return JSON.parse(value)
7062   - } catch (error) {
7063   - return {}
7064   - }
7065   - }
7066   -
7067   -
7068   - /**
7069   - * @description 创建JSON编辑器
7070   - * @param el
7071   - * @param datum
7072   - */
7073   - function createEditor(record) {
7074   - let defaultValue = { [enumConst.ATTR_PLACEHOLDER]: 0 }
7075   - const editor = ace.edit(enumActionEl.EDITOR, {
7076   - maxLines: 18, // 最大行数,超过会自动出现滚动条
7077   - minLines: 10, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
7078   - fontSize: 14, // 编辑器内字体大小
7079   - tabSize: 2, // 制表符设置为 4 个空格大小
7080   - });
7081   - if (record.content && record.content[enumConst.COMMAND]) defaultValue = jsonParse(record.content[enumConst.COMMAND])
7082   - const stringValue = JSON.stringify(defaultValue, null, 2)
7083   - editor.insert(stringValue)
7084   - $(`#${enumActionEl.EDITOR_CONTAINER}`).parent().find(`textarea[name="${enumConst.COMMAND}"]`).val(stringValue)
7085   - editor.session.setMode("ace/mode/json");
7086   - editor.getSession().on('change', (event, editor) => {
7087   - $(`#${enumActionEl.EDITOR_CONTAINER}`).parent().find(`textarea[name="${enumConst.COMMAND}"]`).val(editor.getValue())
7088   - })
7089   - }
7090   -
7091   - /**
7092   - * @description 创建弹窗表单
7093   - */
7094   - function createLayerForm(type) {
7095   -
7096   - const content = `
7097   - <form class="layui-form" lay-filter="${enumActionEl.FORM_FILTER}">
7098   - <div style="width: 450px">
7099   - <div class="layui-form-item">
7100   - <label class="layui-form-label">事件</label>
7101   - <div class="layui-input-block">
7102   - <input type="text" name="${enumConst.EVENT}" disabled class="layui-input" value="${enumEventType[type]}">
7103   - </div>
7104   - </div>
7105   - <div class="layui-form-item">
7106   - <label class="layui-form-label">动作</label>
7107   - <div class="layui-input-block">
7108   - <select name="${enumConst.ACTION}" lay-verType="tips" lay-verify="required" lay-filter="${enumActionEl.ACTION_SELECT_FILTER}">
7109   - ${generatorActionOptions()}
7110   - </select>
7111   - </div>
7112   - </div>
7113   - <div class="layui-form-item" id="${enumActionEl.LINK_EL_ID}">
7114   - <label class="layui-form-label">链接</label>
7115   - <div class="layui-input-block">
7116   - <input type="text" lay-verType="tips" name="${enumConst.LINK_VALUE}" class="layui-input">
7117   - </div>
7118   - </div>
7119   - <div class="layui-form-item" id="${enumActionEl.PAGE_EL_ID}" style="display:none">
7120   - <label class="layui-form-label">页面</label>
7121   - <div class="layui-input-block">
7122   - <select name="${enumConst.PAGE_VALUE}" lay-verType="tips" id="pageSelect">
7123   - ${generatorPageOptions()}
7124   - </select>
7125   - </div>
7126   - </div>
7127   - <div class="layui-form-item" id="${enumActionEl.WAY_SELECT}" style="display:none">
7128   - <label class="layui-form-label">单向/双向 ${createHelpMessage(`单向:服务器向网关设备、直连设备发送指令。发送指令后,设备不会返回任何信息。\n
7129   - 双向:服务器向网关设备、直连设备发送指令。发送指令后,设备返回响应信息。`, 'way')}</label>
7130   - <div class="layui-input-block">
7131   - <input type="radio" name="${enumConst.WAY}" value="${enumWayType.ONE_WAY}" title="单向" checked="">
7132   - <input type="radio" name="${enumConst.WAY}" value="${enumWayType.TWO_WAY}" title="双向">
7133   - </div>
7134   - </div>
7135   - <div id="${enumActionEl.EDITOR_CONTAINER}" style="display: none;">
7136   - <div style="width: 80px; text-align: right; padding: 9px 15px;flex: 0 0 80px;">命令 ${createHelpMessage('用户预览模式下,点击参数设置后。输入的变量值将作为"attrPlaceholder"的值,并以JSON格式下发给服务器。', 'command')}</div>
7137   - <div id="${enumActionEl.EDITOR}" style="width: 100%; height: 100%;border: 2px solid #eee;"></div>
7138   - <textarea name="${enumConst.COMMAND}" style="display: none;" />
7139   - </div>
7140   - </div>
7141   - </form>
7142   - `
7143   -
7144   - layer.open({
7145   - title: "创建交互",
7146   - content,
7147   - area: ["800px", "500px"],
7148   - btn: ["保存", "取消"],
7149   - yes(index) {
7150   - form.on(`submit(${enumActionEl.LAYER_SUBMIT_FILTER})`, data => {
7151   - submit(() => {
7152   - layer.close(index)
7153   - !isControlComponent && getNodeBindInfo()
7154   - })
7155   - })
7156   - },
7157   - btn2(index) {
7158   - layer.close(index);
7159   - },
7160   - success(layero) {
7161   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
7162   - 'lay-submit': '',
7163   - 'lay-filter': enumActionEl.LAYER_SUBMIT_FILTER,
7164   - })
7165   - generatorEventListen()
7166   - const info = getLayerBindInfo('event', type)
7167   - Object.assign(recordData, { enabled: info.enabled })
7168   - createEditor(info)
7169   - form.render(null, enumActionEl.FORM_FILTER)
7170   - if (info) echoFormData(info)
7171   - },
7172   - shade: ["0.7", "#fafafa"],
7173   - });
7174   - }
7175   -
7176   - createLayerForm(event.data.type)
7177   - }
7178   -
7179   - /**
7180   - * @description 处理数据动效
7181   - */
7182   - function handleDataDynamicEffect(event) {
7183   -
7184   - const IS_DISPLAY = event.data.type === enumDynamicEffectType.DISPLAY
7185   - const IS_RUNNING = event.data.type === enumDynamicEffectType.RUNNING
7186   -
7187   - const enumEventType = {
7188   - FLASH: '闪烁',
7189   - DISPLAY: '显示/隐藏',
7190   - ROTATE: '旋转',
7191   - RUNNING: '水流动效'
7192   - }
7193   -
7194   - const enumActionEl = {
7195   - ROW_FILTER: 'dataDynamicEffectRowFilter',
7196   - FORM_FILTER: 'dataDynamicEffectFormFilter',
7197   - TABLE_BODY_EL: 'dataDynamicEffectTbody',
7198   - TYPE_EL: 'dataDynamicEffectType',
7199   - DEL_BTN_EL: 'dataDynamicEffectDelBtn',
7200   - ADD_BTN_EL: 'dataDynamicEffectAddBtn',
7201   - DISPLAY_SWITCH_EL: 'visibleOrHidden',
7202   - LAYER_SUBMIT_FILTER: 'dynamicEffectLayerFilter',
7203   - MIN_FILTER: 'dynamicEffectMinFilter',
7204   - MAX_FILTER: 'dynamicEffectMaxFilter',
7205   - DATA_SOURCE_COMP_EL: 'dynamicDataSourceCompEl',
7206   - }
7207   -
7208   - const getRowFilter = (rowNumber) => `${enumActionEl.ROW_FILTER}${rowNumber}`
7209   -
7210   - /**
7211   - * @description
7212   - */
7213   - const enumConst = {
7214   - MIN: 'min',
7215   - MAX: 'max',
7216   - TYPE: 'type',
7217   - ORG_ID: 'orgId',
7218   - DEVICE_ID: 'deviceId',
7219   - SLAVE_DEVICE_ID: 'slaveDeviceId',
7220   - ATTR: 'attr',
7221   - GATEWAY: 'GATEWAY',
7222   - }
7223   -
7224   - const enumDisplayType = HandleDynamicEffect.enumDisplayType
7225   -
7226   - const enumRunningType = HandleDynamicEffect.enumRunningType
7227   -
7228   - const displayOptions = [
7229   - { name: '显示', id: enumDisplayType.SHOW },
7230   - { name: '隐藏', id: enumDisplayType.HIDDEN },
7231   - ]
7232   -
7233   - const runningOptions = [
7234   - { name: '流动', id: enumRunningType.RUN },
7235   - { name: '静止', id: enumRunningType.STOP },
7236   - ]
7237   -
7238   - /**
7239   - * @description
7240   - */
7241   - let addRowNumber = 0
7242   -
7243   - const recordData = {
7244   - enabled: false
7245   - }
7246   -
7247   - function generateStateOptions(options = []) {
7248   - const template = UseLayUi.generateOptionTemplate({ dataSource: options, addPlaceholderOption: false })
7249   - return `
7250   - <div class="layui-form-item" style="margin-bottom: 0px">
7251   - <div class="layui-input-block" style="margin-left: 0px;">
7252   - <select name="${enumConst.TYPE}" lay-verType="tips" lay-verify="required">${template}</select>
7253   - </div>
7254   - </div>
7255   - `
7256   - }
7257   -
7258   - /**
7259   - * @description 添加一条记录
7260   - */
7261   - function addRecord() {
7262   - const content = `
7263   - <tr class="layui-form" lay-filter="${getRowFilter(addRowNumber)}">
7264   - ${IS_DISPLAY && `<td>${generateStateOptions(displayOptions)}</td>`}
7265   - ${IS_RUNNING && `<td>${generateStateOptions(runningOptions)}</td>`}
7266   - <td>
7267   - <input autocomplete="off" lay-verType="tips" lay-verify="required" type="number" name="${enumConst.MIN}" class="layui-input ${enumActionEl.MIN_FILTER}">
7268   - </td>
7269   - <td>
7270   - <input autocomplete="off" lay-verType="tips" lay-verify="required" type="number" name="${enumConst.MAX}" class="layui-input ${enumActionEl.MAX_FILTER}">
7271   - </td>
7272   - <td style="text-align: center;">
7273   - <button type="button" class="layui-btn layui-btn-primary layui-border-red ${enumActionEl.DEL_BTN_EL}">删除</button>
7274   - </td>
7275   - </tr>
7276   - `
7277   - addRowNumber++
7278   - $(`#${enumActionEl.TABLE_BODY_EL}`).append(content)
7279   - if (IS_DISPLAY || IS_RUNNING) {
7280   - form.render()
7281   - }
7282   - }
7283   -
7284   - /**
7285   - * @description 创建添加记录事件
7286   - */
7287   - function createAddRowListenEvent() {
7288   - $(`#${enumActionEl.ADD_BTN_EL}`).on('click', () => {
7289   - addRecord()
7290   - })
7291   - }
7292   -
7293   - /**
7294   - * @description 创建删除行事件
7295   - */
7296   - function createDeleteRowListenEvent() {
7297   - $(`#${enumActionEl.TABLE_BODY_EL}`).on('click', `.${enumActionEl.DEL_BTN_EL}`, (event) => {
7298   - $(event.target).parents('tr').remove()
7299   - })
7300   - }
7301   -
7302   -
7303   - /**
7304   - * @description 创建输入监听
7305   - */
7306   - function createInputListener() {
7307   - $(`#${enumActionEl.TABLE_BODY_EL}`)
7308   - .on('input', `.${enumActionEl.MIN_FILTER}`, event => {
7309   - const minVal = $(event.target).val()
7310   - const maxVal = $(event.target).parents('tr').find(`input.${enumActionEl.MAX_FILTER}`).val()
7311   - if (maxVal !== '' && Number(minVal) > Number(maxVal)) {
7312   - layer.tips('输入值大于最大值', $(event.target), {
7313   - tips: 1,
7314   - });
7315   - }
7316   - })
7317   - .on('input', `.${enumActionEl.MAX_FILTER}`, event => {
7318   - const maxVal = $(event.target).val()
7319   - const minVal = $(event.target).parents('tr').find(`input.${enumActionEl.MIN_FILTER}`).val()
7320   - if (minVal !== '' && Number(maxVal) < Number(minVal)) {
7321   - layer.tips('输入值小于最小值', $(event.target), {
7322   - tips: 1,
7323   - });
7324   - }
7325   - })
7326   - }
7327   -
7328   -
7329   - /**
7330   - * @description 下拉选项挂载
7331   - */
7332   - function createSelectOptionMountEvent() {
7333   - $(`#${enumActionEl.TABLE_BODY_EL}`).on('click', '.layui-form-select', event => {
7334   - const width = event.currentTarget.offsetWidth || 200
7335   - const height = event.currentTarget.offsetHeight || 38
7336   - const offset = $(event.currentTarget).offset()
7337   - $(event.currentTarget).find('dl').css({
7338   - position: 'fixed',
7339   - 'min-width': width + 'px',
7340   - top: offset.top + height + 'px',
7341   - left: offset.left + 'px'
7342   - })
7343   - })
7344   - }
7345   -
7346   - /**
7347   - * @description 创建事件监听
7348   - */
7349   - function createEventListen() {
7350   - createInputListener()
7351   - createAddRowListenEvent()
7352   - createDeleteRowListenEvent()
7353   - createSelectOptionMountEvent()
7354   - }
7355   -
7356   - /**
7357   - * @description 回显数据
7358   - */
7359   - function echoData(info) {
7360   - const { condition = [] } = info
7361   - echoEachData(condition)
7362   - }
7363   -
7364   - /**
7365   - * @description 回显行数据
7366   - */
7367   - function echoEachData(condition = []) {
7368   - condition.forEach((item, index) => {
7369   - addRecord()
7370   - form.val(getRowFilter(index), { ...item })
7371   - })
7372   - }
7373   -
7374   - function validate(tableData) {
7375   - let validateFlag = true
7376   - for (let i = 0; i < tableData.length; i++) {
7377   - const { min, max } = tableData[i]
7378   - if (Number(min) > Number(max)) {
7379   - validateFlag = false
7380   - layer.tips('输入值大于最大值', $(`#${enumActionEl.TABLE_BODY_EL} tr`).eq(i).find(`input[name="${enumConst.MIN}"]`), { tips: 1 })
7381   - break
7382   - } else if (Number(max) < Number(min)) {
7383   - validateFlag = false
7384   - layer.tips('输入值小于最小值', $(`#${enumActionEl.TABLE_BODY_EL} tr`).eq(i).find(`input[name="${enumConst.MAX}"]`), { tips: 1 })
7385   - break
7386   - }
7387   - }
7388   - return validateFlag
7389   - }
7390   -
7391   - async function submit(callback) {
7392   - if (!hasPermission()) return
7393   - const tableData = Array.from({ length: addRowNumber }).map((_, index) => form.val(getRowFilter(index))).filter(obj => Object.keys(obj).length)
7394   - if (!validate(tableData)) return
7395   - const formVal = form.val(enumActionEl.FORM_FILTER)
7396   - const formModel = {
7397   - configurationId,
7398   - contentId: currentPageId.id,
7399   - ...formVal,
7400   - id: graphId,
7401   - condition: tableData,
7402   - type: event.data.type,
7403   - ...recordData
7404   - }
7405   - await to(autoSaveGraphInfo())
7406   - const [err, res] = await to(ConfigurationNodeApi.updateNodeAct(formModel))
7407   - if (err) return
7408   - UseLayUi.successMsg()
7409   - callback()
7410   - }
7411   -
7412   - function isExistInArea(min, max, value) {
7413   - return Number(value) >= Number(min) && Number(value) <= Number(max)
7414   - }
7415   -
7416   - function createLayerForm(type) {
7417   - const content = `
7418   - <form class="layui-form" lay-filter="${enumActionEl.FORM_FILTER}">
7419   - <div style="width:400px">
7420   - <div class="layui-form-item">
7421   - <label class="layui-form-label">类型</label>
7422   - <div class="layui-input-block">
7423   - <input type="radio" name="type" value="1" title="联网设备" checked>
7424   - <input type="radio" name="type" value="2" title="产品/场景" disabled>
7425   - </div>
7426   - </div>
7427   -
7428   - <div id="${enumActionEl.DATA_SOURCE_COMP_EL}"></div>
7429   -
7430   - </div>
7431   - </form>
7432   - <div class="override__table">
7433   - <table class="layui-table" >
7434   - <thead>
7435   - <tr>
7436   - ${IS_DISPLAY ? '<th style="text-align:center">类型</th>' : ''}
7437   - ${IS_RUNNING ? '<th style="text-align:center">类型</th>' : ''}
7438   - <th style="text-align:center">最小值(>=)</th>
7439   - <th style="text-align:center">最大值(<=)</th>
7440   - <th style="text-align:center">操作</th>
7441   - </tr>
7442   - </thead>
7443   - <tbody id="${enumActionEl.TABLE_BODY_EL}"></tbody>
7444   - </table>
7445   - <div style="display:flex;justify-content:center;">
7446   - <button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="${enumActionEl.ADD_BTN_EL}">添加一条</button>
7447   - </div>
7448   - </div>
7449   - `
7450   -
7451   - layer.open({
7452   - title: enumEventType[type],
7453   - content,
7454   - skin: 'event-layer__override',
7455   - btn: ['保存', '取消'],
7456   - offset: '100px',
7457   - area: (IS_DISPLAY || IS_RUNNING) ? '1000px' : '800PX',
7458   - success(layero) {
7459   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
7460   - 'lay-submit': '',
7461   - 'lay-filter': enumActionEl.LAYER_SUBMIT_FILTER,
7462   - })
7463   -
7464   - // render data source tree
7465   - const {
7466   - component,
7467   - echoDataSource,
7468   - } = generateDataSourceComponent({ overrideClass: 'dynamic-effect__data-source-comp--override' })
7469   - $(`#${enumActionEl.DATA_SOURCE_COMP_EL}`).append(component)
7470   - form.render()
7471   -
7472   - const info = getLayerBindInfo('act', type)
7473   - const { condition = [], enabled } = info
7474   - Object.assign(recordData, { enabled })
7475   - if (info && condition.length) {
7476   - echoDataSource(info)
7477   - echoData(info)
7478   - } else {
7479   - addRecord()
7480   - }
7481   - createEventListen()
7482   - form.render()
7483   - },
7484   - yes(index) {
7485   - form.on(`submit(${enumActionEl.LAYER_SUBMIT_FILTER})`, data => {
7486   - submit(() => {
7487   - layer.close(index)
7488   - getNodeBindInfo()
7489   - })
7490   - })
7491   - },
7492   - btn2() {
7493   -
7494   - },
7495   - })
7496   - }
7497   -
7498   - createLayerForm(event.data.type)
7499   -
7500   - }
7501   -
7502   -
7503   - /**
7504   - * @description
7505   - * @param {} event
7506   - */
7507   - function handleStateSetting(event) {
7508   -
7509   - const enumActionEl = {
7510   - TABLE_BODY_EL: 'stateTableBodyEl',
7511   - LAYER_SUBMIT_FILTER: 'stateSettingSubmitFilter',
7512   - ENABLE_FILTER: 'enableFilter',
7513   - CLOSE_FILTER: 'closeFilter',
7514   - SET_IMG_EL: 'variableImageTableSetImgEl',
7515   - PREVIEW_IMG_CONTAINER: 'img__container',
7516   - DEL_PREVIEW_IMG: 'img__delete',
7517   - PREVIEW_CONTAINER: 'previewContainer'
7518   - }
7519   -
7520   - const enumConst = {
7521   -
7522   - TYPE: 'type',
7523   -
7524   - /**
7525   - * @description 开启类型
7526   - */
7527   - ENABLE_TYPE: 'enable',
7528   -
7529   - /**
7530   - * @description 关闭类型
7531   - */
7532   - CLOSE_TYPE: 'close',
7533   -
7534   - /**
7535   - * @description 图片来源
7536   - */
7537   - IMAGE_ORIGIN: 'imageOrigin',
7538   -
7539   - /**
7540   - * @description 图库图形类别
7541   - */
7542   - IMAGE_GALLERY_CATEGORY: 'category',
7543   -
7544   - /**
7545   - * @description 图表图形路径
7546   - */
7547   - IMAGE_GALLERY_IMAGE_PATH: 'imagePath',
7548   -
7549   - /**
7550   - * @description 状态设置 值
7551   - */
7552   - VALUE: 'value'
7553   - }
7554   -
7555   - const recordData = {
7556   - enabled: false
7557   - }
7558   -
7559   - const StateDefaultValue = {
7560   - enable: {
7561   - [enumConst.TYPE]: enumConst.ENABLE_TYPE,
7562   - [enumConst.IMAGE_ORIGIN]: 'gallery',
7563   - [enumConst.IMAGE_GALLERY_CATEGORY]: 'switch',
7564   - [enumConst.IMAGE_GALLERY_IMAGE_PATH]: `${Proxy_Prefix}/images/thingskit/switch-on.svg`,
7565   - },
7566   - close: {
7567   - [enumConst.TYPE]: enumConst.CLOSE_TYPE,
7568   - [enumConst.IMAGE_ORIGIN]: 'gallery',
7569   - [enumConst.IMAGE_GALLERY_CATEGORY]: 'switch',
7570   - [enumConst.IMAGE_GALLERY_IMAGE_PATH]: `${Proxy_Prefix}/images/thingskit/switch-off.svg`,
7571   - }
7572   - }
7573   -
7574   - function createUploadImgContainer(info) {
7575   - const enableEl = $(`#${enumActionEl.TABLE_BODY_EL} tr[lay-filter="${enumActionEl.ENABLE_FILTER}"] .${enumActionEl.PREVIEW_CONTAINER}`)
7576   - const closeEl = $(`#${enumActionEl.TABLE_BODY_EL} tr[lay-filter="${enumActionEl.CLOSE_FILTER}"] .${enumActionEl.PREVIEW_CONTAINER}`)
7577   - generateUploadImgContainer({ el: enableEl })
7578   - generateUploadImgContainer({ el: closeEl })
7579   - }
7580   -
7581   - function addRecord(filter, state, defaultValue) {
7582   - return `
7583   - <tr class="layui-form" lay-filter="${filter}">
7584   - <td>
7585   - ${state}
7586   - </td>
7587   - <td>
7588   - <div class="layui-form-item">
7589   - <input class="layui-input" autocomplete="off" type="number" name="${enumConst.VALUE}" lay-verType="tips" lay-verify="required" />
7590   - <input class="layui-input" autocomplete="off" style="display: none;" name="${enumConst.TYPE}" lay-verType="tips" lay-verify="required" />
7591   - </div>
7592   - </td>
7593   - <td class=${enumActionEl.PREVIEW_CONTAINER}>
7594   - </td>
7595   - </tr>`
7596   - }
7597   -
7598   - /**
7599   - * @descrition 回显数据
7600   - */
7601   - function echoData(info = {}) {
7602   - const { condition = [] } = info
7603   -
7604   - condition.forEach(item => {
7605   - if (item[enumConst.TYPE] === enumConst.ENABLE_TYPE) {
7606   - setRowFormValue(enumActionEl.ENABLE_FILTER, item)
7607   - } else if (item[enumConst.TYPE] === enumConst.CLOSE_TYPE) {
7608   - setRowFormValue(enumActionEl.CLOSE_FILTER, item)
7609   - }
7610   - })
7611   -
7612   - form.render()
7613   - }
7614   -
7615   - /**
7616   - * @description 初始化数据
7617   - */
7618   - function initialData() {
7619   - setRowFormValue(enumActionEl.ENABLE_FILTER, StateDefaultValue.enable)
7620   - setRowFormValue(enumActionEl.CLOSE_FILTER, StateDefaultValue.close)
7621   - }
7622   -
7623   - function setRowFormValue(formFilter, value = {}) {
7624   - form.val(formFilter, value)
7625   - $(`#${enumActionEl.TABLE_BODY_EL} tr[lay-filter="${formFilter}"] .${enumActionEl.SET_IMG_EL} img`).attr('src', value[enumConst.IMAGE_GALLERY_IMAGE_PATH])
7626   - form.render()
7627   - }
7628   -
7629   - async function submit(callback) {
7630   - if (!hasPermission()) return
7631   -
7632   - const enableValue = form.val(enumActionEl.ENABLE_FILTER)
7633   - const closeValue = form.val(enumActionEl.CLOSE_FILTER)
7634   -
7635   - const formVal = getDataSourceBindValue()
7636   -
7637   - if (![formVal.deviceId && formVal.orgId].every(Boolean)) {
7638   - UseLayUi.topErrorMsg('请先选择数据源')
7639   - return
7640   - }
7641   -
7642   - const formModel = {
7643   - configurationId,
7644   - contentId: currentPageId.id,
7645   - ...formVal,
7646   - id: graphId,
7647   - condition: [enableValue, closeValue],
7648   - type: event.data.type,
7649   - ...recordData
7650   - }
7651   - await to(autoSaveGraphInfo())
7652   - const [err, res] = await to(ConfigurationNodeApi.updateNodeAct(formModel))
7653   - if (err) return
7654   - overrideCurrentData('act', 'type', res)
7655   - echoActionType()
7656   - UseLayUi.successMsg()
7657   - callback()
7658   - }
7659   -
7660   - function createLayerForm(type) {
7661   - const content = `
7662   - <table class="layui-table">
7663   - <colgroup>
7664   - <col width="150">
7665   - <col width="150">
7666   - <col>
7667   - </colgroup>
7668   - <thead>
7669   - <tr>
7670   - <th>状态</th>
7671   - <th>值</th>
7672   - <th>展示图片</th>
7673   - </tr>
7674   - </thead>
7675   - <tbody id="${enumActionEl.TABLE_BODY_EL}">
7676   - ${addRecord(enumActionEl.ENABLE_FILTER, '开启')}
7677   - ${addRecord(enumActionEl.CLOSE_FILTER, '关闭')}
7678   - </tbody>
7679   - </table>`
7680   -
7681   - layer.open({
7682   - title: '状态设置',
7683   - content,
7684   - skin: 'event-layer__override',
7685   - btn: ['保存', '取消'],
7686   - offset: '100px',
7687   - area: '500px',
7688   - success(layero) {
7689   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
7690   - 'lay-submit': '',
7691   - 'lay-filter': enumActionEl.LAYER_SUBMIT_FILTER,
7692   - })
7693   - createUploadImgContainer()
7694   -
7695   - const info = getLayerBindInfo('act', type)
7696   - const { condition = [], enabled } = info
7697   - Object.assign(recordData, { enabled })
7698   -
7699   - if (info && condition.length) {
7700   - echoData(info)
7701   - } else {
7702   - initialData()
7703   - }
7704   - },
7705   - yes(index) {
7706   - form.on(`submit(${enumActionEl.LAYER_SUBMIT_FILTER})`, data => {
7707   - submit(() => {
7708   - layer.close(index)
7709   - // getNodeBindInfo()
7710   - })
7711   - })
7712   - },
7713   - btn2() {
7714   -
7715   - },
7716   - })
7717   - }
7718   -
7719   - createLayerForm(event.data.type)
7720   - }
7721   -
7722   - /**
7723   - * @description 生成数据源组件
7724   - * @param {object} options
7725   - * @param {string} [options.overrideClass = ''] options.overrideClass
7726   - * @param {boolean} [options.validate = true ] options.validate
7727   - */
7728   - function generateDataSourceComponent(options = {}) {
7729   - const { overrideClass = '', validate = true } = options
7730   - const componentFilter = `data-source__component-filter-${Date.now()}`
7731   - const componentId = `data-source__component-${Date.now()}`
7732   -
7733   - const validateRule = validate ? { layVerify: 'required', layVerType: 'tips' } : {}
7734   -
7735   - const enumDataSourceConst = {
7736   - ORG_ID: 'orgId',
7737   - DEVICE_ID: 'deviceId',
7738   - SLAVE_DEVICE_ID: 'slaveDeviceId',
7739   - ATTR: 'attr',
7740   - GATEWAY: 'GATEWAY',
7741   - }
7742   - /**
7743   - * @description
7744   - * @type {{id: string, deviceType: string, name: string}[]}
7745   - */
7746   - let deviceList = []
7747   -
7748   - const component = document.createElement('div')
7749   -
7750   - $(component)
7751   - .addClass(`layui-form data-source__component-style ${overrideClass}`)
7752   - .attr({
7753   - id: componentId,
7754   - 'lay-filter': componentFilter,
7755   - })
7756   -
7757   - init()
7758   -
7759   - function init() {
7760   - generatorOrgTres()
7761   - generatorDeviceSelect()
7762   - generatorSlaveDevice()
7763   - generatorAttrSelect()
7764   - }
7765   -
7766   -
7767   - /**
7768   - * @description 根据组织ID获取设备
7769   - */
7770   - async function getDevicesByOrgId(organizationId) {
7771   - if (organizationId) {
7772   - const items = deviceList = await ConfigurationNodeApi.getMasterDevice(organizationId);
7773   - $(`#${componentId} `).find(`select[name="${enumDataSourceConst.DEVICE_ID}"]`).html(UseLayUi.generateOptionTemplate({ dataSource: items }))
7774   - form.render('select', componentFilter)
7775   - }
7776   - }
7777   -
7778   - /**
7779   - * @description 通过主设备ID获取从设备
7780   - */
7781   - async function getSlaveDeviceByMasterDeviceId(orgId, deviceId) {
7782   - if (deviceId && currentCheckedOrgNode) {
7783   - const items = await ConfigurationNodeApi.getSlaveDevice(orgId, deviceId);
7784   - $(`#${componentId} `).find(`select[name="${enumDataSourceConst.SLAVE_DEVICE_ID}"]`).html(UseLayUi.generateOptionTemplate({ dataSource: items }))
7785   - form.render('select', componentFilter)
7786   - }
7787   - }
7788   -
7789   - /**
7790   - * @description 根据设备ID获取属性
7791   - */
7792   - async function getAttrByDeviceId(tbDeviceId) {
7793   - if (tbDeviceId) {
7794   - const [err, res] = await to(ConfigurationNodeApi.getDeviceAttr(tbDeviceId))
7795   - $(`#${componentId} `).find(`select[name="${enumDataSourceConst.ATTR}"]`).html(UseLayUi.generateOptionTemplate({ dataSource: res }))
7796   - form.render('select', componentFilter)
7797   - }
7798   - }
7799   -
7800   -
7801   - /**
7802   - * @description 生成组织选择
7803   - */
7804   - async function generatorOrgTres() {
7805   - const orgContainerId = `data-source__component--org-${Date.now()}`
7806   - const orgContainer = `<div id="${orgContainerId}"></div>`
7807   - $(component).append(orgContainer)
7808   -
7809   - const [err, res] = await to(ConfigurationNodeApi.getOrgTree())
7810   - if (err) return
7811   - treeList = res
7812   -
7813   - UseLayUi.createTreeSelect({
7814   - elem: `#${orgContainerId}`,
7815   - layFilter: enumDataSourceConst.ORG_ID,
7816   - label: '组织',
7817   - singleUsage: false,
7818   - className: 'data-source__component-select',
7819   - ...validateRule,
7820   - treeProps: {
7821   - data: treeList,
7822   - onlyIconControl: true,
7823   - click(node) {
7824   - currentCheckedOrgNode = node.data.id
7825   - form.val(componentFilter, {
7826   - [enumDataSourceConst.DEVICE_ID]: null,
7827   - [enumDataSourceConst.SLAVE_DEVICE_ID]: null,
7828   - [enumDataSourceConst.ATTR]: null,
7829   - })
7830   - getDevicesByOrgId(node.data.id)
7831   - },
7832   - },
7833   - })
7834   - }
7835   -
7836   - /**
7837   - * @description 生成设备选择器
7838   - */
7839   - function generatorDeviceSelect() {
7840   - const deviceSelect = UseLayUi.createSelect({
7841   - label: '设备',
7842   - bindValueFiled: enumDataSourceConst.DEVICE_ID,
7843   - layFilter: `${componentFilter}--${enumDataSourceConst.DEVICE_ID}`,
7844   - className: 'data-source__component-select',
7845   - ...validateRule,
7846   - onClick(data) {
7847   - const { value } = data
7848   - const selected = deviceList.find(item => item.id === value)
7849   - form.val(componentFilter, {
7850   - [enumDataSourceConst.SLAVE_DEVICE_ID]: null,
7851   - [enumDataSourceConst.ATTR]: null,
7852   - })
7853   - if (!selected) return
7854   - if (selected.deviceType === enumDataSourceConst.GATEWAY) {
7855   - $(`#${componentId}`).find(`select[name="${enumDataSourceConst.SLAVE_DEVICE_ID}"]`)
7856   - .attr('lay-verify', 'required').attr('lay-verType', 'tips')
7857   - .parentsUntil(`#${componentId}`).show()
7858   - getSlaveDeviceByMasterDeviceId(currentCheckedOrgNode, selected.id)
7859   - } else {
7860   - $(`#${componentId}`).find(`select[name="${enumDataSourceConst.SLAVE_DEVICE_ID}"]`)
7861   - .attr('lay-verify', '').attr('lay-verType', 'tips')
7862   - .parentsUntil(`#${componentId}`).hide()
7863   - getAttrByDeviceId(selected.id)
7864   - }
7865   - },
7866   - })
7867   - $(component).append(deviceSelect)
7868   - }
7869   -
7870   - /**
7871   - * @description 生成从设备选择器
7872   - */
7873   - function generatorSlaveDevice() {
7874   - const slaveDeviceSelect = UseLayUi.createSelect({
7875   - label: '子设备',
7876   - bindValueFiled: enumDataSourceConst.SLAVE_DEVICE_ID,
7877   - layFilter: `${componentFilter}--${enumDataSourceConst.SLAVE_DEVICE_ID}`,
7878   - className: 'data-source__component-select',
7879   - onClick(data) {
7880   - const { value } = data
7881   - form.val(componentFilter, {
7882   - [enumDataSourceConst.ATTR]: null,
7883   - })
7884   - getAttrByDeviceId(value)
7885   - },
7886   - })
7887   - $(component).append(slaveDeviceSelect)
7888   - }
7889   -
7890   - /**
7891   - * @description 生成属性选择器
7892   - */
7893   - function generatorAttrSelect() {
7894   - const attrsSelect = UseLayUi.createSelect({
7895   - label: '属性',
7896   - bindValueFiled: enumDataSourceConst.ATTR,
7897   - layFilter: `${componentFilter}--${enumDataSourceConst.ATTR}`,
7898   - className: 'data-source__component-select',
7899   - ...validateRule,
7900   - })
7901   - $(component).append(attrsSelect)
7902   - }
7903   -
7904   - /**
7905   - * @description 回显数据
7906   - * @param {{orgId: string, deviceId: string, slaveDeviceId?: string, attr: string}} dataSource
7907   - */
7908   - function echoDataSource(dataSource = {}) {
7909   - const { orgId, deviceId, slaveDeviceId, attr } = dataSource
7910   - const queue = []
7911   - if (orgId) {
7912   - currentCheckedOrgNode = orgId
7913   - queue.push(getDevicesByOrgId(orgId))
7914   - }
7915   - if (slaveDeviceId) {
7916   - queue.push(getSlaveDeviceByMasterDeviceId(orgId, deviceId))
7917   - $(`#${componentId}`).find(`select[name="${enumDataSourceConst.SLAVE_DEVICE_ID}"]`).parentsUntil(`#${componentId}`).show()
7918   - queue.push(getAttrByDeviceId(slaveDeviceId))
7919   - } else {
7920   - $(`#${componentId}`).find(`select[name="${enumDataSourceConst.SLAVE_DEVICE_ID}"]`).parentsUntil(`#${componentId}`).hide()
7921   - queue.push(getAttrByDeviceId(deviceId))
7922   - }
7923   - Promise.all(queue)
7924   - .finally(() => {
7925   - const orgNode = UseLayUi.findTreeObjectByField(treeList, currentCheckedOrgNode)
7926   - $(`#${componentId} input[name="${enumDataSourceConst.ORG_ID}"]`).parent().find('span').html(orgNode?.name)
7927   - form.val(componentFilter, {
7928   - orgId,
7929   - deviceId,
7930   - slaveDeviceId,
7931   - attr,
7932   - })
7933   - })
7934   - }
7935   -
7936   - /**
7937   - *
7938   - * @returns {{orgId: string, attr: string, deviceId: string, slaveDeviceId: string}}
7939   - */
7940   - function getValue() {
7941   - return form.val(componentFilter)
7942   - }
7943   -
7944   - return { component, getValue, componentId, componentFilter, echoDataSource }
7945   - }
7946   -
7947   - /**
7948   - * @description 生成上传弹出层组件
7949   - */
7950   - function generateUploadLayerComponent(callback) {
7951   -
7952   - const enumActionEl = {
7953   - /**
7954   - * @description 图片选中区域节点
7955   - */
7956   - IMG_SELECT_CONTAINER_EL: 'imgSelectContainerEl',
7957   -
7958   - /**
7959   - * @description 切换图片来源控制
7960   - */
7961   - SWITCH_IMG_ORIGIN_FILTER: 'switchImgOriginFilter',
7962   -
7963   - /**
7964   - * @description 图片选中侧边栏节点
7965   - */
7966   - VAR_IMG_CONTAINER_SIDEBAR: 'var-image__container-sidebar',
7967   -
7968   - /**
7969   - * @description 图库图形选择区域
7970   - */
7971   - VAR_IMG_CONTAINER_CONTENT: 'var-image__container-content',
7972   -
7973   - /**
7974   - * @description 图库图形项
7975   - */
7976   - VAR_IMG_ITEM: 'var-image__img-item',
7977   -
7978   - /**
7979   - * @description 图库图形选中控制
7980   - */
7981   - VAR_IMG_ITEM_CHECKED: 'var-image__img-item--checked',
7982   -
7983   - /**
7984   - * @description 图库图形类别节点
7985   - */
7986   - VAR_IMG_CATEGORY: 'var-image__category',
7987   -
7988   - /**
7989   - * @description 图库图形类别选择状态
7990   - */
7991   - VAR_IMG_CATEGORY_CHECKED: 'var-image__category--checked',
7992   -
7993   - /**
7994   - * @description 本地上传图片节点
7995   - */
7996   - UPLOAD_LOCAL_FILE_EL: 'var-image__container--local',
7997   -
7998   - /**
7999   - * @description 本地上传图片状态
8000   - */
8001   - IMAGE_UPLOAD_STATE_EL: 'var-image__upload-state',
8002   -
8003   - /**
8004   - * @description 预览图片状态
8005   - */
8006   - IMAGE_PREVIEW_EL: 'preview__img--preview',
8007   -
8008   - /**
8009   - * @description 本地图片上传删除按钮
8010   - */
8011   - IMAGE_DEL_PREVIEW_EL: 'var-image__del-icon',
8012   - }
8013   -
8014   - const enumConst = {
8015   - /**
8016   - * @description 图片来源
8017   - */
8018   - IMAGE_ORIGIN: 'imageOrigin',
8019   -
8020   - /**
8021   - * @description 图库图形类别
8022   - */
8023   - IMAGE_GALLERY_CATEGORY: 'category',
8024   -
8025   - /**
8026   - * @description 图表图形路径
8027   - */
8028   - IMAGE_GALLERY_IMAGE_PATH: 'imagePath',
8029   - }
8030   -
8031   - /**
8032   - * @description 图片来源枚举类型
8033   - */
8034   - const enumImageOriginType = {
8035   - LOCAL: 'local',
8036   - GALLERY: 'gallery',
8037   - }
8038   -
8039   - let imageState = {}
8040   -
8041   - /**
8042   - * @description 设置选中样式
8043   - * @param event
8044   - * @param nodeClass
8045   - * @param styleClass
8046   - */
8047   - function setImageSelectedStyle(event, nodeClass, styleClass) {
8048   - if (!$(event.target).hasClass(nodeClass)) return
8049   - $(`.${nodeClass}`).each(function () {
8050   - $(this).removeClass(styleClass)
8051   - })
8052   - $(event.target).addClass(styleClass)
8053   - }
8054   -
8055   - /**
8056   - * @description 切换图库图形
8057   - * @param event
8058   - */
8059   - function switchGalleryLib(event) {
8060   - const key = $(event.target).attr(enumConst.IMAGE_GALLERY_CATEGORY)
8061   - const category = sidebarInstance.getVariableImageLib(key)
8062   - if (key && category) {
8063   - $(`#${enumActionEl.VAR_IMG_CONTAINER_CONTENT}`).html(
8064   - category.lib.reduce((prev, next) => prev + `<div class="${enumActionEl.VAR_IMG_ITEM}" title="${next.name}"><img src="${next.staticPath}" alt=""></div>`, ''),
8065   - )
8066   - }
8067   - }
8068   -
8069   - /**
8070   - * @description 图片来源事件监听
8071   - */
8072   - function generatorSelectImgEventListener() {
8073   - $(`#${enumActionEl.VAR_IMG_CONTAINER_CONTENT}`).on('click', event => {
8074   - setImageSelectedStyle(event, enumActionEl.VAR_IMG_ITEM, enumActionEl.VAR_IMG_ITEM_CHECKED)
8075   - imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH] = $(event.target).find('img').attr('src')
8076   - })
8077   - $(`#${enumActionEl.VAR_IMG_CONTAINER_SIDEBAR}`).on('click', event => {
8078   - setImageSelectedStyle(event, enumActionEl.VAR_IMG_CATEGORY, enumActionEl.VAR_IMG_CATEGORY_CHECKED)
8079   - imageState[enumConst.IMAGE_GALLERY_CATEGORY] = $(event.target).attr(enumConst.IMAGE_GALLERY_CATEGORY)
8080   - imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH] = null
8081   - switchGalleryLib(event)
8082   - })
8083   - }
8084   -
8085   -
8086   - /**
8087   - * @description 创建本地图片上传区域
8088   - */
8089   - function createLocalFileContainer() {
8090   - return `
8091   - <div id="${enumActionEl.UPLOAD_LOCAL_FILE_EL}" class="layui-upload">
8092   - <div class="preview__img">
8093   - <img src="" class="layui-upload-img" id="${enumActionEl.IMAGE_PREVIEW_EL}">
8094   - <div class="var_image__add-icon">+</div>
8095   - <div class="var-image__del-icon">x</div>
8096   - </div>
8097   - <div class="layui-upload-list"></div>
8098   - </div>
8099   - <div style="margin-top: 10px;" id="${enumActionEl.IMAGE_UPLOAD_STATE_EL}"></div>
8100   - <div style="margin-top: 10px;">图片格式支持png、jpg(jpeg)、gif, 大小不能超过5M</div>`
8101   - }
8102   -
8103   - /**
8104   - * @description 创建图库图形上传区域
8105   - */
8106   - function createGalleryFileContainer() {
8107   - const category = sidebarInstance.getAllVariableImageLib()
8108   - const defaultShow = category[0] || { lib: [] }
8109   - return `
8110   - <div class="var-image__container--gallery">
8111   - <div id="${enumActionEl.VAR_IMG_CONTAINER_SIDEBAR}">
8112   - ${category.reduce((prev, next) => prev + `<div class="${enumActionEl.VAR_IMG_CATEGORY}" ${enumConst.IMAGE_GALLERY_CATEGORY}="${next.key}">${next.label}</div>`, '')}
8113   - </div>
8114   - <div id="${enumActionEl.VAR_IMG_CONTAINER_CONTENT}">
8115   - ${defaultShow.lib.reduce((prev, next) => prev + `<div class="${enumActionEl.VAR_IMG_ITEM}" title="${next.name}"><img src="${next.staticPath}" alt=""></div>`, '')}
8116   - </div>
8117   - </div>`
8118   - }
8119   -
8120   - /**
8121   - * @description 上传
8122   - */
8123   - function uploadFileEvent() {
8124   - $(`.${enumActionEl.IMAGE_DEL_PREVIEW_EL}`).on('click', (event) => {
8125   - event.stopPropagation()
8126   - $(`#${enumActionEl.IMAGE_PREVIEW_EL}`).attr('src', '')
8127   - imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH] = null
8128   - })
8129   - upload.render({
8130   - elem: `#${enumActionEl.UPLOAD_LOCAL_FILE_EL}`,
8131   - auto: false,
8132   - size: 1024 * 5,
8133   - url: '/yt/oss/upload',
8134   - method: 'post',
8135   - choose(obj) {
8136   - obj.preview(async function (index, file, result) {
8137   - const formData = new FormData()
8138   - formData.set('file', file)
8139   - $(`#${enumActionEl.IMAGE_UPLOAD_STATE_EL}`).html('上传中...')
8140   - const [err, res] = await to(ConfigurationNodeApi.uploadImg(formData))
8141   - if (!err) {
8142   - $(`#${enumActionEl.IMAGE_PREVIEW_EL}`).attr('src', result)
8143   - const { fileStaticUri = '' } = res
8144   - imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH] = fileStaticUri
8145   - $(`#${enumActionEl.IMAGE_UPLOAD_STATE_EL}`).html('上传成功').css({ color: '#5fb878' })
8146   - } else {
8147   - $(`#${enumActionEl.IMAGE_UPLOAD_STATE_EL}`).html('上传失败').css({ color: 'red' })
8148   - }
8149   - });
8150   - },
8151   - });
8152   - }
8153   -
8154   - /**
8155   - * @description 切换
8156   - */
8157   - function switchUploadImgTypeEventListener() {
8158   - form.on(`radio(${enumActionEl.SWITCH_IMG_ORIGIN_FILTER})`, event => {
8159   - const { value } = event
8160   - imageState = {}
8161   - if (value === enumImageOriginType.LOCAL) {
8162   - $(`#${enumActionEl.IMG_SELECT_CONTAINER_EL}`).html(createLocalFileContainer())
8163   - imageState[enumConst.IMAGE_ORIGIN] = enumImageOriginType.LOCAL
8164   - uploadFileEvent()
8165   - } else if (value === enumImageOriginType.GALLERY) {
8166   - $(`#${enumActionEl.IMG_SELECT_CONTAINER_EL}`).html(createGalleryFileContainer())
8167   - const defaultChecked = $(`.${enumActionEl.VAR_IMG_CATEGORY}`).eq(0)
8168   - defaultChecked.addClass(enumActionEl.VAR_IMG_CATEGORY_CHECKED)
8169   - imageState[enumConst.IMAGE_GALLERY_CATEGORY] = defaultChecked.attr(enumConst.IMAGE_GALLERY_CATEGORY)
8170   - imageState[enumConst.IMAGE_ORIGIN] = enumImageOriginType.GALLERY
8171   - generatorSelectImgEventListener()
8172   - }
8173   - })
8174   - }
8175   -
8176   -
8177   - /**
8178   - * @description 初始化并设置默认值
8179   - */
8180   - function initSelectImg() {
8181   - switchUploadImgTypeEventListener()
8182   - uploadFileEvent()
8183   - imageState[enumConst.IMAGE_ORIGIN] = enumImageOriginType.LOCAL
8184   - form.render()
8185   - }
8186   -
8187   - /**
8188   - * @description 创建上传图片layer
8189   - */
8190   - function createUploadImgLayer() {
8191   - const content = `
8192   - <div class="layui-form">
8193   - <div class="layui-form-item">
8194   - <div class="var-image__radio">
8195   - <input type="radio" lay-filter="${enumActionEl.SWITCH_IMG_ORIGIN_FILTER}" name="${enumConst.IMAGE}" value="${enumImageOriginType.LOCAL}" title="本地图片" checked="">
8196   - <input type="radio" lay-filter="${enumActionEl.SWITCH_IMG_ORIGIN_FILTER}" name="${enumConst.IMAGE}" value="${enumImageOriginType.GALLERY}" title="图库图形">
8197   - </div>
8198   - </div>
8199   - </div>
8200   - <div id="${enumActionEl.IMG_SELECT_CONTAINER_EL}">
8201   - ${createLocalFileContainer()}
8202   - </div>
8203   - `
8204   -
8205   - layer.open({
8206   - title: '图片',
8207   - type: 1,
8208   - content,
8209   - skin: 'event-layer__override',
8210   - area: '600px',
8211   - btn: ["应用", "取消"],
8212   - shade: ["0.7", "#fafafa"],
8213   - yes(index) {
8214   - layer.close(index)
8215   - if (callback && typeof callback === 'function') callback(imageState)
8216   - },
8217   - but2(index, layero) {
8218   - imageState = {}
8219   - layer.close(index)
8220   - },
8221   - // zIndex: layer.zIndex,
8222   - async success(layero, index) {
8223   - // layer.setTop(layero);
8224   - $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
8225   - 'lay-submit': '',
8226   - 'lay-filter': enumActionEl.IMAGE_LAYER_FILTER,
8227   - })
8228   - initSelectImg()
8229   - },
8230   - })
8231   - }
8232   -
8233   - createUploadImgLayer()
8234   -
8235   - return { record: imageState }
8236   - }
8237   -
8238   -
8239   - /**
8240   - * @description TODO 图片上传容器
8241   - * @param {} option
8242   - * @param {} option.el
8243   - */
8244   - function generateUploadImgContainer({ el }) {
8245   -
8246   -
8247   - const enumConst = {
8248   - /**
8249   - * @description 图片来源
8250   - */
8251   - IMAGE_ORIGIN: 'imageOrigin',
8252   -
8253   - /**
8254   - * @description 图库图形类别
8255   - */
8256   - IMAGE_GALLERY_CATEGORY: 'category',
8257   -
8258   - /**
8259   - * @description 图表图形路径
8260   - */
8261   - IMAGE_GALLERY_IMAGE_PATH: 'imagePath',
8262   - }
8263   -
8264   - const enumActionEl = {
8265   -
8266   - CONTAINER_FILTER: 'imgContainerFilter',
8267   -
8268   - /**
8269   - * @description
8270   - */
8271   - SET_IMG_EL: 'variableImageTableSetImgEl',
8272   -
8273   - /**
8274   - * @description 预览
8275   - */
8276   - PREVIEW_IMG_CONTAINER: 'img__container',
8277   -
8278   - /**
8279   - * @description 删除
8280   - */
8281   - DEL_PREVIEW_IMG: 'img__delete',
8282   - }
8283   -
8284   - const getFormFilter = `${enumActionEl.CONTAINER_FILTER}-${Date.now() - Math.random()}`
8285   -
8286   - function createTemplate() {
8287   - return `
8288   - <div class="layui-form ${enumActionEl.SET_IMG_EL}" lay-filter="${getFormFilter}">
8289   - <input name="${enumConst.IMAGE_GALLERY_CATEGORY}" type="text" style="display: none">
8290   - <input name="${enumConst.IMAGE_GALLERY_IMAGE_PATH}" type="text" style="display: none">
8291   - <input name="${enumConst.IMAGE_ORIGIN}" type="text" style="display: none">
8292   - <div class="${enumActionEl.PREVIEW_IMG_CONTAINER}">
8293   - <img src="" alt="">
8294   - <div class="${enumActionEl.DEL_PREVIEW_IMG}">x</div>
8295   - <div class="add__button">+</div>
8296   - </div>
8297   - </div>
8298   - `
8299   - }
8300   -
8301   - /**
8302   - * @description 设置回显
8303   - * @param {} value
8304   - */
8305   - function setValue(value = {}) {
8306   - form.val(getFormFilter, value)
8307   - }
8308   -
8309   - /**
8310   - * @description 获取值
8311   - * @returns
8312   - */
8313   - function getValue() {
8314   - return form.val(getFormFilter) || {}
8315   - }
8316   -
8317   - function mount() {
8318   - if (!el) throw Error('mount element is required')
8319   - $(el).append(createTemplate())
8320   - generateEventLinstenner()
8321   - }
8322   -
8323   - // TODO 生成容器监听事件
8324   - function generateEventLinstenner() {
8325   - $(el).on('click', `.${enumActionEl.SET_IMG_EL}`, (event) => {
8326   - if ($(event.target).hasClass(enumActionEl.DEL_PREVIEW_IMG)) {
8327   - $(el).find(`div[lay-filter="${getFormFilter}"] img`).attr('src', '')
8328   - form.val(getFormFilter, {
8329   - [enumConst.IMAGE_ORIGIN]: null,
8330   - [enumConst.IMAGE_GALLERY_CATEGORY]: null,
8331   - [enumConst.IMAGE_GALLERY_IMAGE_PATH]: null,
8332   - })
8333   - return
8334   - }
8335   - generateUploadLayerComponent((imageState) => {
8336   - $(el).find('img').attr('src', imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH])
8337   - form.val(getFormFilter, imageState)
8338   - })
8339   - })
8340   - }
8341   -
8342   - mount()
8343   - return { getValue, setValue }
8344   - }
8345   -
8346   - function createHelpMessage(message, className) {
8347   - return `
8348   - <div class="thingskit-help-message ${className}">
8349   - <img src="${Proxy_Prefix}/images/thingskit/question.svg"/>
8350   - <div class="thingskit-help-container">
8351   - <div class="thingskit-help-content">${message}</div>
8352   - <div class="thingskit-help-arrow"></div>
8353   - </div>
8354   - </div>
8355   - `
8356   - }
8357   -
8358   - function hasPermission() {
8359   - let flag = hasSavePermission()
8360   - if (!flag) UseLayUi.topErrorMsg('没有权限')
8361   - return flag
8362   - }
8363   -
8364   - // 异步设置此处才能生效 -- 设置默认select和样式和初始化侧边栏生成组件和事件绑定
8365   - setTimeout(() => {
8366   -
8367   - function proxyFn(fn) {
8368   - return (...args) => {
8369   - const currentDataSource = getDataSourceBindValue() || {}
8370   -
8371   - to(ConfigurationNodeApi.updateNodeInfo({
8372   - configurationId,
8373   - contentId: currentPageId.id,
8374   - nodeId: graphId,
8375   - [enumCategory.DATA_SOURCE]: currentDataSource
8376   - }))
8377   - fn.apply(null, args)
8378   - }
8379   - }
8380   -
8381   - // TODO 数据交互事件
8382   - $(`#${enumDynamicEffectType.IMAGE}`).click({ type: enumDynamicEffectType.IMAGE }, proxyFn(handleSettingVarImage));
8383   -
8384   - $(`#${enumInteractionType.DOWN}`).click({ type: enumInteractionType.DOWN }, proxyFn(handleDownOrUpEvent));
8385   - $(`#${enumInteractionType.UP}`).click({ type: enumInteractionType.UP }, proxyFn(handleDownOrUpEvent));
8386   - $(`#${enumInteractionType.SINGLE}`).click({ type: enumInteractionType.SINGLE }, proxyFn(handleClickOrDbClick));
8387   - $(`#${enumInteractionType.DOUBLE}`).click({ type: enumInteractionType.DOUBLE }, proxyFn(handleClickOrDbClick));
8388   - // 数据动效事件
8389   - $(`#${enumDynamicEffectType.FLASH}`).click({ type: enumDynamicEffectType.FLASH }, proxyFn(handleDataDynamicEffect));
8390   - $(`#${enumDynamicEffectType.DISPLAY}`).click({ type: enumDynamicEffectType.DISPLAY }, proxyFn(handleDataDynamicEffect));
8391   - $(`#${enumDynamicEffectType.ROTATE}`).click({ type: enumDynamicEffectType.ROTATE }, proxyFn(handleDataDynamicEffect));
8392   - $(`#${enumDynamicEffectType.RUNNING}`).click({ type: enumDynamicEffectType.RUNNING }, proxyFn(handleDataDynamicEffect))
8393   -
8394   - $(`#${enumDynamicEffectType.SWITCH}`).click({ type: enumDynamicEffectType.SWITCH }, proxyFn(handleStateSetting))
8395   -
8396   - });
8397   -};
8398   -
8399   -/**
8400   - * Adds the label menu items to the given menu and parent.
8401   - */
8402   -StyleFormatPanel = function (format, editorUi, container) {
8403   - BaseFormatPanel.call(this, format, editorUi, container);
8404   - this.init();
8405   -};
8406   -
8407   -mxUtils.extend(StyleFormatPanel, BaseFormatPanel);
8408   -
8409   -/**
8410   - *
8411   - */
8412   -StyleFormatPanel.prototype.defaultStrokeColor = "black";
8413   -
8414   -/**
8415   - * Adds the label menu items to the given menu and parent.
8416   - */
8417   -StyleFormatPanel.prototype.init = function () {
8418   - var ui = this.editorUi;
8419   - var editor = ui.editor;
8420   - var graph = editor.graph;
8421   - var ss = ui.getSelectionState();
8422   -
8423   - if (!ss.containsLabel && ss.cells.length > 0) {
8424   - if (
8425   - ss.containsImage &&
8426   - ss.vertices.length == 1 &&
8427   - ss.style.shape == "image" &&
8428   - ss.style.image != null &&
8429   - ss.style.image.substring(0, 19) == "data:image/svg+xml;"
8430   - ) {
8431   - this.container.appendChild(this.addSvgStyles(this.createPanel()));
8432   - }
8433   -
8434   - if (ss.fill) {
8435   - this.container.appendChild(this.addFill(this.createPanel()));
8436   - }
8437   -
8438   - this.container.appendChild(this.addStroke(this.createPanel()));
8439   - this.container.appendChild(this.addLineJumps(this.createPanel()));
8440   - var opacityPanel = this.createRelativeOption(
8441   - mxResources.get("opacity"),
8442   - mxConstants.STYLE_OPACITY,
8443   - );
8444   - opacityPanel.style.paddingTop = "8px";
8445   - opacityPanel.style.paddingBottom = "8px";
8446   - this.container.appendChild(opacityPanel);
8447   - this.container.appendChild(this.addEffects(this.createPanel()));
8448   - }
8449   -
8450   - // TODO thingsKit 编辑样式 隐藏
8451   - // var opsPanel = this.addEditOps(this.createPanel());
8452   -
8453   - // if (opsPanel.firstChild != null) {
8454   - // mxUtils.br(opsPanel);
8455   - // }
8456   -
8457   - // this.container.appendChild(this.addStyleOps(opsPanel));
8458   -};
8459   -
8460   -/**
8461   - * Use browser for parsing CSS.
8462   - */
8463   -StyleFormatPanel.prototype.getCssRules = function (css) {
8464   - var doc = document.implementation.createHTMLDocument("");
8465   - var styleElement = document.createElement("style");
8466   -
8467   - mxUtils.setTextContent(styleElement, css);
8468   - doc.body.appendChild(styleElement);
8469   -
8470   - return styleElement.sheet.cssRules;
8471   -};
8472   -
8473   -/**
8474   - * Adds the label menu items to the given menu and parent.
8475   - */
8476   -StyleFormatPanel.prototype.addSvgStyles = function (container) {
8477   - var ui = this.editorUi;
8478   - var graph = ui.editor.graph;
8479   - var ss = ui.getSelectionState();
8480   - container.style.paddingTop = "6px";
8481   - container.style.paddingBottom = "6px";
8482   - container.style.fontWeight = "bold";
8483   - container.style.display = "none";
8484   -
8485   - try {
8486   - var exp = ss.style.editableCssRules;
8487   -
8488   - if (exp != null) {
8489   - var regex = new RegExp(exp);
8490   -
8491   - var data = ss.style.image.substring(ss.style.image.indexOf(",") + 1);
8492   - var xml = window.atob ? atob(data) : Base64.decode(data, true);
8493   - var svg = mxUtils.parseXml(xml);
8494   -
8495   - if (svg != null) {
8496   - var styles = svg.getElementsByTagName("style");
8497   -
8498   - for (var i = 0; i < styles.length; i++) {
8499   - var rules = this.getCssRules(mxUtils.getTextContent(styles[i]));
8500   -
8501   - for (var j = 0; j < rules.length; j++) {
8502   - this.addSvgRule(
8503   - container,
8504   - rules[j],
8505   - svg,
8506   - styles[i],
8507   - rules,
8508   - j,
8509   - regex,
8510   - );
8511   - }
8512   - }
8513   - }
8514   - }
8515   - } catch (e) {
8516   - // ignore
8517   - }
8518   -
8519   - return container;
8520   -};
8521   -
8522   -/**
8523   - * Adds the label menu items to the given menu and parent.
8524   - */
8525   -StyleFormatPanel.prototype.addSvgRule = function (
8526   - container,
8527   - rule,
8528   - svg,
8529   - styleElem,
8530   - rules,
8531   - ruleIndex,
8532   - regex,
8533   -) {
8534   - var ui = this.editorUi;
8535   - var graph = ui.editor.graph;
8536   -
8537   - if (regex.test(rule.selectorText)) {
8538   - function rgb2hex(rgb) {
8539   - rgb = rgb.match(
8540   - /^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i,
8541   - );
8542   -
8543   - return rgb && rgb.length === 4
8544   - ? "#" +
8545   - ("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
8546   - ("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) +
8547   - ("0" + parseInt(rgb[3], 10).toString(16)).slice(-2)
8548   - : "";
8549   - }
8550   -
8551   - var addStyleRule = mxUtils.bind(this, function (rule, key, label) {
8552   - var value = mxUtils.trim(rule.style[key]);
8553   -
8554   - if (value != "" && value.substring(0, 4) != "url(") {
8555   - var option = this.createColorOption(
8556   - label + " " + rule.selectorText,
8557   - function () {
8558   - return rgb2hex(value);
8559   - },
8560   - mxUtils.bind(this, function (color) {
8561   - rules[ruleIndex].style[key] = color;
8562   - var cssTxt = "";
8563   -
8564   - for (var i = 0; i < rules.length; i++) {
8565   - cssTxt += rules[i].cssText + " ";
8566   - }
8567   -
8568   - styleElem.textContent = cssTxt;
8569   - var xml = mxUtils.getXml(svg.documentElement);
8570   -
8571   - graph.setCellStyles(
8572   - mxConstants.STYLE_IMAGE,
8573   - "data:image/svg+xml," +
8574   - (window.btoa ? btoa(xml) : Base64.encode(xml, true)),
8575   - ui.getSelectionState().cells,
8576   - );
8577   - }),
8578   - "#ffffff",
8579   - {
8580   - install: function (apply) {
8581   - // ignore
8582   - },
8583   - destroy: function () {
8584   - // ignore
8585   - },
8586   - },
8587   - );
8588   -
8589   - container.appendChild(option);
8590   -
8591   - // Shows container if rules are added
8592   - container.style.display = "";
8593   - }
8594   - });
8595   -
8596   - addStyleRule(rule, "fill", mxResources.get("fill"));
8597   - addStyleRule(rule, "stroke", mxResources.get("line"));
8598   - addStyleRule(rule, "stop-color", mxResources.get("gradient"));
8599   - }
8600   -};
8601   -
8602   -/**
8603   - * Adds the label menu items to the given menu and parent.
8604   - */
8605   -StyleFormatPanel.prototype.addEditOps = function (div) {
8606   - var ss = this.editorUi.getSelectionState();
8607   - var btn = null;
8608   -
8609   - if (ss.cells.length == 1) {
8610   - btn = mxUtils.button(
8611   - mxResources.get("editStyle"),
8612   - mxUtils.bind(this, function (evt) {
8613   - this.editorUi.actions.get("editStyle").funct();
8614   - }),
8615   - );
8616   -
8617   - btn.setAttribute(
8618   - "title",
8619   - mxResources.get("editStyle") +
8620   - " (" +
8621   - this.editorUi.actions.get("editStyle").shortcut +
8622   - ")",
8623   - );
8624   - btn.style.width = "210px";
8625   - btn.style.marginBottom = "2px";
8626   -
8627   - div.appendChild(btn);
8628   - }
8629   -
8630   - if (ss.image && ss.cells.length > 0) {
8631   - var btn2 = mxUtils.button(
8632   - mxResources.get("editImage"),
8633   - mxUtils.bind(this, function (evt) {
8634   - this.editorUi.actions.get("image").funct();
8635   - }),
8636   - );
8637   -
8638   - btn2.setAttribute("title", mxResources.get("editImage"));
8639   - btn2.style.marginBottom = "2px";
8640   -
8641   - if (btn == null) {
8642   - btn2.style.width = "210px";
8643   - } else {
8644   - btn.style.width = "104px";
8645   - btn2.style.width = "104px";
8646   - btn2.style.marginLeft = "2px";
8647   - }
8648   -
8649   - div.appendChild(btn2);
8650   - }
8651   -
8652   - return div;
8653   -};
8654   -
8655   -/**
8656   - * Adds the label menu items to the given menu and parent.
8657   - */
8658   -StyleFormatPanel.prototype.addFill = function (container) {
8659   - var ui = this.editorUi;
8660   - var graph = ui.editor.graph;
8661   - var ss = ui.getSelectionState();
8662   - container.style.paddingTop = "6px";
8663   - container.style.paddingBottom = "6px";
8664   -
8665   - // Adds gradient direction option
8666   - var gradientSelect = document.createElement("select");
8667   - gradientSelect.style.position = "absolute";
8668   - gradientSelect.style.left = "104px";
8669   - gradientSelect.style.width = "70px";
8670   - gradientSelect.style.height = "22px";
8671   - gradientSelect.style.padding = "0px";
8672   - gradientSelect.style.marginTop = "-3px";
8673   - gradientSelect.style.borderRadius = "4px";
8674   - gradientSelect.style.border = "1px solid rgb(160, 160, 160)";
8675   - gradientSelect.style.boxSizing = "border-box";
8676   -
8677   - var fillStyleSelect = gradientSelect.cloneNode(false);
8678   -
8679   - // Stops events from bubbling to color option event handler
8680   - mxEvent.addListener(gradientSelect, "click", function (evt) {
8681   - mxEvent.consume(evt);
8682   - });
8683   - mxEvent.addListener(fillStyleSelect, "click", function (evt) {
8684   - mxEvent.consume(evt);
8685   - });
8686   -
8687   - var defs =
8688   - ss.vertices.length >= 1
8689   - ? graph.stylesheet.getDefaultVertexStyle()
8690   - : graph.stylesheet.getDefaultEdgeStyle();
8691   -
8692   - var gradientPanel = this.createCellColorOption(
8693   - mxResources.get("gradient"),
8694   - mxConstants.STYLE_GRADIENTCOLOR,
8695   - defs[mxConstants.STYLE_GRADIENTCOLOR] != null
8696   - ? defs[mxConstants.STYLE_GRADIENTCOLOR]
8697   - : "#ffffff",
8698   - function (color) {
8699   - if (color == null || color == mxConstants.NONE) {
8700   - gradientSelect.style.display = "none";
8701   - } else {
8702   - gradientSelect.style.display = "";
8703   - }
8704   - },
8705   - function (color) {
8706   - graph.updateCellStyles(
8707   - { gradientColor: color },
8708   - graph.getSelectionCells(),
8709   - );
8710   - },
8711   - );
8712   -
8713   - var fillKey =
8714   - ss.style.shape == "image"
8715   - ? mxConstants.STYLE_IMAGE_BACKGROUND
8716   - : mxConstants.STYLE_FILLCOLOR;
8717   -
8718   - var fillPanel = this.createCellColorOption(
8719   - mxResources.get("fill"),
8720   - fillKey,
8721   - "default",
8722   - null,
8723   - mxUtils.bind(this, function (color) {
8724   - graph.setCellStyles(fillKey, color, ss.cells);
8725   - }),
8726   - graph.shapeBackgroundColor,
8727   - );
8728   -
8729   - fillPanel.style.fontWeight = "bold";
8730   - var tmpColor = mxUtils.getValue(ss.style, fillKey, null);
8731   - gradientPanel.style.display =
8732   - tmpColor != null &&
8733   - tmpColor != mxConstants.NONE &&
8734   - ss.fill &&
8735   - ss.style.shape != "image"
8736   - ? ""
8737   - : "none";
8738   -
8739   - var directions = [
8740   - mxConstants.DIRECTION_NORTH,
8741   - mxConstants.DIRECTION_EAST,
8742   - mxConstants.DIRECTION_SOUTH,
8743   - mxConstants.DIRECTION_WEST,
8744   - mxConstants.DIRECTION_RADIAL,
8745   - ];
8746   -
8747   - for (var i = 0; i < directions.length; i++) {
8748   - var gradientOption = document.createElement("option");
8749   - gradientOption.setAttribute("value", directions[i]);
8750   - mxUtils.write(gradientOption, mxResources.get(directions[i]));
8751   - gradientSelect.appendChild(gradientOption);
8752   - }
8753   -
8754   - gradientPanel.appendChild(gradientSelect);
8755   -
8756   - for (var i = 0; i < Editor.roughFillStyles.length; i++) {
8757   - var fillStyleOption = document.createElement("option");
8758   - fillStyleOption.setAttribute("value", Editor.roughFillStyles[i].val);
8759   - mxUtils.write(fillStyleOption, Editor.roughFillStyles[i].dispName);
8760   - fillStyleSelect.appendChild(fillStyleOption);
8761   - }
8762   -
8763   - fillPanel.appendChild(fillStyleSelect);
8764   -
8765   - var listener = mxUtils.bind(this, function () {
8766   - ss = ui.getSelectionState();
8767   - var value = mxUtils.getValue(
8768   - ss.style,
8769   - mxConstants.STYLE_GRADIENT_DIRECTION,
8770   - mxConstants.DIRECTION_SOUTH,
8771   - );
8772   - var fillStyle = mxUtils.getValue(ss.style, "fillStyle", "auto");
8773   -
8774   - // Handles empty string which is not allowed as a value
8775   - if (value == "") {
8776   - value = mxConstants.DIRECTION_SOUTH;
8777   - }
8778   -
8779   - gradientSelect.value = value;
8780   - fillStyleSelect.value = fillStyle;
8781   - container.style.display = ss.fill ? "" : "none";
8782   -
8783   - var fillColor = mxUtils.getValue(ss.style, fillKey, null);
8784   -
8785   - if (
8786   - !ss.fill ||
8787   - fillColor == null ||
8788   - fillColor == mxConstants.NONE ||
8789   - ss.style.shape == "filledEdge"
8790   - ) {
8791   - fillStyleSelect.style.display = "none";
8792   - gradientPanel.style.display = "none";
8793   - } else {
8794   - fillStyleSelect.style.display = ss.style.sketch == "1" ? "" : "none";
8795   - gradientPanel.style.display =
8796   - !ss.containsImage &&
8797   - (ss.style.sketch != "1" || fillStyle == "solid" || fillStyle == "auto")
8798   - ? ""
8799   - : "none";
8800   - }
8801   - });
8802   -
8803   - graph.getModel().addListener(mxEvent.CHANGE, listener);
8804   - this.listeners.push({
8805   - destroy: function () {
8806   - graph.getModel().removeListener(listener);
8807   - },
8808   - });
8809   - listener();
8810   -
8811   - mxEvent.addListener(gradientSelect, "change", function (evt) {
8812   - graph.setCellStyles(
8813   - mxConstants.STYLE_GRADIENT_DIRECTION,
8814   - gradientSelect.value,
8815   - ss.cells,
8816   - );
8817   - ui.fireEvent(
8818   - new mxEventObject(
8819   - "styleChanged",
8820   - "keys",
8821   - [mxConstants.STYLE_GRADIENT_DIRECTION],
8822   - "values",
8823   - [gradientSelect.value],
8824   - "cells",
8825   - ss.cells,
8826   - ),
8827   - );
8828   - mxEvent.consume(evt);
8829   - });
8830   -
8831   - mxEvent.addListener(fillStyleSelect, "change", function (evt) {
8832   - graph.setCellStyles("fillStyle", fillStyleSelect.value, ss.cells);
8833   - ui.fireEvent(
8834   - new mxEventObject(
8835   - "styleChanged",
8836   - "keys",
8837   - ["fillStyle"],
8838   - "values",
8839   - [fillStyleSelect.value],
8840   - "cells",
8841   - ss.cells,
8842   - ),
8843   - );
8844   - mxEvent.consume(evt);
8845   - });
8846   -
8847   - container.appendChild(fillPanel);
8848   - container.appendChild(gradientPanel);
8849   -
8850   - // Adds custom colors
8851   - var custom = this.getCustomColors();
8852   -
8853   - for (var i = 0; i < custom.length; i++) {
8854   - container.appendChild(
8855   - this.createCellColorOption(
8856   - custom[i].title,
8857   - custom[i].key,
8858   - custom[i].defaultValue,
8859   - ),
8860   - );
8861   - }
8862   -
8863   - return container;
8864   -};
8865   -
8866   -/**
8867   - * Adds the label menu items to the given menu and parent.
8868   - */
8869   -StyleFormatPanel.prototype.getCustomColors = function () {
8870   - var ss = this.editorUi.getSelectionState();
8871   - var result = [];
8872   -
8873   - if (ss.swimlane) {
8874   - result.push({
8875   - title: mxResources.get("laneColor"),
8876   - key: "swimlaneFillColor",
8877   - defaultValue: "default",
8878   - });
8879   - }
8880   -
8881   - return result;
8882   -};
8883   -
8884   -/**
8885   - * Adds the label menu items to the given menu and parent.
8886   - */
8887   -StyleFormatPanel.prototype.addStroke = function (container) {
8888   - var ui = this.editorUi;
8889   - var graph = ui.editor.graph;
8890   - var ss = ui.getSelectionState();
8891   -
8892   - container.style.paddingTop = "6px";
8893   - container.style.paddingBottom = "4px";
8894   - container.style.whiteSpace = "normal";
8895   -
8896   - var colorPanel = document.createElement("div");
8897   - colorPanel.style.fontWeight = "bold";
8898   -
8899   - if (!ss.stroke) {
8900   - colorPanel.style.display = "none";
8901   - }
8902   -
8903   - // Adds gradient direction option
8904   - var styleSelect = document.createElement("select");
8905   - styleSelect.style.position = "absolute";
8906   - styleSelect.style.height = "22px";
8907   - styleSelect.style.padding = "0px";
8908   - styleSelect.style.marginTop = "-3px";
8909   - styleSelect.style.boxSizing = "border-box";
8910   - styleSelect.style.left = "94px";
8911   - styleSelect.style.width = "80px";
8912   - styleSelect.style.border = "1px solid rgb(160, 160, 160)";
8913   - styleSelect.style.borderRadius = "4px";
8914   -
8915   - var styles = ["sharp", "rounded", "curved"];
8916   -
8917   - for (var i = 0; i < styles.length; i++) {
8918   - var styleOption = document.createElement("option");
8919   - styleOption.setAttribute("value", styles[i]);
8920   - mxUtils.write(styleOption, mxResources.get(styles[i]));
8921   - styleSelect.appendChild(styleOption);
8922   - }
8923   -
8924   - mxEvent.addListener(styleSelect, "change", function (evt) {
8925   - graph.getModel().beginUpdate();
8926   - try {
8927   - var keys = [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED];
8928   - // Default for rounded is 1
8929   - var values = ["0", null];
8930   -
8931   - if (styleSelect.value == "rounded") {
8932   - values = ["1", null];
8933   - } else if (styleSelect.value == "curved") {
8934   - values = [null, "1"];
8935   - }
8936   -
8937   - for (var i = 0; i < keys.length; i++) {
8938   - graph.setCellStyles(keys[i], values[i], ss.cells);
8939   - }
8940   -
8941   - ui.fireEvent(
8942   - new mxEventObject(
8943   - "styleChanged",
8944   - "keys",
8945   - keys,
8946   - "values",
8947   - values,
8948   - "cells",
8949   - ss.cells,
8950   - ),
8951   - );
8952   - } finally {
8953   - graph.getModel().endUpdate();
8954   - }
8955   -
8956   - mxEvent.consume(evt);
8957   - });
8958   -
8959   - // Stops events from bubbling to color option event handler
8960   - mxEvent.addListener(styleSelect, "click", function (evt) {
8961   - mxEvent.consume(evt);
8962   - });
8963   -
8964   - var strokeKey =
8965   - ss.style.shape == "image"
8966   - ? mxConstants.STYLE_IMAGE_BORDER
8967   - : mxConstants.STYLE_STROKECOLOR;
8968   - var label =
8969   - ss.style.shape == "image"
8970   - ? mxResources.get("border")
8971   - : mxResources.get("line");
8972   -
8973   - var lineColor = this.createCellColorOption(
8974   - label,
8975   - strokeKey,
8976   - "default",
8977   - null,
8978   - mxUtils.bind(this, function (color) {
8979   - graph.setCellStyles(strokeKey, color, ss.cells);
8980   - }),
8981   - graph.shapeForegroundColor,
8982   - );
8983   -
8984   - lineColor.appendChild(styleSelect);
8985   - colorPanel.appendChild(lineColor);
8986   -
8987   - // Used if only edges selected
8988   - var stylePanel = colorPanel.cloneNode(false);
8989   - stylePanel.style.fontWeight = "normal";
8990   - stylePanel.style.whiteSpace = "nowrap";
8991   - stylePanel.style.position = "relative";
8992   - stylePanel.style.paddingLeft = "0px";
8993   - stylePanel.style.marginBottom = "2px";
8994   - stylePanel.style.overflow = "hidden";
8995   - stylePanel.style.marginTop = "2px";
8996   - stylePanel.style.width = "220px";
8997   - stylePanel.className = "geToolbarContainer";
8998   -
8999   - var addItem = mxUtils.bind(
9000   - this,
9001   - function (menu, width, cssName, keys, values) {
9002   - var item = this.editorUi.menus.styleChange(
9003   - menu,
9004   - "",
9005   - keys,
9006   - values,
9007   - "geIcon",
9008   - null,
9009   - );
9010   -
9011   - var pat = document.createElement("div");
9012   - pat.style.width = width + "px";
9013   - pat.style.height = "1px";
9014   - pat.style.borderBottom = "1px " + cssName + " " + this.defaultStrokeColor;
9015   - pat.style.paddingTop = "6px";
9016   -
9017   - item.firstChild.firstChild.style.padding = "0px 4px 0px 4px";
9018   - item.firstChild.firstChild.style.width = width + "px";
9019   - item.firstChild.firstChild.appendChild(pat);
9020   -
9021   - return item;
9022   - },
9023   - );
9024   -
9025   - var pattern = this.editorUi.toolbar.addMenuFunctionInContainer(
9026   - stylePanel,
9027   - "geSprite-orthogonal",
9028   - mxResources.get("pattern"),
9029   - false,
9030   - mxUtils.bind(this, function (menu) {
9031   - addItem(
9032   - menu,
9033   - 75,
9034   - "solid",
9035   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9036   - [null, null],
9037   - ).setAttribute("title", mxResources.get("solid"));
9038   - addItem(
9039   - menu,
9040   - 75,
9041   - "dashed",
9042   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9043   - ["1", null],
9044   - ).setAttribute("title", mxResources.get("dashed"));
9045   - addItem(
9046   - menu,
9047   - 75,
9048   - "dotted",
9049   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9050   - ["1", "1 1"],
9051   - ).setAttribute("title", mxResources.get("dotted") + " (1)");
9052   - addItem(
9053   - menu,
9054   - 75,
9055   - "dotted",
9056   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9057   - ["1", "1 2"],
9058   - ).setAttribute("title", mxResources.get("dotted") + " (2)");
9059   - addItem(
9060   - menu,
9061   - 75,
9062   - "dotted",
9063   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9064   - ["1", "1 4"],
9065   - ).setAttribute("title", mxResources.get("dotted") + " (3)");
9066   - }),
9067   - );
9068   -
9069   - // Used for mixed selection (vertices and edges)
9070   - var altStylePanel = stylePanel.cloneNode(false);
9071   -
9072   - var edgeShape = this.editorUi.toolbar.addMenuFunctionInContainer(
9073   - altStylePanel,
9074   - "geSprite-connection",
9075   - mxResources.get("connection"),
9076   - false,
9077   - mxUtils.bind(this, function (menu) {
9078   - this.editorUi.menus
9079   - .styleChange(
9080   - menu,
9081   - "",
9082   - [
9083   - mxConstants.STYLE_SHAPE,
9084   - mxConstants.STYLE_STARTSIZE,
9085   - mxConstants.STYLE_ENDSIZE,
9086   - "width",
9087   - ],
9088   - [null, null, null, null],
9089   - "geIcon geSprite geSprite-connection",
9090   - null,
9091   - true,
9092   - )
9093   - .setAttribute("title", mxResources.get("line"));
9094   - this.editorUi.menus
9095   - .styleChange(
9096   - menu,
9097   - "",
9098   - [
9099   - mxConstants.STYLE_SHAPE,
9100   - mxConstants.STYLE_STARTSIZE,
9101   - mxConstants.STYLE_ENDSIZE,
9102   - "width",
9103   - ],
9104   - ["link", null, null, null],
9105   - "geIcon geSprite geSprite-linkedge",
9106   - null,
9107   - true,
9108   - )
9109   - .setAttribute("title", mxResources.get("link"));
9110   - this.editorUi.menus
9111   - .styleChange(
9112   - menu,
9113   - "",
9114   - [
9115   - mxConstants.STYLE_SHAPE,
9116   - mxConstants.STYLE_STARTSIZE,
9117   - mxConstants.STYLE_ENDSIZE,
9118   - "width",
9119   - ],
9120   - ["flexArrow", null, null, null],
9121   - "geIcon geSprite geSprite-arrow",
9122   - null,
9123   - true,
9124   - )
9125   - .setAttribute("title", mxResources.get("arrow"));
9126   - this.editorUi.menus
9127   - .styleChange(
9128   - menu,
9129   - "",
9130   - [
9131   - mxConstants.STYLE_SHAPE,
9132   - mxConstants.STYLE_STARTSIZE,
9133   - mxConstants.STYLE_ENDSIZE,
9134   - "width",
9135   - ],
9136   - ["arrow", null, null, null],
9137   - "geIcon geSprite geSprite-simplearrow",
9138   - null,
9139   - true,
9140   - )
9141   - .setAttribute("title", mxResources.get("simpleArrow"));
9142   - }),
9143   - );
9144   -
9145   - var altPattern = this.editorUi.toolbar.addMenuFunctionInContainer(
9146   - altStylePanel,
9147   - "geSprite-orthogonal",
9148   - mxResources.get("pattern"),
9149   - false,
9150   - mxUtils.bind(this, function (menu) {
9151   - addItem(
9152   - menu,
9153   - 33,
9154   - "solid",
9155   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9156   - [null, null],
9157   - ).setAttribute("title", mxResources.get("solid"));
9158   - addItem(
9159   - menu,
9160   - 33,
9161   - "dashed",
9162   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9163   - ["1", null],
9164   - ).setAttribute("title", mxResources.get("dashed"));
9165   - addItem(
9166   - menu,
9167   - 33,
9168   - "dotted",
9169   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9170   - ["1", "1 1"],
9171   - ).setAttribute("title", mxResources.get("dotted") + " (1)");
9172   - addItem(
9173   - menu,
9174   - 33,
9175   - "dotted",
9176   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9177   - ["1", "1 2"],
9178   - ).setAttribute("title", mxResources.get("dotted") + " (2)");
9179   - addItem(
9180   - menu,
9181   - 33,
9182   - "dotted",
9183   - [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
9184   - ["1", "1 4"],
9185   - ).setAttribute("title", mxResources.get("dotted") + " (3)");
9186   - }),
9187   - );
9188   -
9189   - var stylePanel2 = stylePanel.cloneNode(false);
9190   -
9191   - // Stroke width
9192   - var input = document.createElement("input");
9193   - input.style.position = "absolute";
9194   - input.style.textAlign = "right";
9195   - input.style.marginTop = "2px";
9196   - input.style.width = "52px";
9197   - input.style.height = "21px";
9198   - input.style.left = "146px";
9199   - input.style.border = "1px solid rgb(160, 160, 160)";
9200   - input.style.borderRadius = "4px";
9201   - input.style.boxSizing = "border-box";
9202   - input.setAttribute("title", mxResources.get("linewidth"));
9203   -
9204   - stylePanel.appendChild(input);
9205   -
9206   - var altInput = input.cloneNode(true);
9207   - altStylePanel.appendChild(altInput);
9208   -
9209   - function update(evt) {
9210   - // Maximum stroke width is 999
9211   - var value = parseFloat(input.value);
9212   - value = Math.min(999, Math.max(0, isNaN(value) ? 1 : value));
9213   -
9214   - if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)) {
9215   - graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
9216   - ui.fireEvent(
9217   - new mxEventObject(
9218   - "styleChanged",
9219   - "keys",
9220   - [mxConstants.STYLE_STROKEWIDTH],
9221   - "values",
9222   - [value],
9223   - "cells",
9224   - ss.cells,
9225   - ),
9226   - );
9227   - }
9228   -
9229   - input.value = value + " pt";
9230   - mxEvent.consume(evt);
9231   - }
9232   -
9233   - function altUpdate(evt) {
9234   - // Maximum stroke width is 999
9235   - var value = parseFloat(altInput.value);
9236   - value = Math.min(999, Math.max(0, isNaN(value) ? 1 : value));
9237   -
9238   - if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)) {
9239   - graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
9240   - ui.fireEvent(
9241   - new mxEventObject(
9242   - "styleChanged",
9243   - "keys",
9244   - [mxConstants.STYLE_STROKEWIDTH],
9245   - "values",
9246   - [value],
9247   - "cells",
9248   - ss.cells,
9249   - ),
9250   - );
9251   - }
9252   -
9253   - altInput.value = value + " pt";
9254   - mxEvent.consume(evt);
9255   - }
9256   -
9257   - var stepper = this.createStepper(input, update, 1, 9);
9258   - stepper.style.display = input.style.display;
9259   - stepper.style.marginTop = "2px";
9260   - stepper.style.left = "198px";
9261   - stylePanel.appendChild(stepper);
9262   -
9263   - var altStepper = this.createStepper(altInput, altUpdate, 1, 9);
9264   - altStepper.style.display = altInput.style.display;
9265   - altStepper.style.marginTop = "2px";
9266   - altInput.style.position = "absolute";
9267   - altStepper.style.left = "198px";
9268   - altStylePanel.appendChild(altStepper);
9269   -
9270   - mxEvent.addListener(input, "blur", update);
9271   - mxEvent.addListener(input, "change", update);
9272   -
9273   - mxEvent.addListener(altInput, "blur", altUpdate);
9274   - mxEvent.addListener(altInput, "change", altUpdate);
9275   -
9276   - var edgeStyle = this.editorUi.toolbar.addMenuFunctionInContainer(
9277   - stylePanel2,
9278   - "geSprite-orthogonal",
9279   - mxResources.get("waypoints"),
9280   - false,
9281   - mxUtils.bind(this, function (menu) {
9282   - if (ss.style.shape != "arrow") {
9283   - this.editorUi.menus
9284   - .edgeStyleChange(
9285   - menu,
9286   - "",
9287   - [
9288   - mxConstants.STYLE_EDGE,
9289   - mxConstants.STYLE_CURVED,
9290   - mxConstants.STYLE_NOEDGESTYLE,
9291   - ],
9292   - [null, null, null],
9293   - "geIcon geSprite geSprite-straight",
9294   - null,
9295   - true,
9296   - )
9297   - .setAttribute("title", mxResources.get("straight"));
9298   - this.editorUi.menus
9299   - .edgeStyleChange(
9300   - menu,
9301   - "",
9302   - [
9303   - mxConstants.STYLE_EDGE,
9304   - mxConstants.STYLE_CURVED,
9305   - mxConstants.STYLE_NOEDGESTYLE,
9306   - ],
9307   - ["orthogonalEdgeStyle", null, null],
9308   - "geIcon geSprite geSprite-orthogonal",
9309   - null,
9310   - true,
9311   - )
9312   - .setAttribute("title", mxResources.get("orthogonal"));
9313   - this.editorUi.menus
9314   - .edgeStyleChange(
9315   - menu,
9316   - "",
9317   - [
9318   - mxConstants.STYLE_EDGE,
9319   - mxConstants.STYLE_ELBOW,
9320   - mxConstants.STYLE_CURVED,
9321   - mxConstants.STYLE_NOEDGESTYLE,
9322   - ],
9323   - ["elbowEdgeStyle", null, null, null],
9324   - "geIcon geSprite geSprite-horizontalelbow",
9325   - null,
9326   - true,
9327   - )
9328   - .setAttribute("title", mxResources.get("simple"));
9329   - this.editorUi.menus
9330   - .edgeStyleChange(
9331   - menu,
9332   - "",
9333   - [
9334   - mxConstants.STYLE_EDGE,
9335   - mxConstants.STYLE_ELBOW,
9336   - mxConstants.STYLE_CURVED,
9337   - mxConstants.STYLE_NOEDGESTYLE,
9338   - ],
9339   - ["elbowEdgeStyle", "vertical", null, null],
9340   - "geIcon geSprite geSprite-verticalelbow",
9341   - null,
9342   - true,
9343   - )
9344   - .setAttribute("title", mxResources.get("simple"));
9345   - this.editorUi.menus
9346   - .edgeStyleChange(
9347   - menu,
9348   - "",
9349   - [
9350   - mxConstants.STYLE_EDGE,
9351   - mxConstants.STYLE_ELBOW,
9352   - mxConstants.STYLE_CURVED,
9353   - mxConstants.STYLE_NOEDGESTYLE,
9354   - ],
9355   - ["isometricEdgeStyle", null, null, null],
9356   - "geIcon geSprite geSprite-horizontalisometric",
9357   - null,
9358   - true,
9359   - )
9360   - .setAttribute("title", mxResources.get("isometric"));
9361   - this.editorUi.menus
9362   - .edgeStyleChange(
9363   - menu,
9364   - "",
9365   - [
9366   - mxConstants.STYLE_EDGE,
9367   - mxConstants.STYLE_ELBOW,
9368   - mxConstants.STYLE_CURVED,
9369   - mxConstants.STYLE_NOEDGESTYLE,
9370   - ],
9371   - ["isometricEdgeStyle", "vertical", null, null],
9372   - "geIcon geSprite geSprite-verticalisometric",
9373   - null,
9374   - true,
9375   - )
9376   - .setAttribute("title", mxResources.get("isometric"));
9377   -
9378   - if (ss.style.shape == "connector") {
9379   - this.editorUi.menus
9380   - .edgeStyleChange(
9381   - menu,
9382   - "",
9383   - [
9384   - mxConstants.STYLE_EDGE,
9385   - mxConstants.STYLE_CURVED,
9386   - mxConstants.STYLE_NOEDGESTYLE,
9387   - ],
9388   - ["orthogonalEdgeStyle", "1", null],
9389   - "geIcon geSprite geSprite-curved",
9390   - null,
9391   - true,
9392   - )
9393   - .setAttribute("title", mxResources.get("curved"));
9394   - }
9395   -
9396   - this.editorUi.menus
9397   - .edgeStyleChange(
9398   - menu,
9399   - "",
9400   - [
9401   - mxConstants.STYLE_EDGE,
9402   - mxConstants.STYLE_CURVED,
9403   - mxConstants.STYLE_NOEDGESTYLE,
9404   - ],
9405   - ["entityRelationEdgeStyle", null, null],
9406   - "geIcon geSprite geSprite-entity",
9407   - null,
9408   - true,
9409   - )
9410   - .setAttribute("title", mxResources.get("entityRelation"));
9411   - }
9412   - }),
9413   - );
9414   -
9415   - var lineStart = this.editorUi.toolbar.addMenuFunctionInContainer(
9416   - stylePanel2,
9417   - "geSprite-startclassic",
9418   - mxResources.get("linestart"),
9419   - false,
9420   - mxUtils.bind(this, function (menu) {
9421   - if (
9422   - ss.style.shape == "connector" ||
9423   - ss.style.shape == "flexArrow" ||
9424   - ss.style.shape == "filledEdge"
9425   - ) {
9426   - var item = this.editorUi.menus.edgeStyleChange(
9427   - menu,
9428   - "",
9429   - [mxConstants.STYLE_STARTARROW, "startFill"],
9430   - [mxConstants.NONE, 0],
9431   - "geIcon",
9432   - null,
9433   - false,
9434   - );
9435   - item.setAttribute("title", mxResources.get("none"));
9436   -
9437   - var font = document.createElement("font");
9438   - font.style.fontSize = "10px";
9439   - mxUtils.write(font, mxResources.get("none"));
9440   - item.firstChild.firstChild.appendChild(font);
9441   -
9442   - if (ss.style.shape == "connector" || ss.style.shape == "filledEdge") {
9443   - Format.processMenuIcon(
9444   - this.editorUi.menus.edgeStyleChange(
9445   - menu,
9446   - "",
9447   - [mxConstants.STYLE_STARTARROW, "startFill"],
9448   - [mxConstants.ARROW_CLASSIC, 1],
9449   - null,
9450   - null,
9451   - false,
9452   - Format.classicFilledMarkerImage.src,
9453   - ),
9454   - );
9455   - Format.processMenuIcon(
9456   - this.editorUi.menus.edgeStyleChange(
9457   - menu,
9458   - "",
9459   - [mxConstants.STYLE_STARTARROW, "startFill"],
9460   - [mxConstants.ARROW_CLASSIC_THIN, 1],
9461   - null,
9462   - null,
9463   - false,
9464   - Format.classicThinFilledMarkerImage.src,
9465   - ),
9466   - );
9467   - Format.processMenuIcon(
9468   - this.editorUi.menus.edgeStyleChange(
9469   - menu,
9470   - "",
9471   - [mxConstants.STYLE_STARTARROW, "startFill"],
9472   - [mxConstants.ARROW_OPEN, 0],
9473   - null,
9474   - null,
9475   - false,
9476   - Format.openFilledMarkerImage.src,
9477   - ),
9478   - );
9479   - Format.processMenuIcon(
9480   - this.editorUi.menus.edgeStyleChange(
9481   - menu,
9482   - "",
9483   - [mxConstants.STYLE_STARTARROW, "startFill"],
9484   - [mxConstants.ARROW_OPEN_THIN, 0],
9485   - null,
9486   - null,
9487   - false,
9488   - Format.openThinFilledMarkerImage.src,
9489   - ),
9490   - );
9491   - Format.processMenuIcon(
9492   - this.editorUi.menus.edgeStyleChange(
9493   - menu,
9494   - "",
9495   - [mxConstants.STYLE_STARTARROW, "startFill"],
9496   - ["openAsync", 0],
9497   - null,
9498   - null,
9499   - false,
9500   - Format.openAsyncFilledMarkerImage.src,
9501   - ),
9502   - );
9503   - Format.processMenuIcon(
9504   - this.editorUi.menus.edgeStyleChange(
9505   - menu,
9506   - "",
9507   - [mxConstants.STYLE_STARTARROW, "startFill"],
9508   - [mxConstants.ARROW_BLOCK, 1],
9509   - null,
9510   - null,
9511   - false,
9512   - Format.blockFilledMarkerImage.src,
9513   - ),
9514   - );
9515   - Format.processMenuIcon(
9516   - this.editorUi.menus.edgeStyleChange(
9517   - menu,
9518   - "",
9519   - [mxConstants.STYLE_STARTARROW, "startFill"],
9520   - [mxConstants.ARROW_BLOCK_THIN, 1],
9521   - null,
9522   - null,
9523   - false,
9524   - Format.blockThinFilledMarkerImage.src,
9525   - ),
9526   - );
9527   - Format.processMenuIcon(
9528   - this.editorUi.menus.edgeStyleChange(
9529   - menu,
9530   - "",
9531   - [mxConstants.STYLE_STARTARROW, "startFill"],
9532   - ["async", 1],
9533   - null,
9534   - null,
9535   - false,
9536   - Format.asyncFilledMarkerImage.src,
9537   - ),
9538   - );
9539   - Format.processMenuIcon(
9540   - this.editorUi.menus.edgeStyleChange(
9541   - menu,
9542   - "",
9543   - [mxConstants.STYLE_STARTARROW, "startFill"],
9544   - [mxConstants.ARROW_OVAL, 1],
9545   - null,
9546   - null,
9547   - false,
9548   - Format.ovalFilledMarkerImage.src,
9549   - ),
9550   - );
9551   - Format.processMenuIcon(
9552   - this.editorUi.menus.edgeStyleChange(
9553   - menu,
9554   - "",
9555   - [mxConstants.STYLE_STARTARROW, "startFill"],
9556   - [mxConstants.ARROW_DIAMOND, 1],
9557   - null,
9558   - null,
9559   - false,
9560   - Format.diamondFilledMarkerImage.src,
9561   - ),
9562   - );
9563   - Format.processMenuIcon(
9564   - this.editorUi.menus.edgeStyleChange(
9565   - menu,
9566   - "",
9567   - [mxConstants.STYLE_STARTARROW, "startFill"],
9568   - [mxConstants.ARROW_DIAMOND_THIN, 1],
9569   - null,
9570   - null,
9571   - false,
9572   - Format.diamondThinFilledMarkerImage.src,
9573   - ),
9574   - );
9575   - Format.processMenuIcon(
9576   - this.editorUi.menus.edgeStyleChange(
9577   - menu,
9578   - "",
9579   - [mxConstants.STYLE_STARTARROW, "startFill"],
9580   - [mxConstants.ARROW_CLASSIC, 0],
9581   - null,
9582   - null,
9583   - false,
9584   - Format.classicMarkerImage.src,
9585   - ),
9586   - );
9587   - Format.processMenuIcon(
9588   - this.editorUi.menus.edgeStyleChange(
9589   - menu,
9590   - "",
9591   - [mxConstants.STYLE_STARTARROW, "startFill"],
9592   - [mxConstants.ARROW_CLASSIC_THIN, 0],
9593   - null,
9594   - null,
9595   - false,
9596   - Format.classicThinMarkerImage.src,
9597   - ),
9598   - );
9599   - Format.processMenuIcon(
9600   - this.editorUi.menus.edgeStyleChange(
9601   - menu,
9602   - "",
9603   - [mxConstants.STYLE_STARTARROW, "startFill"],
9604   - [mxConstants.ARROW_BLOCK, 0],
9605   - null,
9606   - null,
9607   - false,
9608   - Format.blockMarkerImage.src,
9609   - ),
9610   - );
9611   - Format.processMenuIcon(
9612   - this.editorUi.menus.edgeStyleChange(
9613   - menu,
9614   - "",
9615   - [mxConstants.STYLE_STARTARROW, "startFill"],
9616   - [mxConstants.ARROW_BLOCK_THIN, 0],
9617   - null,
9618   - null,
9619   - false,
9620   - Format.blockThinMarkerImage.src,
9621   - ),
9622   - );
9623   - Format.processMenuIcon(
9624   - this.editorUi.menus.edgeStyleChange(
9625   - menu,
9626   - "",
9627   - [mxConstants.STYLE_STARTARROW, "startFill"],
9628   - ["async", 0],
9629   - null,
9630   - null,
9631   - false,
9632   - Format.asyncMarkerImage.src,
9633   - ),
9634   - );
9635   - Format.processMenuIcon(
9636   - this.editorUi.menus.edgeStyleChange(
9637   - menu,
9638   - "",
9639   - [mxConstants.STYLE_STARTARROW, "startFill"],
9640   - [mxConstants.ARROW_OVAL, 0],
9641   - null,
9642   - null,
9643   - false,
9644   - Format.ovalMarkerImage.src,
9645   - ),
9646   - );
9647   - Format.processMenuIcon(
9648   - this.editorUi.menus.edgeStyleChange(
9649   - menu,
9650   - "",
9651   - [mxConstants.STYLE_STARTARROW, "startFill"],
9652   - [mxConstants.ARROW_DIAMOND, 0],
9653   - null,
9654   - null,
9655   - false,
9656   - Format.diamondMarkerImage.src,
9657   - ),
9658   - );
9659   - Format.processMenuIcon(
9660   - this.editorUi.menus.edgeStyleChange(
9661   - menu,
9662   - "",
9663   - [mxConstants.STYLE_STARTARROW, "startFill"],
9664   - [mxConstants.ARROW_DIAMOND_THIN, 0],
9665   - null,
9666   - null,
9667   - false,
9668   - Format.diamondThinMarkerImage.src,
9669   - ),
9670   - );
9671   - Format.processMenuIcon(
9672   - this.editorUi.menus.edgeStyleChange(
9673   - menu,
9674   - "",
9675   - [mxConstants.STYLE_STARTARROW, "startFill"],
9676   - ["box", 0],
9677   - null,
9678   - null,
9679   - false,
9680   - Format.boxMarkerImage.src,
9681   - ),
9682   - );
9683   - Format.processMenuIcon(
9684   - this.editorUi.menus.edgeStyleChange(
9685   - menu,
9686   - "",
9687   - [mxConstants.STYLE_STARTARROW, "startFill"],
9688   - ["halfCircle", 0],
9689   - null,
9690   - null,
9691   - false,
9692   - Format.halfCircleMarkerImage.src,
9693   - ),
9694   - );
9695   - Format.processMenuIcon(
9696   - this.editorUi.menus.edgeStyleChange(
9697   - menu,
9698   - "",
9699   - [mxConstants.STYLE_STARTARROW, "startFill"],
9700   - ["dash", 0],
9701   - null,
9702   - null,
9703   - false,
9704   - Format.dashMarkerImage.src,
9705   - ),
9706   - );
9707   - Format.processMenuIcon(
9708   - this.editorUi.menus.edgeStyleChange(
9709   - menu,
9710   - "",
9711   - [mxConstants.STYLE_STARTARROW, "startFill"],
9712   - ["cross", 0],
9713   - null,
9714   - null,
9715   - false,
9716   - Format.crossMarkerImage.src,
9717   - ),
9718   - );
9719   - Format.processMenuIcon(
9720   - this.editorUi.menus.edgeStyleChange(
9721   - menu,
9722   - "",
9723   - [mxConstants.STYLE_STARTARROW, "startFill"],
9724   - ["circlePlus", 0],
9725   - null,
9726   - null,
9727   - false,
9728   - Format.circlePlusMarkerImage.src,
9729   - ),
9730   - );
9731   - Format.processMenuIcon(
9732   - this.editorUi.menus.edgeStyleChange(
9733   - menu,
9734   - "",
9735   - [mxConstants.STYLE_STARTARROW, "startFill"],
9736   - ["circle", 1],
9737   - null,
9738   - null,
9739   - false,
9740   - Format.circleMarkerImage.src,
9741   - ),
9742   - );
9743   - Format.processMenuIcon(
9744   - this.editorUi.menus.edgeStyleChange(
9745   - menu,
9746   - "",
9747   - [mxConstants.STYLE_STARTARROW, "startFill"],
9748   - ["baseDash", 0],
9749   - null,
9750   - null,
9751   - false,
9752   - Format.baseDashMarkerImage.src,
9753   - ),
9754   - );
9755   - Format.processMenuIcon(
9756   - this.editorUi.menus.edgeStyleChange(
9757   - menu,
9758   - "",
9759   - [mxConstants.STYLE_STARTARROW, "startFill"],
9760   - ["ERone", 0],
9761   - null,
9762   - null,
9763   - false,
9764   - Format.EROneMarkerImage.src,
9765   - ),
9766   - );
9767   - Format.processMenuIcon(
9768   - this.editorUi.menus.edgeStyleChange(
9769   - menu,
9770   - "",
9771   - [mxConstants.STYLE_STARTARROW, "startFill"],
9772   - ["ERmandOne", 0],
9773   - null,
9774   - null,
9775   - false,
9776   - Format.ERmandOneMarkerImage.src,
9777   - ),
9778   - );
9779   - Format.processMenuIcon(
9780   - this.editorUi.menus.edgeStyleChange(
9781   - menu,
9782   - "",
9783   - [mxConstants.STYLE_STARTARROW, "startFill"],
9784   - ["ERmany", 0],
9785   - null,
9786   - null,
9787   - false,
9788   - Format.ERmanyMarkerImage.src,
9789   - ),
9790   - );
9791   - Format.processMenuIcon(
9792   - this.editorUi.menus.edgeStyleChange(
9793   - menu,
9794   - "",
9795   - [mxConstants.STYLE_STARTARROW, "startFill"],
9796   - ["ERoneToMany", 0],
9797   - null,
9798   - null,
9799   - false,
9800   - Format.ERoneToManyMarkerImage.src,
9801   - ),
9802   - );
9803   - Format.processMenuIcon(
9804   - this.editorUi.menus.edgeStyleChange(
9805   - menu,
9806   - "",
9807   - [mxConstants.STYLE_STARTARROW, "startFill"],
9808   - ["ERzeroToOne", 0],
9809   - null,
9810   - null,
9811   - false,
9812   - Format.ERzeroToOneMarkerImage.src,
9813   - ),
9814   - );
9815   - Format.processMenuIcon(
9816   - this.editorUi.menus.edgeStyleChange(
9817   - menu,
9818   - "",
9819   - [mxConstants.STYLE_STARTARROW, "startFill"],
9820   - ["ERzeroToMany", 0],
9821   - null,
9822   - null,
9823   - false,
9824   - Format.ERzeroToManyMarkerImage.src,
9825   - ),
9826   - );
9827   - Format.processMenuIcon(
9828   - this.editorUi.menus.edgeStyleChange(
9829   - menu,
9830   - "",
9831   - [mxConstants.STYLE_STARTARROW, "startFill"],
9832   - ["doubleBlock", 0],
9833   - null,
9834   - null,
9835   - false,
9836   - Format.doubleBlockMarkerImage.src,
9837   - ),
9838   - );
9839   - Format.processMenuIcon(
9840   - this.editorUi.menus.edgeStyleChange(
9841   - menu,
9842   - "",
9843   - [mxConstants.STYLE_STARTARROW, "startFill"],
9844   - ["doubleBlock", 1],
9845   - null,
9846   - null,
9847   - false,
9848   - Format.doubleBlockFilledMarkerImage.src,
9849   - ),
9850   - );
9851   - } else {
9852   - this.editorUi.menus
9853   - .edgeStyleChange(
9854   - menu,
9855   - "",
9856   - [mxConstants.STYLE_STARTARROW],
9857   - [mxConstants.ARROW_BLOCK],
9858   - "geIcon geSprite geSprite-startblocktrans",
9859   - null,
9860   - false,
9861   - )
9862   - .setAttribute("title", mxResources.get("block"));
9863   - }
9864   -
9865   - menu.div.style.width = "40px";
9866   -
9867   - window.setTimeout(
9868   - mxUtils.bind(this, function () {
9869   - if (menu.div != null) {
9870   - mxUtils.fit(menu.div);
9871   - }
9872   - }),
9873   - 0,
9874   - );
9875   - }
9876   - }),
9877   - );
9878   -
9879   - var lineEnd = this.editorUi.toolbar.addMenuFunctionInContainer(
9880   - stylePanel2,
9881   - "geSprite-endclassic",
9882   - mxResources.get("lineend"),
9883   - false,
9884   - mxUtils.bind(this, function (menu) {
9885   - if (
9886   - ss.style.shape == "connector" ||
9887   - ss.style.shape == "flexArrow" ||
9888   - ss.style.shape == "filledEdge"
9889   - ) {
9890   - var item = this.editorUi.menus.edgeStyleChange(
9891   - menu,
9892   - "",
9893   - [mxConstants.STYLE_ENDARROW, "endFill"],
9894   - [mxConstants.NONE, 0],
9895   - "geIcon",
9896   - null,
9897   - false,
9898   - );
9899   - item.setAttribute("title", mxResources.get("none"));
9900   -
9901   - var font = document.createElement("font");
9902   - font.style.fontSize = "10px";
9903   - mxUtils.write(font, mxResources.get("none"));
9904   - item.firstChild.firstChild.appendChild(font);
9905   -
9906   - if (ss.style.shape == "connector" || ss.style.shape == "filledEdge") {
9907   - Format.processMenuIcon(
9908   - this.editorUi.menus.edgeStyleChange(
9909   - menu,
9910   - "",
9911   - [mxConstants.STYLE_ENDARROW, "endFill"],
9912   - [mxConstants.ARROW_CLASSIC, 1],
9913   - null,
9914   - null,
9915   - false,
9916   - Format.classicFilledMarkerImage.src,
9917   - ),
9918   - "scaleX(-1)",
9919   - );
9920   - Format.processMenuIcon(
9921   - this.editorUi.menus.edgeStyleChange(
9922   - menu,
9923   - "",
9924   - [mxConstants.STYLE_ENDARROW, "endFill"],
9925   - [mxConstants.ARROW_CLASSIC_THIN, 1],
9926   - null,
9927   - null,
9928   - false,
9929   - Format.classicThinFilledMarkerImage.src,
9930   - ),
9931   - "scaleX(-1)",
9932   - );
9933   - Format.processMenuIcon(
9934   - this.editorUi.menus.edgeStyleChange(
9935   - menu,
9936   - "",
9937   - [mxConstants.STYLE_ENDARROW, "endFill"],
9938   - [mxConstants.ARROW_OPEN, 0],
9939   - null,
9940   - null,
9941   - false,
9942   - Format.openFilledMarkerImage.src,
9943   - ),
9944   - "scaleX(-1)",
9945   - );
9946   - Format.processMenuIcon(
9947   - this.editorUi.menus.edgeStyleChange(
9948   - menu,
9949   - "",
9950   - [mxConstants.STYLE_ENDARROW, "endFill"],
9951   - [mxConstants.ARROW_OPEN_THIN, 0],
9952   - null,
9953   - null,
9954   - false,
9955   - Format.openThinFilledMarkerImage.src,
9956   - ),
9957   - "scaleX(-1)",
9958   - );
9959   - Format.processMenuIcon(
9960   - this.editorUi.menus.edgeStyleChange(
9961   - menu,
9962   - "",
9963   - [mxConstants.STYLE_ENDARROW, "endFill"],
9964   - ["openAsync", 0],
9965   - null,
9966   - null,
9967   - false,
9968   - Format.openAsyncFilledMarkerImage.src,
9969   - ),
9970   - "scaleX(-1)",
9971   - );
9972   - Format.processMenuIcon(
9973   - this.editorUi.menus.edgeStyleChange(
9974   - menu,
9975   - "",
9976   - [mxConstants.STYLE_ENDARROW, "endFill"],
9977   - [mxConstants.ARROW_BLOCK, 1],
9978   - null,
9979   - null,
9980   - false,
9981   - Format.blockFilledMarkerImage.src,
9982   - ),
9983   - "scaleX(-1)",
9984   - );
9985   - Format.processMenuIcon(
9986   - this.editorUi.menus.edgeStyleChange(
9987   - menu,
9988   - "",
9989   - [mxConstants.STYLE_ENDARROW, "endFill"],
9990   - [mxConstants.ARROW_BLOCK_THIN, 1],
9991   - null,
9992   - null,
9993   - false,
9994   - Format.blockThinFilledMarkerImage.src,
9995   - ),
9996   - "scaleX(-1)",
9997   - );
9998   - Format.processMenuIcon(
9999   - this.editorUi.menus.edgeStyleChange(
10000   - menu,
10001   - "",
10002   - [mxConstants.STYLE_ENDARROW, "endFill"],
10003   - ["async", 1],
10004   - null,
10005   - null,
10006   - false,
10007   - Format.asyncFilledMarkerImage.src,
10008   - ),
10009   - "scaleX(-1)",
10010   - );
10011   - Format.processMenuIcon(
10012   - this.editorUi.menus.edgeStyleChange(
10013   - menu,
10014   - "",
10015   - [mxConstants.STYLE_ENDARROW, "endFill"],
10016   - [mxConstants.ARROW_OVAL, 1],
10017   - null,
10018   - null,
10019   - false,
10020   - Format.ovalFilledMarkerImage.src,
10021   - ),
10022   - "scaleX(-1)",
10023   - );
10024   - Format.processMenuIcon(
10025   - this.editorUi.menus.edgeStyleChange(
10026   - menu,
10027   - "",
10028   - [mxConstants.STYLE_ENDARROW, "endFill"],
10029   - [mxConstants.ARROW_DIAMOND, 1],
10030   - null,
10031   - null,
10032   - false,
10033   - Format.diamondFilledMarkerImage.src,
10034   - ),
10035   - "scaleX(-1)",
10036   - );
10037   - Format.processMenuIcon(
10038   - this.editorUi.menus.edgeStyleChange(
10039   - menu,
10040   - "",
10041   - [mxConstants.STYLE_ENDARROW, "endFill"],
10042   - [mxConstants.ARROW_DIAMOND_THIN, 1],
10043   - null,
10044   - null,
10045   - false,
10046   - Format.diamondThinFilledMarkerImage.src,
10047   - ),
10048   - "scaleX(-1)",
10049   - );
10050   - Format.processMenuIcon(
10051   - this.editorUi.menus.edgeStyleChange(
10052   - menu,
10053   - "",
10054   - [mxConstants.STYLE_ENDARROW, "endFill"],
10055   - [mxConstants.ARROW_CLASSIC, 0],
10056   - null,
10057   - null,
10058   - false,
10059   - Format.classicMarkerImage.src,
10060   - ),
10061   - "scaleX(-1)",
10062   - );
10063   - Format.processMenuIcon(
10064   - this.editorUi.menus.edgeStyleChange(
10065   - menu,
10066   - "",
10067   - [mxConstants.STYLE_ENDARROW, "endFill"],
10068   - [mxConstants.ARROW_CLASSIC_THIN, 0],
10069   - null,
10070   - null,
10071   - false,
10072   - Format.classicThinMarkerImage.src,
10073   - ),
10074   - "scaleX(-1)",
10075   - );
10076   - Format.processMenuIcon(
10077   - this.editorUi.menus.edgeStyleChange(
10078   - menu,
10079   - "",
10080   - [mxConstants.STYLE_ENDARROW, "endFill"],
10081   - [mxConstants.ARROW_BLOCK, 0],
10082   - null,
10083   - null,
10084   - false,
10085   - Format.blockMarkerImage.src,
10086   - ),
10087   - "scaleX(-1)",
10088   - );
10089   - Format.processMenuIcon(
10090   - this.editorUi.menus.edgeStyleChange(
10091   - menu,
10092   - "",
10093   - [mxConstants.STYLE_ENDARROW, "endFill"],
10094   - [mxConstants.ARROW_BLOCK_THIN, 0],
10095   - null,
10096   - null,
10097   - false,
10098   - Format.blockThinMarkerImage.src,
10099   - ),
10100   - "scaleX(-1)",
10101   - );
10102   - Format.processMenuIcon(
10103   - this.editorUi.menus.edgeStyleChange(
10104   - menu,
10105   - "",
10106   - [mxConstants.STYLE_ENDARROW, "endFill"],
10107   - ["async", 0],
10108   - null,
10109   - null,
10110   - false,
10111   - Format.asyncMarkerImage.src,
10112   - ),
10113   - "scaleX(-1)",
10114   - );
10115   - Format.processMenuIcon(
10116   - this.editorUi.menus.edgeStyleChange(
10117   - menu,
10118   - "",
10119   - [mxConstants.STYLE_ENDARROW, "endFill"],
10120   - [mxConstants.ARROW_OVAL, 0],
10121   - null,
10122   - null,
10123   - false,
10124   - Format.ovalMarkerImage.src,
10125   - ),
10126   - "scaleX(-1)",
10127   - );
10128   - Format.processMenuIcon(
10129   - this.editorUi.menus.edgeStyleChange(
10130   - menu,
10131   - "",
10132   - [mxConstants.STYLE_ENDARROW, "endFill"],
10133   - [mxConstants.ARROW_DIAMOND, 0],
10134   - null,
10135   - null,
10136   - false,
10137   - Format.diamondMarkerImage.src,
10138   - ),
10139   - "scaleX(-1)",
10140   - );
10141   - Format.processMenuIcon(
10142   - this.editorUi.menus.edgeStyleChange(
10143   - menu,
10144   - "",
10145   - [mxConstants.STYLE_ENDARROW, "endFill"],
10146   - [mxConstants.ARROW_DIAMOND_THIN, 0],
10147   - null,
10148   - null,
10149   - false,
10150   - Format.diamondThinMarkerImage.src,
10151   - ),
10152   - "scaleX(-1)",
10153   - );
10154   - Format.processMenuIcon(
10155   - this.editorUi.menus.edgeStyleChange(
10156   - menu,
10157   - "",
10158   - [mxConstants.STYLE_ENDARROW, "endFill"],
10159   - ["box", 0],
10160   - null,
10161   - null,
10162   - false,
10163   - Format.boxMarkerImage.src,
10164   - ),
10165   - "scaleX(-1)",
10166   - );
10167   - Format.processMenuIcon(
10168   - this.editorUi.menus.edgeStyleChange(
10169   - menu,
10170   - "",
10171   - [mxConstants.STYLE_ENDARROW, "endFill"],
10172   - ["halfCircle", 0],
10173   - null,
10174   - null,
10175   - false,
10176   - Format.halfCircleMarkerImage.src,
10177   - ),
10178   - "scaleX(-1)",
10179   - );
10180   - Format.processMenuIcon(
10181   - this.editorUi.menus.edgeStyleChange(
10182   - menu,
10183   - "",
10184   - [mxConstants.STYLE_ENDARROW, "endFill"],
10185   - ["dash", 0],
10186   - null,
10187   - null,
10188   - false,
10189   - Format.dashMarkerImage.src,
10190   - ),
10191   - "scaleX(-1)",
10192   - );
10193   - Format.processMenuIcon(
10194   - this.editorUi.menus.edgeStyleChange(
10195   - menu,
10196   - "",
10197   - [mxConstants.STYLE_ENDARROW, "endFill"],
10198   - ["cross", 0],
10199   - null,
10200   - null,
10201   - false,
10202   - Format.crossMarkerImage.src,
10203   - ),
10204   - "scaleX(-1)",
10205   - );
10206   - Format.processMenuIcon(
10207   - this.editorUi.menus.edgeStyleChange(
10208   - menu,
10209   - "",
10210   - [mxConstants.STYLE_ENDARROW, "endFill"],
10211   - ["circlePlus", 0],
10212   - null,
10213   - null,
10214   - false,
10215   - Format.circlePlusMarkerImage.src,
10216   - ),
10217   - "scaleX(-1)",
10218   - );
10219   - Format.processMenuIcon(
10220   - this.editorUi.menus.edgeStyleChange(
10221   - menu,
10222   - "",
10223   - [mxConstants.STYLE_ENDARROW, "endFill"],
10224   - ["circle", 0],
10225   - null,
10226   - null,
10227   - false,
10228   - Format.circleMarkerImage.src,
10229   - ),
10230   - "scaleX(-1)",
10231   - );
10232   - Format.processMenuIcon(
10233   - this.editorUi.menus.edgeStyleChange(
10234   - menu,
10235   - "",
10236   - [mxConstants.STYLE_ENDARROW, "endFill"],
10237   - ["baseDash", 0],
10238   - null,
10239   - null,
10240   - false,
10241   - Format.baseDashMarkerImage.src,
10242   - ),
10243   - "scaleX(-1)",
10244   - );
10245   - Format.processMenuIcon(
10246   - this.editorUi.menus.edgeStyleChange(
10247   - menu,
10248   - "",
10249   - [mxConstants.STYLE_ENDARROW, "endFill"],
10250   - ["ERone", 0],
10251   - null,
10252   - null,
10253   - false,
10254   - Format.EROneMarkerImage.src,
10255   - ),
10256   - "scaleX(-1)",
10257   - );
10258   - Format.processMenuIcon(
10259   - this.editorUi.menus.edgeStyleChange(
10260   - menu,
10261   - "",
10262   - [mxConstants.STYLE_ENDARROW, "endFill"],
10263   - ["ERmandOne", 0],
10264   - null,
10265   - null,
10266   - false,
10267   - Format.ERmandOneMarkerImage.src,
10268   - ),
10269   - "scaleX(-1)",
10270   - );
10271   - Format.processMenuIcon(
10272   - this.editorUi.menus.edgeStyleChange(
10273   - menu,
10274   - "",
10275   - [mxConstants.STYLE_ENDARROW, "endFill"],
10276   - ["ERmany", 0],
10277   - null,
10278   - null,
10279   - false,
10280   - Format.ERmanyMarkerImage.src,
10281   - ),
10282   - "scaleX(-1)",
10283   - );
10284   - Format.processMenuIcon(
10285   - this.editorUi.menus.edgeStyleChange(
10286   - menu,
10287   - "",
10288   - [mxConstants.STYLE_ENDARROW, "endFill"],
10289   - ["ERoneToMany", 0],
10290   - null,
10291   - null,
10292   - false,
10293   - Format.ERoneToManyMarkerImage.src,
10294   - ),
10295   - "scaleX(-1)",
10296   - );
10297   - Format.processMenuIcon(
10298   - this.editorUi.menus.edgeStyleChange(
10299   - menu,
10300   - "",
10301   - [mxConstants.STYLE_ENDARROW, "endFill"],
10302   - ["ERzeroToOne", 0],
10303   - null,
10304   - null,
10305   - false,
10306   - Format.ERzeroToOneMarkerImage.src,
10307   - ),
10308   - "scaleX(-1)",
10309   - );
10310   - Format.processMenuIcon(
10311   - this.editorUi.menus.edgeStyleChange(
10312   - menu,
10313   - "",
10314   - [mxConstants.STYLE_ENDARROW, "endFill"],
10315   - ["ERzeroToMany", 0],
10316   - null,
10317   - null,
10318   - false,
10319   - Format.ERzeroToManyMarkerImage.src,
10320   - ),
10321   - "scaleX(-1)",
10322   - );
10323   - Format.processMenuIcon(
10324   - this.editorUi.menus.edgeStyleChange(
10325   - menu,
10326   - "",
10327   - [mxConstants.STYLE_ENDARROW, "endFill"],
10328   - ["doubleBlock", 0],
10329   - null,
10330   - null,
10331   - false,
10332   - Format.doubleBlockMarkerImage.src,
10333   - ),
10334   - "scaleX(-1)",
10335   - );
10336   - Format.processMenuIcon(
10337   - this.editorUi.menus.edgeStyleChange(
10338   - menu,
10339   - "",
10340   - [mxConstants.STYLE_ENDARROW, "endFill"],
10341   - ["doubleBlock", 1],
10342   - null,
10343   - null,
10344   - false,
10345   - Format.doubleBlockFilledMarkerImage.src,
10346   - ),
10347   - "scaleX(-1)",
10348   - );
10349   - } else {
10350   - this.editorUi.menus
10351   - .edgeStyleChange(
10352   - menu,
10353   - "",
10354   - [mxConstants.STYLE_ENDARROW],
10355   - [mxConstants.ARROW_BLOCK],
10356   - "geIcon geSprite geSprite-endblocktrans",
10357   - null,
10358   - false,
10359   - )
10360   - .setAttribute("title", mxResources.get("block"));
10361   - }
10362   -
10363   - menu.div.style.width = "40px";
10364   -
10365   - window.setTimeout(
10366   - mxUtils.bind(this, function () {
10367   - if (menu.div != null) {
10368   - mxUtils.fit(menu.div);
10369   - }
10370   - }),
10371   - 0,
10372   - );
10373   - }
10374   - }),
10375   - );
10376   -
10377   - var elt = this.addArrow(edgeShape, 8);
10378   - elt.nextSibling.style.position = "relative";
10379   - elt.nextSibling.style.top = "-2px";
10380   - elt = this.addArrow(edgeStyle, 10);
10381   - elt.nextSibling.style.position = "relative";
10382   - elt.nextSibling.style.top = "-3px";
10383   - edgeStyle.getElementsByTagName("img")[0].style.top = "-1px";
10384   - this.addArrow(lineStart);
10385   - this.addArrow(lineEnd);
10386   -
10387   - var symbol = this.addArrow(pattern, 9);
10388   - symbol.className = "geIcon";
10389   - symbol.style.width = "auto";
10390   -
10391   - var altSymbol = this.addArrow(altPattern, 9);
10392   - altSymbol.className = "geIcon";
10393   - altSymbol.style.width = "22px";
10394   -
10395   - var solid = document.createElement("div");
10396   - solid.style.width = "84px";
10397   - solid.style.height = "1px";
10398   - solid.style.borderBottom = "1px solid " + this.defaultStrokeColor;
10399   - solid.style.marginBottom = "7px";
10400   - symbol.appendChild(solid);
10401   -
10402   - var altSolid = document.createElement("div");
10403   - altSolid.style.width = "23px";
10404   - altSolid.style.height = "1px";
10405   - altSolid.style.borderBottom = "1px solid " + this.defaultStrokeColor;
10406   - altSolid.style.marginBottom = "7px";
10407   - altSymbol.appendChild(altSolid);
10408   -
10409   - pattern.style.height = "15px";
10410   - pattern.style.marginLeft = "16px";
10411   - altPattern.style.height = "15px";
10412   - altPattern.style.marginLeft = "3px";
10413   - edgeShape.style.marginLeft = "10px";
10414   - edgeShape.style.height = "15px";
10415   - edgeStyle.style.marginLeft = "10px";
10416   - edgeStyle.style.height = "17px";
10417   - lineStart.style.marginLeft = "3px";
10418   - lineStart.style.height = "17px";
10419   - lineEnd.style.marginLeft = "3px";
10420   - lineEnd.style.height = "17px";
10421   -
10422   - container.appendChild(colorPanel);
10423   - container.appendChild(altStylePanel);
10424   - container.appendChild(stylePanel);
10425   -
10426   - var arrowPanel = stylePanel.cloneNode(false);
10427   - arrowPanel.style.padding = "5px 4px 6px 0px";
10428   - arrowPanel.style.fontWeight = "normal";
10429   -
10430   - var span = document.createElement("div");
10431   - span.style.position = "absolute";
10432   - span.style.marginLeft = "0px";
10433   - span.style.marginBottom = "12px";
10434   - span.style.marginTop = "2px";
10435   - span.style.fontWeight = "normal";
10436   - span.style.width = "76px";
10437   -
10438   - mxUtils.write(span, mxResources.get("lineend"));
10439   - arrowPanel.appendChild(span);
10440   -
10441   - var endSpacingUpdate, endSizeUpdate;
10442   - var endSpacing = this.addUnitInput(arrowPanel, "pt", 98, 52, function () {
10443   - endSpacingUpdate.apply(this, arguments);
10444   - });
10445   - var endSize = this.addUnitInput(arrowPanel, "pt", 30, 52, function () {
10446   - endSizeUpdate.apply(this, arguments);
10447   - });
10448   -
10449   - mxUtils.br(arrowPanel);
10450   -
10451   - var spacer = document.createElement("div");
10452   - spacer.style.height = "8px";
10453   - arrowPanel.appendChild(spacer);
10454   -
10455   - span = span.cloneNode(false);
10456   - mxUtils.write(span, mxResources.get("linestart"));
10457   - arrowPanel.appendChild(span);
10458   -
10459   - var startSpacingUpdate, startSizeUpdate;
10460   - var startSpacing = this.addUnitInput(arrowPanel, "pt", 98, 52, function () {
10461   - startSpacingUpdate.apply(this, arguments);
10462   - });
10463   - var startSize = this.addUnitInput(arrowPanel, "pt", 30, 52, function () {
10464   - startSizeUpdate.apply(this, arguments);
10465   - });
10466   -
10467   - mxUtils.br(arrowPanel);
10468   - this.addLabel(arrowPanel, mxResources.get("spacing"), 98, 52);
10469   - this.addLabel(arrowPanel, mxResources.get("size"), 30, 52);
10470   - mxUtils.br(arrowPanel);
10471   -
10472   - var perimeterPanel = colorPanel.cloneNode(false);
10473   - perimeterPanel.style.fontWeight = "normal";
10474   - perimeterPanel.style.position = "relative";
10475   - perimeterPanel.style.paddingLeft = "16px";
10476   - perimeterPanel.style.marginBottom = "2px";
10477   - perimeterPanel.style.marginTop = "6px";
10478   - perimeterPanel.style.borderWidth = "0px";
10479   - perimeterPanel.style.paddingBottom = "18px";
10480   -
10481   - var span = document.createElement("div");
10482   - span.style.position = "absolute";
10483   - span.style.marginLeft = "3px";
10484   - span.style.marginBottom = "12px";
10485   - span.style.marginTop = "1px";
10486   - span.style.fontWeight = "normal";
10487   - span.style.width = "120px";
10488   - mxUtils.write(span, mxResources.get("perimeter"));
10489   - perimeterPanel.appendChild(span);
10490   -
10491   - var perimeterUpdate;
10492   - var perimeterSpacing = this.addUnitInput(
10493   - perimeterPanel,
10494   - "pt",
10495   - 30,
10496   - 52,
10497   - function () {
10498   - perimeterUpdate.apply(this, arguments);
10499   - },
10500   - );
10501   -
10502   - if (ss.edges.length == ss.cells.length) {
10503   - container.appendChild(stylePanel2);
10504   - container.appendChild(arrowPanel);
10505   - } else if (ss.vertices.length == ss.cells.length) {
10506   - container.appendChild(perimeterPanel);
10507   - }
10508   -
10509   - var listener = mxUtils.bind(this, function (sender, evt, force) {
10510   - ss = ui.getSelectionState();
10511   -
10512   - if (force || document.activeElement != input) {
10513   - var tmp = parseFloat(
10514   - mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1),
10515   - );
10516   - input.value = isNaN(tmp) ? "" : tmp + " pt";
10517   - }
10518   -
10519   - if (force || document.activeElement != altInput) {
10520   - var tmp = parseFloat(
10521   - mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1),
10522   - );
10523   - altInput.value = isNaN(tmp) ? "" : tmp + " pt";
10524   - }
10525   -
10526   - styleSelect.style.visibility =
10527   - ss.style.shape == "connector" || ss.style.shape == "filledEdge"
10528   - ? ""
10529   - : "hidden";
10530   -
10531   - if (mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == "1") {
10532   - styleSelect.value = "curved";
10533   - } else if (
10534   - mxUtils.getValue(ss.style, mxConstants.STYLE_ROUNDED, null) == "1"
10535   - ) {
10536   - styleSelect.value = "rounded";
10537   - }
10538   -
10539   - if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASHED, null) == "1") {
10540   - if (
10541   - mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, null) == null
10542   - ) {
10543   - solid.style.borderBottom = "1px dashed " + this.defaultStrokeColor;
10544   - } else {
10545   - solid.style.borderBottom = "1px dotted " + this.defaultStrokeColor;
10546   - }
10547   - } else {
10548   - solid.style.borderBottom = "1px solid " + this.defaultStrokeColor;
10549   - }
10550   -
10551   - altSolid.style.borderBottom = solid.style.borderBottom;
10552   -
10553   - // Updates toolbar icon for edge style
10554   - var edgeStyleDiv = edgeStyle.getElementsByTagName("div")[0];
10555   -
10556   - if (edgeStyleDiv != null) {
10557   - var es = mxUtils.getValue(ss.style, mxConstants.STYLE_EDGE, null);
10558   -
10559   - if (
10560   - mxUtils.getValue(ss.style, mxConstants.STYLE_NOEDGESTYLE, null) == "1"
10561   - ) {
10562   - es = null;
10563   - }
10564   -
10565   - if (
10566   - es == "orthogonalEdgeStyle" &&
10567   - mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == "1"
10568   - ) {
10569   - edgeStyleDiv.className = "geSprite geSprite-curved";
10570   - } else if (es == "straight" || es == "none" || es == null) {
10571   - edgeStyleDiv.className = "geSprite geSprite-straight";
10572   - } else if (es == "entityRelationEdgeStyle") {
10573   - edgeStyleDiv.className = "geSprite geSprite-entity";
10574   - } else if (es == "elbowEdgeStyle") {
10575   - edgeStyleDiv.className =
10576   - "geSprite " +
10577   - (mxUtils.getValue(ss.style, mxConstants.STYLE_ELBOW, null) ==
10578   - "vertical"
10579   - ? "geSprite-verticalelbow"
10580   - : "geSprite-horizontalelbow");
10581   - } else if (es == "isometricEdgeStyle") {
10582   - edgeStyleDiv.className =
10583   - "geSprite " +
10584   - (mxUtils.getValue(ss.style, mxConstants.STYLE_ELBOW, null) ==
10585   - "vertical"
10586   - ? "geSprite-verticalisometric"
10587   - : "geSprite-horizontalisometric");
10588   - } else {
10589   - edgeStyleDiv.className = "geSprite geSprite-orthogonal";
10590   - }
10591   - }
10592   -
10593   - // Updates icon for edge shape
10594   - var edgeShapeDiv = edgeShape.getElementsByTagName("div")[0];
10595   -
10596   - if (edgeShapeDiv != null) {
10597   - if (ss.style.shape == "link") {
10598   - edgeShapeDiv.className = "geSprite geSprite-linkedge";
10599   - } else if (ss.style.shape == "flexArrow") {
10600   - edgeShapeDiv.className = "geSprite geSprite-arrow";
10601   - } else if (ss.style.shape == "arrow") {
10602   - edgeShapeDiv.className = "geSprite geSprite-simplearrow";
10603   - } else {
10604   - edgeShapeDiv.className = "geSprite geSprite-connection";
10605   - }
10606   - }
10607   -
10608   - if (ss.edges.length == ss.cells.length) {
10609   - altStylePanel.style.display = "";
10610   - stylePanel.style.display = "none";
10611   - } else {
10612   - altStylePanel.style.display = "none";
10613   - stylePanel.style.display = "";
10614   - }
10615   -
10616   - if (
10617   - Graph.lineJumpsEnabled &&
10618   - ss.edges.length > 0 &&
10619   - ss.vertices.length == 0 &&
10620   - ss.lineJumps
10621   - ) {
10622   - container.style.borderBottomStyle = "none";
10623   - }
10624   -
10625   - function updateArrow(marker, fill, elt, prefix) {
10626   - var markerDiv = elt.getElementsByTagName("div")[0];
10627   -
10628   - if (markerDiv != null) {
10629   - markerDiv.className = ui.getCssClassForMarker(
10630   - prefix,
10631   - ss.style.shape,
10632   - marker,
10633   - fill,
10634   - );
10635   - markerDiv.nextSibling.style.marginLeft = "1px";
10636   - markerDiv.nextSibling.style.paddingRight = "5px";
10637   -
10638   - if (markerDiv.className == "geSprite geSprite-noarrow") {
10639   - markerDiv.innerHTML = mxUtils.htmlEntities(mxResources.get("none"));
10640   - markerDiv.style.backgroundImage = "none";
10641   - markerDiv.style.verticalAlign = "top";
10642   - markerDiv.style.marginTop = "4px";
10643   - markerDiv.style.fontSize = "10px";
10644   - markerDiv.style.filter = "none";
10645   - markerDiv.style.color = this.defaultStrokeColor;
10646   - markerDiv.nextSibling.style.marginTop = "0px";
10647   - } else {
10648   - markerDiv.nextSibling.style.position = "relative";
10649   - markerDiv.nextSibling.style.top = "-2px";
10650   - }
10651   - }
10652   -
10653   - return markerDiv;
10654   - }
10655   -
10656   - var sourceDiv = updateArrow(
10657   - mxUtils.getValue(ss.style, mxConstants.STYLE_STARTARROW, null),
10658   - mxUtils.getValue(ss.style, "startFill", "1"),
10659   - lineStart,
10660   - "start",
10661   - );
10662   - var targetDiv = updateArrow(
10663   - mxUtils.getValue(ss.style, mxConstants.STYLE_ENDARROW, null),
10664   - mxUtils.getValue(ss.style, "endFill", "1"),
10665   - lineEnd,
10666   - "end",
10667   - );
10668   -
10669   - // Special cases for markers
10670   - if (sourceDiv != null && targetDiv != null) {
10671   - if (ss.style.shape == "arrow") {
10672   - sourceDiv.className = "geSprite geSprite-noarrow";
10673   - targetDiv.className = "geSprite geSprite-endblocktrans";
10674   - } else if (ss.style.shape == "link") {
10675   - sourceDiv.className = "geSprite geSprite-noarrow";
10676   - targetDiv.className = "geSprite geSprite-noarrow";
10677   - }
10678   - }
10679   -
10680   - mxUtils.setOpacity(edgeStyle, ss.style.shape == "arrow" ? 30 : 100);
10681   -
10682   - if (
10683   - ss.style.shape != "connector" &&
10684   - ss.style.shape != "flexArrow" &&
10685   - ss.style.shape != "filledEdge"
10686   - ) {
10687   - mxUtils.setOpacity(lineStart, 30);
10688   - mxUtils.setOpacity(lineEnd, 30);
10689   - } else {
10690   - mxUtils.setOpacity(lineStart, 100);
10691   - mxUtils.setOpacity(lineEnd, 100);
10692   - }
10693   -
10694   - if (force || document.activeElement != startSize) {
10695   - var tmp = parseInt(
10696   - mxUtils.getValue(
10697   - ss.style,
10698   - mxConstants.STYLE_STARTSIZE,
10699   - mxConstants.DEFAULT_MARKERSIZE,
10700   - ),
10701   - );
10702   - startSize.value = isNaN(tmp) ? "" : tmp + " pt";
10703   - }
10704   -
10705   - if (force || document.activeElement != startSpacing) {
10706   - var tmp = parseInt(
10707   - mxUtils.getValue(
10708   - ss.style,
10709   - mxConstants.STYLE_SOURCE_PERIMETER_SPACING,
10710   - 0,
10711   - ),
10712   - );
10713   - startSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
10714   - }
10715   -
10716   - if (force || document.activeElement != endSize) {
10717   - var tmp = parseInt(
10718   - mxUtils.getValue(
10719   - ss.style,
10720   - mxConstants.STYLE_ENDSIZE,
10721   - mxConstants.DEFAULT_MARKERSIZE,
10722   - ),
10723   - );
10724   - endSize.value = isNaN(tmp) ? "" : tmp + " pt";
10725   - }
10726   -
10727   - if (force || document.activeElement != startSpacing) {
10728   - var tmp = parseInt(
10729   - mxUtils.getValue(
10730   - ss.style,
10731   - mxConstants.STYLE_TARGET_PERIMETER_SPACING,
10732   - 0,
10733   - ),
10734   - );
10735   - endSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
10736   - }
10737   -
10738   - if (force || document.activeElement != perimeterSpacing) {
10739   - var tmp = parseInt(
10740   - mxUtils.getValue(ss.style, mxConstants.STYLE_PERIMETER_SPACING, 0),
10741   - );
10742   - perimeterSpacing.value = isNaN(tmp) ? "" : tmp + " pt";
10743   - }
10744   - });
10745   -
10746   - startSizeUpdate = this.installInputHandler(
10747   - startSize,
10748   - mxConstants.STYLE_STARTSIZE,
10749   - mxConstants.DEFAULT_MARKERSIZE,
10750   - 0,
10751   - 999,
10752   - " pt",
10753   - );
10754   - startSpacingUpdate = this.installInputHandler(
10755   - startSpacing,
10756   - mxConstants.STYLE_SOURCE_PERIMETER_SPACING,
10757   - 0,
10758   - -999,
10759   - 999,
10760   - " pt",
10761   - );
10762   - endSizeUpdate = this.installInputHandler(
10763   - endSize,
10764   - mxConstants.STYLE_ENDSIZE,
10765   - mxConstants.DEFAULT_MARKERSIZE,
10766   - 0,
10767   - 999,
10768   - " pt",
10769   - );
10770   - endSpacingUpdate = this.installInputHandler(
10771   - endSpacing,
10772   - mxConstants.STYLE_TARGET_PERIMETER_SPACING,
10773   - 0,
10774   - -999,
10775   - 999,
10776   - " pt",
10777   - );
10778   - perimeterUpdate = this.installInputHandler(
10779   - perimeterSpacing,
10780   - mxConstants.STYLE_PERIMETER_SPACING,
10781   - 0,
10782   - 0,
10783   - 999,
10784   - " pt",
10785   - );
10786   -
10787   - this.addKeyHandler(input, listener);
10788   - this.addKeyHandler(startSize, listener);
10789   - this.addKeyHandler(startSpacing, listener);
10790   - this.addKeyHandler(endSize, listener);
10791   - this.addKeyHandler(endSpacing, listener);
10792   - this.addKeyHandler(perimeterSpacing, listener);
10793   -
10794   - graph.getModel().addListener(mxEvent.CHANGE, listener);
10795   - this.listeners.push({
10796   - destroy: function () {
10797   - graph.getModel().removeListener(listener);
10798   - },
10799   - });
10800   - listener();
10801   -
10802   - return container;
10803   -};
10804   -
10805   -/**
10806   - * Adds UI for configuring line jumps.
10807   - */
10808   -StyleFormatPanel.prototype.addLineJumps = function (container) {
10809   - var ui = this.editorUi;
10810   - var editor = ui.editor;
10811   - var graph = editor.graph;
10812   - var ss = ui.getSelectionState();
10813   -
10814   - if (
10815   - Graph.lineJumpsEnabled &&
10816   - ss.edges.length > 0 &&
10817   - ss.vertices.length == 0 &&
10818   - ss.lineJumps
10819   - ) {
10820   - container.style.padding = "2px 0px 24px 14px";
10821   -
10822   - var span = document.createElement("div");
10823   - span.style.position = "absolute";
10824   - span.style.maxWidth = "82px";
10825   - span.style.overflow = "hidden";
10826   - span.style.textOverflow = "ellipsis";
10827   -
10828   - mxUtils.write(span, mxResources.get("lineJumps"));
10829   - container.appendChild(span);
10830   -
10831   - var styleSelect = document.createElement("select");
10832   - styleSelect.style.position = "absolute";
10833   - styleSelect.style.height = "21px";
10834   - styleSelect.style.padding = "0px";
10835   - styleSelect.style.marginTop = "-2px";
10836   - styleSelect.style.boxSizing = "border-box";
10837   - styleSelect.style.right = "76px";
10838   - styleSelect.style.width = "54px";
10839   - styleSelect.style.border = "1px solid rgb(160, 160, 160)";
10840   - styleSelect.style.borderRadius = "4px";
10841   -
10842   - var styles = ["none", "arc", "gap", "sharp", "line"];
10843   -
10844   - for (var i = 0; i < styles.length; i++) {
10845   - var styleOption = document.createElement("option");
10846   - styleOption.setAttribute("value", styles[i]);
10847   - mxUtils.write(styleOption, mxResources.get(styles[i]));
10848   - styleSelect.appendChild(styleOption);
10849   - }
10850   -
10851   - mxEvent.addListener(styleSelect, "change", function (evt) {
10852   - graph.getModel().beginUpdate();
10853   - try {
10854   - graph.setCellStyles("jumpStyle", styleSelect.value, ss.cells);
10855   - ui.fireEvent(
10856   - new mxEventObject(
10857   - "styleChanged",
10858   - "keys",
10859   - ["jumpStyle"],
10860   - "values",
10861   - [styleSelect.value],
10862   - "cells",
10863   - ss.cells,
10864   - ),
10865   - );
10866   - } finally {
10867   - graph.getModel().endUpdate();
10868   - }
10869   -
10870   - mxEvent.consume(evt);
10871   - });
10872   -
10873   - // Stops events from bubbling to color option event handler
10874   - mxEvent.addListener(styleSelect, "click", function (evt) {
10875   - mxEvent.consume(evt);
10876   - });
10877   -
10878   - container.appendChild(styleSelect);
10879   -
10880   - var jumpSizeUpdate;
10881   -
10882   - var jumpSize = this.addUnitInput(container, "pt", 16, 42, function () {
10883   - jumpSizeUpdate.apply(this, arguments);
10884   - });
10885   -
10886   - jumpSizeUpdate = this.installInputHandler(
10887   - jumpSize,
10888   - "jumpSize",
10889   - Graph.defaultJumpSize,
10890   - 0,
10891   - 999,
10892   - " pt",
10893   - );
10894   -
10895   - var listener = mxUtils.bind(this, function (sender, evt, force) {
10896   - ss = ui.getSelectionState();
10897   - styleSelect.value = mxUtils.getValue(ss.style, "jumpStyle", "none");
10898   -
10899   - if (force || document.activeElement != jumpSize) {
10900   - var tmp = parseInt(
10901   - mxUtils.getValue(ss.style, "jumpSize", Graph.defaultJumpSize),
10902   - );
10903   - jumpSize.value = isNaN(tmp) ? "" : tmp + " pt";
10904   - }
10905   - });
10906   -
10907   - this.addKeyHandler(jumpSize, listener);
10908   -
10909   - graph.getModel().addListener(mxEvent.CHANGE, listener);
10910   - this.listeners.push({
10911   - destroy: function () {
10912   - graph.getModel().removeListener(listener);
10913   - },
10914   - });
10915   - listener();
10916   - } else {
10917   - container.style.display = "none";
10918   - }
10919   -
10920   - return container;
10921   -};
10922   -
10923   -/**
10924   - * Adds the label menu items to the given menu and parent.
10925   - */
10926   -StyleFormatPanel.prototype.addEffects = function (div) {
10927   - var ui = this.editorUi;
10928   - var editor = ui.editor;
10929   - var graph = editor.graph;
10930   - var ss = ui.getSelectionState();
10931   -
10932   - div.style.paddingTop = "4px";
10933   - div.style.paddingBottom = "0px";
10934   -
10935   - var table = document.createElement("table");
10936   -
10937   - table.style.width = "210px";
10938   - table.style.fontWeight = "bold";
10939   - table.style.tableLayout = "fixed";
10940   - var tbody = document.createElement("tbody");
10941   - var row = document.createElement("tr");
10942   - row.style.padding = "0px";
10943   - var left = document.createElement("td");
10944   - left.style.padding = "0px";
10945   - left.style.width = "50%";
10946   - left.setAttribute("valign", "top");
10947   -
10948   - var right = left.cloneNode(true);
10949   - right.style.paddingLeft = "8px";
10950   - row.appendChild(left);
10951   - row.appendChild(right);
10952   - tbody.appendChild(row);
10953   - table.appendChild(tbody);
10954   - div.appendChild(table);
10955   -
10956   - var current = left;
10957   - var count = 0;
10958   -
10959   - var addOption = mxUtils.bind(this, function (label, key, defaultValue) {
10960   - var opt = this.createCellOption(label, key, defaultValue);
10961   - opt.style.width = "100%";
10962   - current.appendChild(opt);
10963   - current = current == left ? right : left;
10964   - count++;
10965   - });
10966   -
10967   - var listener = mxUtils.bind(this, function (sender, evt, force) {
10968   - ss = ui.getSelectionState();
10969   -
10970   - left.innerHTML = "";
10971   - right.innerHTML = "";
10972   - current = left;
10973   -
10974   - if (ss.rounded) {
10975   - addOption(mxResources.get("rounded"), mxConstants.STYLE_ROUNDED, 0);
10976   - }
10977   -
10978   - if (ss.swimlane) {
10979   - addOption(mxResources.get("divider"), "swimlaneLine", 1);
10980   - }
10981   -
10982   - if (!ss.containsImage) {
10983   - addOption(mxResources.get("shadow"), mxConstants.STYLE_SHADOW, 0);
10984   - }
10985   -
10986   - if (ss.glass) {
10987   - addOption(mxResources.get("glass"), mxConstants.STYLE_GLASS, 0);
10988   - }
10989   -
10990   - addOption(mxResources.get("sketch"), "sketch", 0);
10991   - });
10992   -
10993   - graph.getModel().addListener(mxEvent.CHANGE, listener);
10994   - this.listeners.push({
10995   - destroy: function () {
10996   - graph.getModel().removeListener(listener);
10997   - },
10998   - });
10999   - listener();
11000   -
11001   - return div;
11002   -};
11003   -
11004   -/**
11005   - * Adds the label menu items to the given menu and parent.
11006   - */
11007   -StyleFormatPanel.prototype.addStyleOps = function (div) {
11008   - div.style.paddingTop = "10px";
11009   - div.style.paddingBottom = "10px";
11010   -
11011   - this.addActions(div, ["setAsDefaultStyle"]);
11012   -
11013   - return div;
11014   -};
11015   -
11016   -/**
11017   - * Adds the label menu items to the given menu and parent.
11018   - */
11019   -DiagramStylePanel = function (format, editorUi, container) {
11020   - BaseFormatPanel.call(this, format, editorUi, container);
11021   - this.init();
11022   -};
11023   -
11024   -mxUtils.extend(DiagramStylePanel, BaseFormatPanel);
11025   -
11026   -/**
11027   - * Adds the label menu items to the given menu and parent.
11028   - */
11029   -DiagramStylePanel.prototype.init = function () {
11030   - var ui = this.editorUi;
11031   - var editor = ui.editor;
11032   - var graph = editor.graph;
11033   -
11034   - this.darkModeChangedListener = mxUtils.bind(this, function () {
11035   - this.format.cachedStyleEntries = [];
11036   - });
11037   -
11038   - ui.addListener("darkModeChanged", this.darkModeChangedListener);
11039   - this.container.appendChild(this.addView(this.createPanel()));
11040   -};
11041   -
11042   -/**
11043   - * Adds the label menu items to the given menu and parent.
11044   - */
11045   -DiagramStylePanel.prototype.addView = function (div) {
11046   - var ui = this.editorUi;
11047   - var editor = ui.editor;
11048   - var graph = editor.graph;
11049   - var model = graph.getModel();
11050   - var gridColor = graph.view.gridColor;
11051   -
11052   - div.style.whiteSpace = "normal";
11053   -
11054   - var sketch =
11055   - graph.currentVertexStyle["sketch"] == "1" &&
11056   - graph.currentEdgeStyle["sketch"] == "1";
11057   - var rounded = graph.currentVertexStyle["rounded"] == "1";
11058   - var curved = graph.currentEdgeStyle["curved"] == "1";
11059   -
11060   - var opts = document.createElement("div");
11061   - opts.style.marginRight = "16px";
11062   - div.style.paddingTop = "8px";
11063   -
11064   - var table = document.createElement("table");
11065   -
11066   - table.style.width = "210px";
11067   - table.style.fontWeight = "bold";
11068   -
11069   - var tbody = document.createElement("tbody");
11070   - var row = document.createElement("tr");
11071   - row.style.padding = "0px";
11072   -
11073   - var left = document.createElement("td");
11074   - left.style.padding = "0px";
11075   - left.style.width = "50%";
11076   - left.setAttribute("valign", "middle");
11077   -
11078   - var right = left.cloneNode(true);
11079   - right.style.paddingLeft = "8px";
11080   -
11081   - // Sketch
11082   - if (urlParams["sketch"] != "1") {
11083   - opts.style.paddingBottom = "12px";
11084   - row.appendChild(left);
11085   -
11086   - left.appendChild(
11087   - this.createOption(
11088   - mxResources.get("sketch"),
11089   - function () {
11090   - return sketch;
11091   - },
11092   - function (checked) {
11093   - sketch = checked;
11094   -
11095   - if (checked) {
11096   - graph.currentEdgeStyle["sketch"] = "1";
11097   - graph.currentVertexStyle["sketch"] = "1";
11098   - } else {
11099   - delete graph.currentEdgeStyle["sketch"];
11100   - delete graph.currentVertexStyle["sketch"];
11101   - }
11102   -
11103   - graph.updateCellStyles(
11104   - { sketch: checked ? "1" : null },
11105   - graph.getVerticesAndEdges(),
11106   - );
11107   - },
11108   - null,
11109   - function (div) {
11110   - div.style.width = "auto";
11111   - },
11112   - ),
11113   - );
11114   - }
11115   -
11116   - row.appendChild(right);
11117   - tbody.appendChild(row);
11118   - table.appendChild(tbody);
11119   -
11120   - // Rounded
11121   - right.appendChild(
11122   - this.createOption(
11123   - mxResources.get("rounded"),
11124   - function () {
11125   - return rounded;
11126   - },
11127   - function (checked) {
11128   - rounded = checked;
11129   -
11130   - if (checked) {
11131   - graph.currentEdgeStyle["rounded"] = "1";
11132   - graph.currentVertexStyle["rounded"] = "1";
11133   - } else {
11134   - delete graph.currentEdgeStyle["rounded"];
11135   - delete graph.currentVertexStyle["rounded"];
11136   - }
11137   -
11138   - graph.updateCellStyles(
11139   - { rounded: checked ? "1" : "0" },
11140   - graph.getVerticesAndEdges(),
11141   - );
11142   - },
11143   - null,
11144   - function (div) {
11145   - div.style.width = "auto";
11146   - },
11147   - ),
11148   - );
11149   -
11150   - // Curved
11151   - if (urlParams["sketch"] != "1") {
11152   - left = left.cloneNode(false);
11153   - right = right.cloneNode(false);
11154   - row = row.cloneNode(false);
11155   - row.appendChild(left);
11156   - row.appendChild(right);
11157   - tbody.appendChild(row);
11158   -
11159   - left.appendChild(
11160   - this.createOption(
11161   - mxResources.get("curved"),
11162   - function () {
11163   - return curved;
11164   - },
11165   - function (checked) {
11166   - curved = checked;
11167   -
11168   - if (checked) {
11169   - graph.currentEdgeStyle["curved"] = "1";
11170   - } else {
11171   - delete graph.currentEdgeStyle["curved"];
11172   - }
11173   -
11174   - graph.updateCellStyles(
11175   - { curved: checked ? "1" : null },
11176   - graph.getVerticesAndEdges(false, true),
11177   - );
11178   - },
11179   - null,
11180   - function (div) {
11181   - div.style.width = "auto";
11182   - },
11183   - ),
11184   - );
11185   - }
11186   -
11187   - opts.appendChild(table);
11188   - div.appendChild(opts);
11189   -
11190   - var defaultStyles = [
11191   - "fillColor",
11192   - "strokeColor",
11193   - "fontColor",
11194   - "gradientColor",
11195   - ];
11196   -
11197   - var updateCells = mxUtils.bind(this, function (styles, graphStyle) {
11198   - var cells = graph.getVerticesAndEdges();
11199   -
11200   - model.beginUpdate();
11201   - try {
11202   - for (var i = 0; i < cells.length; i++) {
11203   - var style = graph.getCellStyle(cells[i]);
11204   -
11205   - // Handles special label background color
11206   - if (style["labelBackgroundColor"] != null) {
11207   - graph.updateCellStyles(
11208   - {
11209   - labelBackgroundColor:
11210   - graphStyle != null ? graphStyle.background : null,
11211   - },
11212   - [cells[i]],
11213   - );
11214   - }
11215   -
11216   - var edge = model.isEdge(cells[i]);
11217   - var newStyle = model.getStyle(cells[i]);
11218   - var current = edge ? graph.currentEdgeStyle : graph.currentVertexStyle;
11219   -
11220   - for (var j = 0; j < styles.length; j++) {
11221   - if (
11222   - (style[styles[j]] != null &&
11223   - style[styles[j]] != mxConstants.NONE) ||
11224   - (styles[j] != mxConstants.STYLE_FILLCOLOR &&
11225   - styles[j] != mxConstants.STYLE_STROKECOLOR)
11226   - ) {
11227   - newStyle = mxUtils.setStyle(
11228   - newStyle,
11229   - styles[j],
11230   - current[styles[j]],
11231   - );
11232   - }
11233   - }
11234   -
11235   - model.setStyle(cells[i], newStyle);
11236   - }
11237   - } finally {
11238   - model.endUpdate();
11239   - }
11240   - });
11241   -
11242   - var removeStyles = mxUtils.bind(this, function (style, styles, defaultStyle) {
11243   - if (style != null) {
11244   - for (var j = 0; j < styles.length; j++) {
11245   - if (
11246   - (style[styles[j]] != null && style[styles[j]] != mxConstants.NONE) ||
11247   - (styles[j] != mxConstants.STYLE_FILLCOLOR &&
11248   - styles[j] != mxConstants.STYLE_STROKECOLOR)
11249   - ) {
11250   - style[styles[j]] = defaultStyle[styles[j]];
11251   - }
11252   - }
11253   - }
11254   - });
11255   -
11256   - var applyStyle = mxUtils.bind(
11257   - this,
11258   - function (style, result, cell, graphStyle, theGraph) {
11259   - if (style != null) {
11260   - if (cell != null) {
11261   - // Handles special label background color
11262   - if (result["labelBackgroundColor"] != null) {
11263   - var bg = graphStyle != null ? graphStyle.background : null;
11264   - theGraph = theGraph != null ? theGraph : graph;
11265   -
11266   - if (bg == null) {
11267   - bg = theGraph.background;
11268   - }
11269   -
11270   - if (bg == null) {
11271   - bg = theGraph.defaultPageBackgroundColor;
11272   - }
11273   -
11274   - result["labelBackgroundColor"] = bg;
11275   - }
11276   - }
11277   -
11278   - for (var key in style) {
11279   - if (
11280   - cell == null ||
11281   - (result[key] != null && result[key] != mxConstants.NONE) ||
11282   - (key != mxConstants.STYLE_FILLCOLOR &&
11283   - key != mxConstants.STYLE_STROKECOLOR)
11284   - ) {
11285   - result[key] = style[key];
11286   - }
11287   - }
11288   - }
11289   - },
11290   - );
11291   -
11292   - if (urlParams["sketch"] != "1") {
11293   - var btn = mxUtils.button(
11294   - mxResources.get("reset"),
11295   - mxUtils.bind(this, function (evt) {
11296   - var all = graph.getVerticesAndEdges(true, true);
11297   -
11298   - if (all.length > 0) {
11299   - model.beginUpdate();
11300   - try {
11301   - graph.updateCellStyles({ sketch: null, rounded: null }, all);
11302   - graph.updateCellStyles(
11303   - { curved: null },
11304   - graph.getVerticesAndEdges(false, true),
11305   - );
11306   - } finally {
11307   - model.endUpdate();
11308   - }
11309   - }
11310   -
11311   - ui.clearDefaultStyle();
11312   - }),
11313   - );
11314   -
11315   - btn.setAttribute("title", mxResources.get("reset"));
11316   - btn.style.textOverflow = "ellipsis";
11317   - btn.style.maxWidth = "90px";
11318   - right.appendChild(btn);
11319   - }
11320   -
11321   - var createPreview = mxUtils.bind(
11322   - this,
11323   - function (commonStyle, vertexStyle, edgeStyle, graphStyle, container) {
11324   - // Wrapper needed to catch events
11325   - var div = document.createElement("div");
11326   - div.style.position = "absolute";
11327   - div.style.display = "inline-block";
11328   - div.style.overflow = "hidden";
11329   - div.style.pointerEvents = "none";
11330   - div.style.width = "100%";
11331   - div.style.height = "100%";
11332   - container.appendChild(div);
11333   -
11334   - var graph2 = new Graph(div, null, null, graph.getStylesheet());
11335   -
11336   - graph2.resetViewOnRootChange = false;
11337   - graph2.foldingEnabled = false;
11338   - graph2.gridEnabled = false;
11339   - graph2.autoScroll = false;
11340   - graph2.setTooltips(false);
11341   - graph2.setConnectable(false);
11342   - graph2.setPanning(false);
11343   - graph2.setEnabled(false);
11344   -
11345   - graph2.getCellStyle = function (cell, resolve) {
11346   - resolve = resolve != null ? resolve : true;
11347   - var result = mxUtils.clone(graph.getCellStyle.apply(this, arguments));
11348   - var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
11349   - var appliedStyle = vertexStyle;
11350   -
11351   - if (model.isEdge(cell)) {
11352   - defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
11353   - appliedStyle = edgeStyle;
11354   - }
11355   -
11356   - removeStyles(result, defaultStyles, defaultStyle);
11357   - applyStyle(commonStyle, result, cell, graphStyle, graph2);
11358   - applyStyle(appliedStyle, result, cell, graphStyle, graph2);
11359   -
11360   - if (resolve) {
11361   - result = graph.postProcessCellStyle(cell, result);
11362   - }
11363   -
11364   - return result;
11365   - };
11366   -
11367   - // Avoid HTML labels to capture events in bubble phase
11368   - graph2.model.beginUpdate();
11369   - try {
11370   - var v1 = graph2.insertVertex(
11371   - graph2.getDefaultParent(),
11372   - null,
11373   - "Shape",
11374   - 14,
11375   - 8,
11376   - 70,
11377   - 40,
11378   - "strokeWidth=2;",
11379   - );
11380   - var e1 = graph2.insertEdge(
11381   - graph2.getDefaultParent(),
11382   - null,
11383   - "Connector",
11384   - v1,
11385   - v1,
11386   - "edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;endSize=5;strokeWidth=2;",
11387   - );
11388   - e1.geometry.points = [new mxPoint(32, 70)];
11389   - e1.geometry.offset = new mxPoint(0, 8);
11390   - } finally {
11391   - graph2.model.endUpdate();
11392   - }
11393   - },
11394   - );
11395   -
11396   - // Entries
11397   - var entries = document.createElement("div");
11398   - entries.style.position = "relative";
11399   - div.appendChild(entries);
11400   -
11401   - // Cached entries
11402   - if (this.format.cachedStyleEntries == null) {
11403   - this.format.cachedStyleEntries = [];
11404   - }
11405   -
11406   - function addKeys(style, result) {
11407   - for (var key in style) {
11408   - result.push(key);
11409   - }
11410   -
11411   - return result;
11412   - }
11413   -
11414   - var addEntry = mxUtils.bind(
11415   - this,
11416   - function (commonStyle, vertexStyle, edgeStyle, graphStyle, index) {
11417   - var panel = this.format.cachedStyleEntries[index];
11418   -
11419   - if (panel == null) {
11420   - panel = document.createElement("div");
11421   - panel.style.display = "inline-block";
11422   - panel.style.position = "relative";
11423   - panel.style.width = "96px";
11424   - panel.style.height = "90px";
11425   - panel.style.cursor = "pointer";
11426   - panel.style.border = "1px solid gray";
11427   - panel.style.borderRadius = "8px";
11428   - panel.style.margin = "2px";
11429   - panel.style.overflow = "hidden";
11430   -
11431   - if (graphStyle != null && graphStyle.background != null) {
11432   - panel.style.backgroundColor = graphStyle.background;
11433   - }
11434   -
11435   - createPreview(commonStyle, vertexStyle, edgeStyle, graphStyle, panel);
11436   -
11437   - mxEvent.addGestureListeners(
11438   - panel,
11439   - mxUtils.bind(this, function (evt) {
11440   - panel.style.opacity = 0.5;
11441   - }),
11442   - null,
11443   - mxUtils.bind(this, function (evt) {
11444   - panel.style.opacity = 1;
11445   - graph.currentVertexStyle = mxUtils.clone(graph.defaultVertexStyle);
11446   - graph.currentEdgeStyle = mxUtils.clone(graph.defaultEdgeStyle);
11447   -
11448   - applyStyle(commonStyle, graph.currentVertexStyle);
11449   - applyStyle(commonStyle, graph.currentEdgeStyle);
11450   - applyStyle(vertexStyle, graph.currentVertexStyle);
11451   - applyStyle(edgeStyle, graph.currentEdgeStyle);
11452   -
11453   - if (urlParams["sketch"] == "1") {
11454   - sketch = Editor.sketchMode;
11455   - }
11456   -
11457   - if (sketch) {
11458   - graph.currentEdgeStyle["sketch"] = "1";
11459   - graph.currentVertexStyle["sketch"] = "1";
11460   - } else {
11461   - graph.currentEdgeStyle["sketch"] = "0";
11462   - graph.currentVertexStyle["sketch"] = "0";
11463   - }
11464   -
11465   - if (rounded) {
11466   - graph.currentVertexStyle["rounded"] = "1";
11467   - graph.currentEdgeStyle["rounded"] = "1";
11468   - } else {
11469   - graph.currentVertexStyle["rounded"] = "0";
11470   - graph.currentEdgeStyle["rounded"] = "1";
11471   - }
11472   -
11473   - if (curved) {
11474   - graph.currentEdgeStyle["curved"] = "1";
11475   - } else {
11476   - graph.currentEdgeStyle["curved"] = "0";
11477   - }
11478   -
11479   - model.beginUpdate();
11480   - try {
11481   - updateCells(
11482   - addKeys(commonStyle, defaultStyles.slice()),
11483   - graphStyle,
11484   - );
11485   -
11486   - var change = new ChangePageSetup(
11487   - ui,
11488   - graphStyle != null ? graphStyle.background : null,
11489   - );
11490   - change.ignoreImage = true;
11491   - model.execute(change);
11492   -
11493   - model.execute(
11494   - new ChangeGridColor(
11495   - ui,
11496   - graphStyle != null && graphStyle.gridColor != null
11497   - ? graphStyle.gridColor
11498   - : gridColor,
11499   - ),
11500   - );
11501   - } finally {
11502   - model.endUpdate();
11503   - }
11504   - }),
11505   - );
11506   -
11507   - mxEvent.addListener(
11508   - panel,
11509   - "mouseenter",
11510   - mxUtils.bind(this, function (evt) {
11511   - var prev = graph.getCellStyle;
11512   - var prevBg = graph.background;
11513   - var prevGrid = graph.view.gridColor;
11514   -
11515   - graph.background =
11516   - graphStyle != null ? graphStyle.background : null;
11517   - graph.view.gridColor =
11518   - graphStyle != null && graphStyle.gridColor != null
11519   - ? graphStyle.gridColor
11520   - : gridColor;
11521   -
11522   - graph.getCellStyle = function (cell, resolve) {
11523   - resolve = resolve != null ? resolve : true;
11524   - var result = mxUtils.clone(prev.apply(this, arguments));
11525   -
11526   - var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
11527   - var appliedStyle = vertexStyle;
11528   -
11529   - if (model.isEdge(cell)) {
11530   - defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
11531   - appliedStyle = edgeStyle;
11532   - }
11533   -
11534   - removeStyles(result, defaultStyles, defaultStyle);
11535   - applyStyle(commonStyle, result, cell, graphStyle);
11536   - applyStyle(appliedStyle, result, cell, graphStyle);
11537   -
11538   - if (resolve) {
11539   - result = this.postProcessCellStyle(cell, result);
11540   - }
11541   -
11542   - return result;
11543   - };
11544   -
11545   - graph.refresh();
11546   - graph.getCellStyle = prev;
11547   - graph.background = prevBg;
11548   - graph.view.gridColor = prevGrid;
11549   - }),
11550   - );
11551   -
11552   - mxEvent.addListener(
11553   - panel,
11554   - "mouseleave",
11555   - mxUtils.bind(this, function (evt) {
11556   - graph.refresh();
11557   - }),
11558   - );
11559   -
11560   - // Workaround for broken cache in IE11
11561   - if (!mxClient.IS_IE && !mxClient.IS_IE11) {
11562   - this.format.cachedStyleEntries[index] = panel;
11563   - }
11564   - }
11565   -
11566   - entries.appendChild(panel);
11567   - },
11568   - );
11569   -
11570   - // Maximum palettes to switch the switcher
11571   - var maxEntries = 10;
11572   - var pageCount = Math.ceil(Editor.styles.length / maxEntries);
11573   - this.format.currentStylePage =
11574   - this.format.currentStylePage != null ? this.format.currentStylePage : 0;
11575   - var dots = [];
11576   -
11577   - var addEntries = mxUtils.bind(this, function () {
11578   - if (dots.length > 0) {
11579   - dots[this.format.currentStylePage].style.background = "#84d7ff";
11580   - }
11581   -
11582   - for (
11583   - var i = this.format.currentStylePage * maxEntries;
11584   - i <
11585   - Math.min(
11586   - (this.format.currentStylePage + 1) * maxEntries,
11587   - Editor.styles.length
11588   - );
11589   - i++
11590   - ) {
11591   - var s = Editor.styles[i];
11592   - addEntry(s.commonStyle, s.vertexStyle, s.edgeStyle, s.graph, i);
11593   - }
11594   - });
11595   -
11596   - var selectPage = mxUtils.bind(this, function (index) {
11597   - if (index >= 0 && index < pageCount) {
11598   - dots[this.format.currentStylePage].style.background = "transparent";
11599   - entries.innerHTML = "";
11600   - this.format.currentStylePage = index;
11601   - addEntries();
11602   - }
11603   - });
11604   -
11605   - if (pageCount > 1) {
11606   - // Selector
11607   - var switcher = document.createElement("div");
11608   - switcher.style.whiteSpace = "nowrap";
11609   - switcher.style.position = "relative";
11610   - switcher.style.textAlign = "center";
11611   - switcher.style.paddingTop = "4px";
11612   - switcher.style.width = "210px";
11613   -
11614   - div.style.paddingBottom = "8px";
11615   -
11616   - for (var i = 0; i < pageCount; i++) {
11617   - var dot = document.createElement("div");
11618   - dot.style.display = "inline-block";
11619   - dot.style.width = "6px";
11620   - dot.style.height = "6px";
11621   - dot.style.marginLeft = "4px";
11622   - dot.style.marginRight = "3px";
11623   - dot.style.borderRadius = "3px";
11624   - dot.style.cursor = "pointer";
11625   - dot.style.background = "transparent";
11626   - dot.style.border = "1px solid #b5b6b7";
11627   -
11628   - mxUtils.bind(this, function (index, elt) {
11629   - mxEvent.addListener(
11630   - dot,
11631   - "click",
11632   - mxUtils.bind(this, function () {
11633   - selectPage(index);
11634   - }),
11635   - );
11636   - })(i, dot);
11637   -
11638   - switcher.appendChild(dot);
11639   - dots.push(dot);
11640   - }
11641   -
11642   - div.appendChild(switcher);
11643   - addEntries();
11644   -
11645   - if (pageCount < 15) {
11646   - var left = document.createElement("div");
11647   - left.style.position = "absolute";
11648   - left.style.left = "0px";
11649   - left.style.top = "0px";
11650   - left.style.bottom = "0px";
11651   - left.style.width = "24px";
11652   - left.style.height = "24px";
11653   - left.style.margin = "0px";
11654   - left.style.cursor = "pointer";
11655   - left.style.opacity = "0.5";
11656   - left.style.backgroundRepeat = "no-repeat";
11657   - left.style.backgroundPosition = "center center";
11658   - left.style.backgroundSize = "24px 24px";
11659   - left.style.backgroundImage = "url(" + Editor.previousImage + ")";
11660   -
11661   - if (Editor.isDarkMode()) {
11662   - left.style.filter = "invert(100%)";
11663   - }
11664   -
11665   - var right = left.cloneNode(false);
11666   - right.style.backgroundImage = "url(" + Editor.nextImage + ")";
11667   - right.style.left = "";
11668   - right.style.right = "2px";
11669   -
11670   - switcher.appendChild(left);
11671   - switcher.appendChild(right);
11672   -
11673   - mxEvent.addListener(
11674   - left,
11675   - "click",
11676   - mxUtils.bind(this, function () {
11677   - selectPage(mxUtils.mod(this.format.currentStylePage - 1, pageCount));
11678   - }),
11679   - );
11680   -
11681   - mxEvent.addListener(
11682   - right,
11683   - "click",
11684   - mxUtils.bind(this, function () {
11685   - selectPage(mxUtils.mod(this.format.currentStylePage + 1, pageCount));
11686   - }),
11687   - );
11688   -
11689   - // Hover state
11690   - function addHoverState(elt) {
11691   - mxEvent.addListener(elt, "mouseenter", function () {
11692   - elt.style.opacity = "1";
11693   - });
11694   - mxEvent.addListener(elt, "mouseleave", function () {
11695   - elt.style.opacity = "0.5";
11696   - });
11697   - }
11698   -
11699   - addHoverState(left);
11700   - addHoverState(right);
11701   - }
11702   - } else {
11703   - addEntries();
11704   - }
11705   -
11706   - return div;
11707   -};
11708   -
11709   -/**
11710   - * Adds the label menu items to the given menu and parent.
11711   - */
11712   -DiagramStylePanel.prototype.destroy = function () {
11713   - BaseFormatPanel.prototype.destroy.apply(this, arguments);
11714   -
11715   - if (this.darkModeChangedListener) {
11716   - this.editorUi.removeListener(this.darkModeChangedListener);
11717   - this.darkModeChangedListener = null;
11718   - }
11719   -};
11720   -
11721   -/**
11722   - * Adds the label menu items to the given menu and parent.
11723   - */
11724   -DiagramFormatPanel = function (format, editorUi, container) {
11725   - BaseFormatPanel.call(this, format, editorUi, container);
11726   - this.init();
11727   -};
11728   -
11729   -mxUtils.extend(DiagramFormatPanel, BaseFormatPanel);
11730   -
11731   -/**
11732   - * Switch to disable page view.
11733   - */
11734   -DiagramFormatPanel.showPageView = true;
11735   -
11736   -/**
11737   - * Specifies if the background image option should be shown. Default is true.
11738   - */
11739   -DiagramFormatPanel.prototype.showBackgroundImageOption = true;
11740   -
11741   -/**
11742   - * Adds the label menu items to the given menu and parent.
11743   - */
11744   -DiagramFormatPanel.prototype.init = function () {
11745   - var ui = this.editorUi;
11746   - var editor = ui.editor;
11747   - var graph = editor.graph;
11748   -
11749   - this.container.appendChild(this.addView(this.createPanel()));
11750   -
11751   - if (graph.isEnabled()) {
11752   - this.container.appendChild(this.addOptions(this.createPanel()));
11753   - this.container.appendChild(this.addPaperSize(this.createPanel()));
11754   - this.container.appendChild(this.addStyleOps(this.createPanel()));
11755   - }
11756   -};
11757   -
11758   -/**
11759   - * Adds the label menu items to the given menu and parent.
11760   - */
11761   -DiagramFormatPanel.prototype.addView = function (div) {
11762   - var ui = this.editorUi;
11763   - var editor = ui.editor;
11764   - var graph = editor.graph;
11765   -
11766   - div.appendChild(this.createTitle(mxResources.get("view")));
11767   -
11768   - // Grid
11769   - this.addGridOption(div);
11770   -
11771   - // Page View
11772   - if (DiagramFormatPanel.showPageView) {
11773   - div.appendChild(
11774   - this.createOption(
11775   - mxResources.get("pageView"),
11776   - function () {
11777   - return graph.pageVisible;
11778   - },
11779   - function (checked) {
11780   - ui.actions.get("pageView").funct();
11781   - },
11782   - {
11783   - install: function (apply) {
11784   - this.listener = function () {
11785   - apply(graph.pageVisible);
11786   - };
11787   -
11788   - ui.addListener("pageViewChanged", this.listener);
11789   - },
11790   - destroy: function () {
11791   - ui.removeListener(this.listener);
11792   - },
11793   - },
11794   - ),
11795   - );
11796   - }
11797   -
11798   - if (graph.isEnabled()) {
11799   - // Background
11800   - var bg = this.createColorOption(
11801   - mxResources.get("background"),
11802   - function () {
11803   - return graph.background;
11804   - },
11805   - function (color) {
11806   - var change = new ChangePageSetup(ui, color);
11807   - change.ignoreImage = color != null && color != mxConstants.NONE;
11808   -
11809   - graph.model.execute(change);
11810   - },
11811   - "#ffffff",
11812   - {
11813   - install: function (apply) {
11814   - this.listener = function () {
11815   - apply(graph.background);
11816   - };
11817   -
11818   - ui.addListener("backgroundColorChanged", this.listener);
11819   - },
11820   - destroy: function () {
11821   - ui.removeListener(this.listener);
11822   - },
11823   - },
11824   - );
11825   -
11826   - if (this.showBackgroundImageOption) {
11827   - var label = bg.getElementsByTagName("span")[0];
11828   - label.style.display = "inline-block";
11829   - label.style.textOverflow = "ellipsis";
11830   - label.style.overflow = "hidden";
11831   - label.style.maxWidth = "68px";
11832   -
11833   - if (mxClient.IS_FF) {
11834   - label.style.marginTop = "1px";
11835   - }
11836   -
11837   - var btn = mxUtils.button(mxResources.get("change"), function (evt) {
11838   - ui.showBackgroundImageDialog(null, ui.editor.graph.backgroundImage);
11839   - mxEvent.consume(evt);
11840   - });
11841   -
11842   - btn.className = "geColorBtn";
11843   - btn.style.position = "absolute";
11844   - btn.style.marginTop = "-3px";
11845   - btn.style.height = "22px";
11846   - btn.style.left = "118px";
11847   - btn.style.width = "56px";
11848   -
11849   - bg.appendChild(btn);
11850   - }
11851   -
11852   - div.appendChild(bg);
11853   - }
11854   -
11855   - return div;
11856   -};
11857   -
11858   -/**
11859   - * Adds the label menu items to the given menu and parent.
11860   - */
11861   -DiagramFormatPanel.prototype.addOptions = function (div) {
11862   - var ui = this.editorUi;
11863   - var editor = ui.editor;
11864   - var graph = editor.graph;
11865   -
11866   - div.appendChild(this.createTitle(mxResources.get("options")));
11867   -
11868   - if (graph.isEnabled()) {
11869   - // Connection arrows
11870   - div.appendChild(
11871   - this.createOption(
11872   - mxResources.get("connectionArrows"),
11873   - function () {
11874   - return graph.connectionArrowsEnabled;
11875   - },
11876   - function (checked) {
11877   - ui.actions.get("connectionArrows").funct();
11878   - },
11879   - {
11880   - install: function (apply) {
11881   - this.listener = function () {
11882   - apply(graph.connectionArrowsEnabled);
11883   - };
11884   -
11885   - ui.addListener("connectionArrowsChanged", this.listener);
11886   - },
11887   - destroy: function () {
11888   - ui.removeListener(this.listener);
11889   - },
11890   - },
11891   - ),
11892   - );
11893   -
11894   - // Connection points
11895   - div.appendChild(
11896   - this.createOption(
11897   - mxResources.get("connectionPoints"),
11898   - function () {
11899   - return graph.connectionHandler.isEnabled();
11900   - },
11901   - function (checked) {
11902   - ui.actions.get("connectionPoints").funct();
11903   - },
11904   - {
11905   - install: function (apply) {
11906   - this.listener = function () {
11907   - apply(graph.connectionHandler.isEnabled());
11908   - };
11909   -
11910   - ui.addListener("connectionPointsChanged", this.listener);
11911   - },
11912   - destroy: function () {
11913   - ui.removeListener(this.listener);
11914   - },
11915   - },
11916   - ),
11917   - );
11918   -
11919   - // Guides
11920   - div.appendChild(
11921   - this.createOption(
11922   - mxResources.get("guides"),
11923   - function () {
11924   - return graph.graphHandler.guidesEnabled;
11925   - },
11926   - function (checked) {
11927   - ui.actions.get("guides").funct();
11928   - },
11929   - {
11930   - install: function (apply) {
11931   - this.listener = function () {
11932   - apply(graph.graphHandler.guidesEnabled);
11933   - };
11934   -
11935   - ui.addListener("guidesEnabledChanged", this.listener);
11936   - },
11937   - destroy: function () {
11938   - ui.removeListener(this.listener);
11939   - },
11940   - },
11941   - ),
11942   - );
11943   - }
11944   -
11945   - return div;
11946   -};
11947   -
11948   -/**
11949   - *
11950   - */
11951   -DiagramFormatPanel.prototype.addGridOption = function (container) {
11952   - var fPanel = this;
11953   - var ui = this.editorUi;
11954   - var graph = ui.editor.graph;
11955   -
11956   - var input = document.createElement("input");
11957   - input.style.position = "absolute";
11958   - input.style.textAlign = "right";
11959   - input.style.width = "48px";
11960   - input.style.marginTop = "-2px";
11961   - input.style.height = "21px";
11962   - input.style.border = "1px solid rgb(160, 160, 160)";
11963   - input.style.borderRadius = "4px";
11964   - input.style.boxSizing = "border-box";
11965   - input.value = this.inUnit(graph.getGridSize()) + " " + this.getUnit();
11966   -
11967   - var stepper = this.createStepper(
11968   - input,
11969   - update,
11970   - this.getUnitStep(),
11971   - null,
11972   - null,
11973   - null,
11974   - this.isFloatUnit(),
11975   - );
11976   - input.style.display = graph.isGridEnabled() ? "" : "none";
11977   - stepper.style.display = input.style.display;
11978   -
11979   - mxEvent.addListener(input, "keydown", function (e) {
11980   - if (e.keyCode == 13) {
11981   - graph.container.focus();
11982   - mxEvent.consume(e);
11983   - } else if (e.keyCode == 27) {
11984   - input.value = graph.getGridSize();
11985   - graph.container.focus();
11986   - mxEvent.consume(e);
11987   - }
11988   - });
11989   -
11990   - function update(evt) {
11991   - var value = fPanel.isFloatUnit()
11992   - ? parseFloat(input.value)
11993   - : parseInt(input.value);
11994   - value = fPanel.fromUnit(
11995   - Math.max(fPanel.inUnit(1), isNaN(value) ? fPanel.inUnit(10) : value),
11996   - );
11997   -
11998   - if (value != graph.getGridSize()) {
11999   - mxGraph.prototype.gridSize = value;
12000   - graph.setGridSize(value);
12001   - }
12002   -
12003   - input.value = fPanel.inUnit(value) + " " + fPanel.getUnit();
12004   - mxEvent.consume(evt);
12005   - }
12006   -
12007   - mxEvent.addListener(input, "blur", update);
12008   - mxEvent.addListener(input, "change", update);
12009   -
12010   - input.style.right = "78px";
12011   - stepper.style.marginTop = "-17px";
12012   - stepper.style.right = "66px";
12013   -
12014   - var panel = this.createColorOption(
12015   - mxResources.get("grid"),
12016   - function () {
12017   - var color = graph.view.gridColor;
12018   -
12019   - return graph.isGridEnabled() ? color : null;
12020   - },
12021   - function (color) {
12022   - var enabled = graph.isGridEnabled();
12023   -
12024   - if (color == mxConstants.NONE) {
12025   - graph.setGridEnabled(false);
12026   - } else {
12027   - graph.setGridEnabled(true);
12028   - ui.setGridColor(color);
12029   - }
12030   -
12031   - input.style.display = graph.isGridEnabled() ? "" : "none";
12032   - stepper.style.display = input.style.display;
12033   -
12034   - if (enabled != graph.isGridEnabled()) {
12035   - graph.defaultGridEnabled = graph.isGridEnabled();
12036   - ui.fireEvent(new mxEventObject("gridEnabledChanged"));
12037   - }
12038   - },
12039   - Editor.isDarkMode()
12040   - ? graph.view.defaultDarkGridColor
12041   - : graph.view.defaultGridColor,
12042   - {
12043   - install: function (apply) {
12044   - this.listener = function () {
12045   - apply(graph.isGridEnabled() ? graph.view.gridColor : null);
12046   - };
12047   -
12048   - ui.addListener("gridColorChanged", this.listener);
12049   - ui.addListener("gridEnabledChanged", this.listener);
12050   - },
12051   - destroy: function () {
12052   - ui.removeListener(this.listener);
12053   - },
12054   - },
12055   - );
12056   -
12057   - panel.appendChild(input);
12058   - panel.appendChild(stepper);
12059   - container.appendChild(panel);
12060   -};
12061   -
12062   -/**
12063   - * Adds the label menu items to the given menu and parent.
12064   - */
12065   -DiagramFormatPanel.prototype.addDocumentProperties = function (div) {
12066   - // Hook for subclassers
12067   - var ui = this.editorUi;
12068   - var editor = ui.editor;
12069   - var graph = editor.graph;
12070   -
12071   - div.appendChild(this.createTitle(mxResources.get("options")));
12072   -
12073   - return div;
12074   -};
12075   -
12076   -/**
12077   - * Adds the label menu items to the given menu and parent.
12078   - */
12079   -DiagramFormatPanel.prototype.addPaperSize = function (div) {
12080   - var ui = this.editorUi;
12081   - var editor = ui.editor;
12082   - var graph = editor.graph;
12083   -
12084   - div.appendChild(this.createTitle(mxResources.get("paperSize")));
12085   -
12086   - var accessor = PageSetupDialog.addPageFormatPanel(
12087   - div,
12088   - "formatpanel",
12089   - graph.pageFormat,
12090   - function (pageFormat) {
12091   - if (
12092   - graph.pageFormat == null ||
12093   - graph.pageFormat.width != pageFormat.width ||
12094   - graph.pageFormat.height != pageFormat.height
12095   - ) {
12096   - var change = new ChangePageSetup(ui, null, null, pageFormat);
12097   - change.ignoreColor = true;
12098   - change.ignoreImage = true;
12099   -
12100   - graph.model.execute(change);
12101   - }
12102   - },
12103   - );
12104   -
12105   - this.addKeyHandler(accessor.widthInput, function () {
12106   - accessor.set(graph.pageFormat);
12107   - });
12108   - this.addKeyHandler(accessor.heightInput, function () {
12109   - accessor.set(graph.pageFormat);
12110   - });
12111   -
12112   - var listener = function () {
12113   - accessor.set(graph.pageFormat);
12114   - };
12115   -
12116   - ui.addListener("pageFormatChanged", listener);
12117   - this.listeners.push({
12118   - destroy: function () {
12119   - ui.removeListener(listener);
12120   - },
12121   - });
12122   -
12123   - graph.getModel().addListener(mxEvent.CHANGE, listener);
12124   - this.listeners.push({
12125   - destroy: function () {
12126   - graph.getModel().removeListener(listener);
12127   - },
12128   - });
12129   -
12130   - return div;
12131   -};
12132   -
12133   -/**
12134   - * Adds the label menu items to the given menu and parent.
12135   - */
12136   -DiagramFormatPanel.prototype.addStyleOps = function (div) {
12137   - this.addActions(div, ["editData"]);
12138   - this.addActions(div, ["clearDefaultStyle"]);
12139   -
12140   - return div;
12141   -};
12142   -
12143   -/**
12144   - * Adds the label menu items to the given menu and parent.
12145   - */
12146   -DiagramFormatPanel.prototype.destroy = function () {
12147   - BaseFormatPanel.prototype.destroy.apply(this, arguments);
12148   -
12149   - if (this.gridEnabledListener) {
12150   - this.editorUi.removeListener(this.gridEnabledListener);
12151   - this.gridEnabledListener = null;
12152   - }
12153   -};
12154   -
12155   -// TODO UseLayUi
12156   -class UseLayUi {
12157   -
12158   - constructor() {
12159   - }
12160   -
12161   - static isFunction = fn => {
12162   - const result = Object.prototype.toString.call(fn)
12163   - return result === '[object Function]' || result === '[object AsyncFunction]'
12164   - }
12165   -
12166   - static dynamicAttr = (attr, value) => value ? `${attr}="${value}"` : ''
12167   -
12168   - /**
12169   - * @description format data source to tree structure
12170   - * @param {object[]} data - data source
12171   - * @param {Function} [customSetValue = ((record) => ({ id: record.id, title: record.name }))] customSetValue - custom set value && need return value
12172   - * @param {string} [idField = 'id'] idField - id field
12173   - * @param {string} [titleField = 'name'] titleField - titleField field
12174   - * @param {string} [childrenField = 'children'] childrenField - children field
12175   - * @returns {object[]}
12176   - */
12177   - static formatTreeDataSource(data, customSetValue, idField = 'id', titleField = 'name', childrenField = 'children') {
12178   - if (!Array.isArray(data) && !data.length) return []
12179   - customSetValue = customSetValue || ((record) => ({ id: record[idField], title: record[titleField] }))
12180   - const fn = (data) => {
12181   - return data.reduce((prev, next = {}) => {
12182   - let children = []
12183   - if (next[childrenField] && next[childrenField].length) {
12184   - children = fn(next.children)
12185   - }
12186   - return [...prev, { children, ...customSetValue(next) }]
12187   - }, [])
12188   - }
12189   - return fn(data)
12190   - }
12191   -
12192   - /**
12193   - * @description 通过ID 找到对应节点
12194   - * @param dataSource
12195   - * @param value
12196   - * @param findField
12197   - * @param childrenField
12198   - * @returns {any}
12199   - */
12200   - static findTreeObjectByField(dataSource, value, findField = 'id', childrenField = 'children') {
12201   - const map = new Map()
12202   -
12203   - function find(array) {
12204   - for (const item of array) {
12205   - map.set(item[findField], item)
12206   - if (map.has(item[value])) {
12207   - break
12208   - }
12209   - if (item[childrenField] && Array.isArray(item[childrenField])) {
12210   - find(item[childrenField])
12211   - }
12212   - }
12213   - }
12214   -
12215   - if (Array.isArray(dataSource)) {
12216   - find(dataSource)
12217   - return map.get(value)
12218   - }
12219   - }
12220   -
12221   - /**
12222   - * @description generator options template 生产下拉选项模板
12223   - * @param options
12224   - * @param {object[]} [dataSource] options.dataSource
12225   - * @param {boolean} [addPlaceholderOption = true] options.addPlaceholderOption
12226   - * @param {string} [labelField = 'name'] options.labelField
12227   - * @param {string} [valueField = 'name'] options.valueField
12228   - * @returns {*}
12229   - */
12230   - static generateOptionTemplate(options) {
12231   - const { dataSource = [], addPlaceholderOption = true, labelField = 'name', valueField = 'id' } = options
12232   - let { renderFn } = options
12233   - renderFn = renderFn || ((record) => {
12234   - if (typeof record === 'object') {
12235   - return `<option value="${record[valueField]}" ${record.disabled ? 'disabled=""' : ''}>${record[labelField]}</option>`
12236   - } else {
12237   - return `<option value="${record}">${record}</option>`
12238   - }
12239   - })
12240   - const optionsList = dataSource.map(renderFn)
12241   - if (addPlaceholderOption) optionsList.unshift('<option value="">请选择</option>')
12242   - return optionsList.join('')
12243   - }
12244   -
12245   - /**
12246   - * @description create single usage controls
12247   - * @param {string} content
12248   - */
12249   - static createSingleUseFormItem(content, props = '') {
12250   - return `
12251   - <div class="layui-form" ${props}>
12252   - ${content}
12253   - </div>
12254   - `
12255   - }
12256   -
12257   - /**
12258   - * @description 判断节点是否在某个节点之内
12259   - * @param {HTMLElement} parentNode
12260   - * @param {HTMLElement} childrenNode
12261   - * @param {boolean} [containsItsOwn = false] containsItsOwn - 是否包含自身
12262   - * @returns {boolean|*}
12263   - */
12264   - static isInNode(parentNode, childrenNode, containsItsOwn = false) {
12265   - return parentNode === childrenNode
12266   - ? containsItsOwn
12267   - : parentNode.contains(childrenNode)
12268   - }
12269   -
12270   - /**
12271   - * @description create layui single select template
12272   - * @param {string} [options.layFilter] options.layFilter
12273   - * @param {string} [options.bindValueFiled] options.bindValueFiled
12274   - * @param {string} [options.layVerify] options.layVerify
12275   - * @param {string} [options.layVerType] options.layVerType
12276   - * @param {Function} [options.renderFn] options.renderFn
12277   - * @param {Array} [options.dataSource = []] options.dataSource
12278   - * @param {string} [options.valueField = id] options.valueField
12279   - * @param {string} [options.labelField = name] options.labelField - dataSource
12280   - * @param {string} [options.label = 选择框] options.label - select label
12281   - * @param {string} [options.className = ''] options.className - css class name
12282   - * @param {Function} [options.onClick] options.onClick - select on click
12283   - * @returns {string}
12284   - */
12285   - static createSelect(options) {
12286   - const { form, jquery: $ } = layui
12287   -
12288   - const {
12289   - elem,
12290   - layFilter,
12291   - bindValueFiled,
12292   - layVerify,
12293   - layVerType,
12294   - renderFn,
12295   - dataSource = [],
12296   - valueField = 'id',
12297   - labelField = 'name',
12298   - label = '',
12299   - className = '',
12300   - onClick,
12301   - singleUsage = true,
12302   - } = options
12303   -
12304   - const formatDataSource = (dataSource) => {
12305   - return dataSource.map(record => {
12306   - return {
12307   - value: record[valueField],
12308   - label: record[labelField],
12309   - }
12310   - })
12311   - }
12312   -
12313   - const getOptionList = (dataSource) => {
12314   - if (renderFn && this.isFunction(renderFn)) {
12315   - return dataSource.map(record => renderFn(record))
12316   - }
12317   - return formatDataSource(dataSource).map(record => {
12318   - return `<option value="${record[valueField]}" ${record.disable ? 'disabled=""' : ''}>${record[labelField]}</option>`
12319   - })
12320   - }
12321   -
12322   - const generateOptionTemplate = (dataSource, addPlaceholderOption = true) => {
12323   - const optionsList = getOptionList(dataSource)
12324   - if (addPlaceholderOption) optionsList.unshift('<option value="">请选择</option>')
12325   - return optionsList.join('')
12326   - }
12327   -
12328   - if (layFilter) {
12329   - form.on(`select(${layFilter})`, (data) => {
12330   - if (onClick && this.isFunction(onClick)) {
12331   - onClick(data)
12332   - }
12333   - })
12334   - }
12335   -
12336   - let template = `
12337   - <div class="layui-form-item ${className}">
12338   - <label class="layui-form-label">${label}</label>
12339   - <div class="layui-input-block">
12340   - <select name="${bindValueFiled}" ${this.dynamicAttr('lay-filter', layFilter)} ${this.dynamicAttr('lay-verify', layVerify)} ${this.dynamicAttr('lay-verType', layVerType)}>
12341   - ${generateOptionTemplate(dataSource)}
12342   - </select>
12343   - </div>
12344   - </div>`
12345   -
12346   - const updateOptions = (dataSource) => {
12347   - if (!elem) return
12348   - const optionList = generateOptionTemplate(dataSource)
12349   - $(elem).find('select').html(optionList)
12350   - form.render('select', layFilter)
12351   - }
12352   -
12353   - template = singleUsage ? UseLayUi.createSingleUseFormItem(template, '') : template
12354   -
12355   -
12356   - function mount() {
12357   - if (elem) {
12358   - UseLayUi.nextTick(() => {
12359   - $(elem).html(template)
12360   - })
12361   - return { template, updateOptions }
12362   - }
12363   - return template
12364   - }
12365   -
12366   - return mount()
12367   - }
12368   -
12369   - // TODO Tree Select
12370   - /**
12371   - * @description create a tree select controls
12372   - * @param {string} [options.layFilter] options.layFilter
12373   - * @param {string} [options.label] options.label
12374   - * @param {object} [options.treeProps] options.treeProps
12375   - * @param {HTMLDivElement} [options.elem] options.elem
12376   - * @param {boolean} [options.singleUsage = true] options.singleUsage
12377   - * @param {Function} [options.customSetTree = ((record) => ({ id: record.id, title: record.name }))] options.customSetTree
12378   - * @param {boolean} [options.autoFormatDataSource = true] options.autoFormatDataSource
12379   - * @param {string} [options.layVerify] options.layVerify
12380   - * @param {string} [options.layVerType] options.layVerType
12381   - * @param {Function} [options.treeProps.onReady] options.treeProps.onReady
12382   - */
12383   - static createTreeSelect(options) {
12384   - const CLASS_NAME = 'things-kit-tree-select'
12385   - const SELECT_CLS = 'things-kit-tree-select__tree'
12386   - const { tree, jquery: $, form } = layui
12387   -
12388   - const {
12389   - layFilter,
12390   - label,
12391   - treeProps = {},
12392   - elem,
12393   - className = '',
12394   - singleUsage = true,
12395   - customSetTree = undefined,
12396   - autoFormatDataSource = true,
12397   - labelField = 'name',
12398   - valueField = 'id',
12399   - childrenField = 'children',
12400   - layVerify,
12401   - layVerType,
12402   - } = options
12403   -
12404   - let { data = [], click, onReady } = treeProps
12405   -
12406   - let template = `
12407   - <div class="layui-form-item ${CLASS_NAME} ${className}">
12408   - <label class="layui-form-label">${label}</label>
12409   - <div class="layui-input-block">
12410   - <div class="layui-unselect layui-form-select ${SELECT_CLS}">
12411   - <div class="layui-select-title">
12412   - <span class="layui-input layui-unselect tree-select__label">请选择</span>
12413   - <input ${this.dynamicAttr('lay-verify', layVerify)} ${this.dynamicAttr('lay-verType', layVerType)} type="text" style="visibility: hidden; position: absolute; top: 0" name="${layFilter}">
12414   - <i class="layui-edge"></i>
12415   - </div>
12416   - <dl class="layui-anim layui-anim-upbit">
12417   - <dd>
12418   - <ul class="tree-select__tree-mount"></ul>
12419   - </dd>
12420   - </dl>
12421   - </div>
12422   - </div>
12423   - </div>`
12424   -
12425   - template = singleUsage ? UseLayUi.createSingleUseFormItem(template) : template
12426   -
12427   - /**
12428   - * @description 设置下拉树值
12429   - * @param {string} id - layui tree 树形结构 title字段
12430   - * @param {string} title - layui tree 树形结构 id字段
12431   - */
12432   - function setValue({ id, title }) {
12433   - $(elem)
12434   - .find('.layui-form-select').removeClass('layui-form-selected').end()
12435   - .find(".layui-select-title span").html(title).end()
12436   - .find(`input[name='${layFilter}']`).val(id);
12437   - }
12438   -
12439   - // init mount
12440   - function mount() {
12441   - // mount select container
12442   - $(elem).html(template)
12443   -
12444   - // mount tree
12445   - // UseLayUi.nextTick(() => {
12446   - tree.render({
12447   - ...treeProps,
12448   - ...(autoFormatDataSource ? { data: UseLayUi.formatTreeDataSource(data, customSetTree, valueField, labelField, childrenField) } : {}),
12449   - elem: $(elem).find('.tree-select__tree-mount'),
12450   - click(node) {
12451   - setValue(node.data)
12452   - if (UseLayUi.isFunction(click)) click(node)
12453   - },
12454   - })
12455   -
12456   - // focus
12457   - $(`.${SELECT_CLS}`).off('click')
12458   - .on("click", ".layui-select-title", function (e) {
12459   - $(document).find('.layui-form-select').removeClass('layui-form-selected')
12460   - $(this).parents(`.${SELECT_CLS}`).toggleClass("layui-form-selected");
12461   - layui.stope(e);
12462   - })
12463   - .on('click', '.layui-anim', (e) => {
12464   - layui.stope(e)
12465   - })
12466   - .on("click", "dl i", function (e) {
12467   - layui.stope(e);
12468   - })
12469   -
12470   - // blur
12471   - // $(document)
12472   - // .on("click", function (e) {
12473   - // const target = e.target
12474   - // const parentNode = $(`.${CLASS_NAME} .tree-select__tree-mount`)
12475   - // if (!parentNode) return
12476   - // console.log($.contains(parentNode, target))
12477   - // // const showClose = UseLayUi.isInNode(parentNode, target, true)
12478   - // // if (showClose) return
12479   - // // $(`.${ SELECT_CLS }`).removeClass("layui-form-selected")
12480   - // });
12481   -
12482   - if (UseLayUi.isFunction(onReady)) {
12483   - onReady(setValue)
12484   - }
12485   - // })
12486   - form.render()
12487   - }
12488   -
12489   - mount()
12490   - }
12491   -
12492   - static createCheckBox(options) {
12493   - const { jquery: $, form } = layui
12494   - const CLASS_NAME = 'things-kit__checkbox'
12495   - let {
12496   - elem,
12497   - singleUsage = true,
12498   - layFilter = '',
12499   - layVerify = '',
12500   - label = '',
12501   - laySkin = 'primary',
12502   - dataSource = [],
12503   - customSetValue,
12504   - labelField = 'name',
12505   - valueField = 'id',
12506   - checkedField = 'checked',
12507   - onChange,
12508   - } = options
12509   - customSetValue = customSetValue || ((record) => ({ value: record.id, title: record.name }))
12510   - if (!Array.isArray(dataSource)) {
12511   - dataSource = [dataSource]
12512   - }
12513   -
12514   - function createOptions(dataSource) {
12515   - return dataSource.map((record) => {
12516   - return `<input
12517   - type="checkbox" lay-skin="${laySkin}"
12518   - ${UseLayUi.dynamicAttr('name', record[valueField])}
12519   - ${UseLayUi.dynamicAttr('title', record[labelField])}
12520   - ${UseLayUi.dynamicAttr('lay-filter', layFilter)}
12521   - ${UseLayUi.dynamicAttr('lay-verify', layVerify)}
12522   - ${UseLayUi.dynamicAttr('checked', record[checkedField])}
12523   - >`
12524   - })
12525   - }
12526   -
12527   - let template = `
12528   - <div class="layui-form-item ${CLASS_NAME}" >
12529   - <label class="layui-form-label">${label}</label>
12530   - <div class="layui-input-block">
12531   - ${createOptions(dataSource).join('')}
12532   - </div>
12533   - </div>`
12534   -
12535   - template = singleUsage ? UseLayUi.createSingleUseFormItem(template) : template
12536   -
12537   - function mount() {
12538   - if (!elem) return template
12539   - $(elem).empty()
12540   - $(elem).append(template)
12541   - form.on(`checkbox(${layFilter})`, (data) => {
12542   - onChange && (onChange(data))
12543   - })
12544   - form.render()
12545   - }
12546   -
12547   - return mount()
12548   - }
12549   -
12550   - /**
12551   - * @description 创建树形组件
12552   - * @param {object} options
12553   - * @param {string | object} options.elem - 挂载节点
12554   - * @param {object[]} [data] options.data - 数据源
12555   - * @param {string} [id] options.id - 用于基础方法传参使用
12556   - * @param {boolean} [showCheckbox = false] options.showCheckbox - 显示复选框
12557   - * @param {boolean|string[]} [edit] options.edit - 是否开启节点操作
12558   - * @param {boolean} [accordion = false] options.accordion - 手风琴
12559   - * @param {boolean} [onlyIconControl = false] options.onlyIconControl - 仅允许左侧图标展开收缩
12560   - * @param {boolean} [isJump = false] options.isJump - 跳转
12561   - * @param {boolean} [showLine = true] options.showLine - 显示连接线
12562   - * @param {object} [text] options.text - 自定义默认值
12563   - * @param {string} [valueField = 'id'] options.valueField - 值字段
12564   - * @param {string} [labelField = 'name'] options.labelField - 标签字段
12565   - * @param {string} [childrenField = 'children'] options.childrenField - 后代节点字段
12566   - * @param {Function} [customSetValue] options.customSetValue - 后代节点字段
12567   - * @param {boolean} [autoFormatValue = true] options.autoFormatValue - 自动格式化值
12568   - */
12569   - static createTree(options = {}) {
12570   - const { tree } = layui
12571   - const {
12572   - data = [],
12573   - valueField = 'id',
12574   - labelField = 'name',
12575   - childrenField = 'children',
12576   - customSetValue,
12577   - autoFormatValue = true,
12578   - } = options
12579   - tree.render({
12580   - ...options,
12581   - data: autoFormatValue ? UseLayUi.formatTreeDataSource(data, customSetValue, valueField, labelField, childrenField) : data,
12582   - })
12583   - }
12584   -
12585   -
12586   - static nextTick(fn) {
12587   - new Promise((resolve) => {
12588   - resolve()
12589   - }).then(() => {
12590   - fn()
12591   - })
12592   - }
12593   -
12594   - static msg(msg, options) {
12595   - const { layer } = layui
12596   - layer.msg(msg, options)
12597   - }
12598   -
12599   - static successMsg(msg = '操作成功', options) {
12600   - UseLayUi.msg(msg, { ...options, icon: 6 })
12601   - }
12602   -
12603   - static errorMsg(msg = '操作失败', options) {
12604   - UseLayUi.msg(msg, { ...options, icon: 5 })
12605   - }
12606   -
12607   - static topMsg(msg, options, icon) {
12608   - const { layer } = layui
12609   - layer.msg(`<div style="padding: 20px; display: flex; align-items: center;"><i class="layui-layer-ico layui-layer-ico${icon}" style="width: 30px;height: 30px;"></i><span style="margin-left: 5px">${msg}</span></div>`, { ...options, type: 1, icon, time: 2000, })
12610   - }
12611   -
12612   - static topSuccessMsg(msg = '操作成功', options) {
12613   - this.topMsg(msg, options, 6)
12614   - }
12615   -
12616   - static topErrorMsg(msg = '操作失败', options) {
12617   - this.topMsg(msg, options, 5)
12618   - }
12619   -
12620   - static topInfoMsg(msg = '提示', options) {
12621   - this.topMsg(msg, options, 0)
12622   - }
12623   -}
12624   -
12625   -
12626   -/**
12627   - * @description use to function capture await throw error
12628   - * @param promise
12629   - * @param errorExt - Additional Information you can pass to the err object
12630   - */
12631   -function to(promise, errorExt) {
12632   - return promise
12633   - .then((data) => [null, data])
12634   - .catch((err) => {
12635   - if (errorExt) {
12636   - const parsedError = Object.assign({}, err, errorExt)
12637   - return [parsedError, undefined]
12638   - }
12639   - return [err, undefined]
12640   - })
12641   -}
12642   -
12643   -
12644   -class EventCenter {
12645   -
12646   - /**
12647   - * @description 调度中心
12648   - * @type {Map<string, Function[]>}
12649   - */
12650   - eventStack
12651   -
12652   - /**
12653   - * @description 实例化EventCenter
12654   - */
12655   - constructor() {
12656   - this.eventStack = new Map()
12657   - }
12658   -
12659   - /**
12660   - * @description 监听事件
12661   - * @param {string | number} eventName - 事件名
12662   - * @param {Function} callback - 事件处理方法
12663   - */
12664   - on(eventName, callback) {
12665   - if (this.eventStack.has(eventName)) {
12666   - this.eventStack.get(eventName).push(callback)
12667   - return
12668   - }
12669   - this.eventStack.set(eventName, [callback])
12670   - }
12671   -
12672   - /**
12673   - * @description 触发事件
12674   - * @param {string | number} eventName - 事件名
12675   - * @param {any} args - 参数
12676   - */
12677   - emit(eventName, ...args) {
12678   - if (this.eventStack.has(eventName))
12679   - this.eventStack.get(eventName).forEach(fn => fn(...args))
12680   - }
12681   -
12682   - /**
12683   - * @description 移除事件
12684   - * @param {string} eventName - 时间名
12685   - */
12686   - off(eventName) {
12687   - if (this.eventStack.has(eventName))
12688   - this.eventStack.delete(eventName)
12689   - }
12690   -
12691   - /**
12692   - * @description 清除事件
12693   - */
12694   - clean(eventName) {
12695   - this.eventStack.clear()
12696   - }
12697   -
12698   -
12699   -}
12700   -
12701   -class Ws {
12702   - /**
12703   - * @description url 连接地址
12704   - */
12705   - url
12706   -
12707   - /**
12708   - * @description 协议
12709   - */
12710   - protocols
12711   -
12712   - /**
12713   - * @description socket open时 拓展
12714   - * @type {Function}
12715   - * @param {Ws} instance - 实例
12716   - */
12717   - onopenCallback
12718   -
12719   - /**
12720   - * @description socket error时 拓展
12721   - * @type {Function}
12722   - * @param {Ws} instance - 实例
12723   - */
12724   - onerrorCallback
12725   -
12726   - /**
12727   - * @description socket close时 拓展
12728   - * @type {Function}
12729   - * @param {Ws} instance - 实例
12730   - */
12731   - oncloseCallback
12732   -
12733   - /**
12734   - * @description socket message时 拓展
12735   - * @type {Function}
12736   - * @param {object} data - event.data message数据
12737   - * @param {MessageEvent} event - event 事件对象
12738   - * @param {Ws} instance - Ws 实例
12739   - */
12740   - onmessageCallback
12741   -
12742   - /**
12743   - * @description socket 实例
12744   - * @type {WebSocket}
12745   - */
12746   - ws
12747   -
12748   - /**
12749   - * @description 重连标志
12750   - * @type {boolean}
12751   - */
12752   - isReconnectionLoading = false
12753   -
12754   - /**
12755   - * @description 重连定时器
12756   - */
12757   - timeId = null
12758   -
12759   - /**
12760   - * @description 手动关闭标志位
12761   - * @type {boolean}
12762   - */
12763   - isCustomClose = false
12764   -
12765   - /**
12766   - * @description 消息队列 重新连接后会将之前断开期间发送的消息重新推送
12767   - * @type {Array}
12768   - */
12769   - errorStack = []
12770   -
12771   - /**
12772   - * @description 实例
12773   - */
12774   - static instance
12775   -
12776   - /**
12777   - * @description 创建websocket实例
12778   - * @param {string} option.url - 连接路径
12779   - * @param {string} [option.protocols] option.protocols - 协议
12780   - * @param {Function} [option.onopenCallback] option.onopenCallback - socket open时 拓展
12781   - * @param {Function} [option.onerrorCallback] option.onerrorCallback - socket error时 拓展
12782   - * @param {Function} [option.oncloseCallback] option.oncloseCallback - socket close时 拓展
12783   - * @param {Function} [option.onmessageCallback] option.onmessageCallback - socket message时 拓展
12784   - */
12785   - constructor(option) {
12786   - const { url, protocols, onopenCallback, onerrorCallback, oncloseCallback, onmessageCallback } = option
12787   - if (!url) throw new Error('param url in Ws constructor is required')
12788   - this.url = url
12789   - this.protocols = protocols
12790   - this.onopenCallback = onopenCallback
12791   - this.onerrorCallback = onerrorCallback
12792   - this.oncloseCallback = oncloseCallback
12793   - this.onmessageCallback = onmessageCallback
12794   - this.createWs()
12795   - }
12796   -
12797   - /**
12798   - * @description
12799   - */
12800   - createWs() {
12801   - this.ws = new WebSocket(this.url, this.protocols)
12802   - this.onopen()
12803   - this.onerror()
12804   - this.onclose()
12805   - this.onmessage()
12806   - }
12807   -
12808   - /**
12809   - * @description 建立连接时
12810   - */
12811   - onopen() {
12812   - this.ws.onopen = () => {
12813   - this.errorStack.forEach(message => {
12814   - this.send(message)
12815   - })
12816   - this.errorStack = []
12817   - this.isReconnectionLoading = false
12818   - if (typeof this.onopenCallback === 'function') this.onopenCallback(this)
12819   - }
12820   - }
12821   -
12822   - /**
12823   - * @description 连接发生错误
12824   - */
12825   - onerror() {
12826   - this.ws.onerror = (err) => {
12827   - this.reconnection()
12828   - this.isReconnectionLoading = false
12829   - if (typeof this.onerrorCallback === 'function') this.onerrorCallback(this)
12830   - }
12831   - }
12832   -
12833   - /**
12834   - * @description 连接断开时
12835   - */
12836   - onclose() {
12837   - this.ws.onclose = () => {
12838   - if (this.isCustomClose) return
12839   -
12840   - this.reconnection()
12841   - this.isReconnectionLoading = false
12842   -
12843   - if (typeof this.oncloseCallback === 'function') this.oncloseCallback(this)
12844   - }
12845   - }
12846   -
12847   - /**
12848   - * @description 接受消息
12849   - */
12850   - onmessage() {
12851   - this.ws.onmessage = (event) => {
12852   - try {
12853   - const data = JSON.parse(event.data)
12854   - if (typeof this.onmessageCallback === 'function') this.onmessageCallback(data, event, this)
12855   -
12856   - } catch (error) {
12857   - // throw new Error(error)
12858   - console.error(error)
12859   - }
12860   - }
12861   - }
12862   -
12863   - /**
12864   - * @description 断开重连
12865   - */
12866   - reconnection() {
12867   - if (this.isReconnectionLoading) return
12868   -
12869   - this.isReconnectionLoading = true
12870   - clearTimeout(this.timeId)
12871   - this.timeId = setTimeout(() => {
12872   - this.createWs()
12873   - }, 60000)
12874   - }
12875   -
12876   - /**
12877   - * @description 发送消息
12878   - */
12879   - send(message) {
12880   - if (!this.ws || this.ws.readyState !== 1) {
12881   - this.errorStack.push(message)
12882   - return
12883   - }
12884   -
12885   - this.ws.send(message)
12886   - }
12887   -
12888   - /**
12889   - * @description 手动关闭
12890   - */
12891   - close() {
12892   - this.isCustomClose = true
12893   - this.ws.close()
12894   - }
12895   -
12896   - /**
12897   - * @description 手动开启
12898   - */
12899   - start() {
12900   - this.isCustomClose = false
12901   - this.reconnection()
12902   - }
12903   -
12904   - /**
12905   - * @description 销毁
12906   - */
12907   - destroy() {
12908   - this.close()
12909   - this.ws = null
12910   - this.errorStack = null
12911   - Ws.instance = null
12912   - }
12913   -
12914   - /**
12915   - * @description 单例模式
12916   - * @param {string} option.url - 连接路径
12917   - * @param {string} [option.protocols] option.protocols - 协议
12918   - * @param {Function} [option.onopenCallback] option.onopenCallback - socket open时 拓展
12919   - * @param {Function} [option.onerrorCallback] option.onerrorCallback - socket error时 拓展
12920   - * @param {Function} [option.oncloseCallback] option.oncloseCallback - socket close时 拓展
12921   - * @param {Function} [option.onmessageCallback] option.onmessageCallback - socket message时 拓展
12922   - * @return {Ws} instance
12923   - */
12924   - static getInstance(option) {
12925   - if (!this.instance) {
12926   - this.instance = new Ws(option)
12927   - }
12928   - return this.instance
12929   - }
12930   -}
12931   -
12932   -/**
12933   - * @description 切换页面时触发 /src/main/webapp/js/diagramly/Pages.js row: 461
12934   - * @param editorUi
12935   - * @param currentPage
12936   - */
12937   -function previewAction(editorUi, currentPage) {
12938   - if (!editorUi.editor.graph.isLightboxView()) return
12939   - DispatchCenter.getInstance(editorUi, currentPage)
12940   -
12941   - /**
12942   - * @description 编辑模式下editor对象的editable为true
12943   - * @param editorUi
12944   - * @return {boolean}
12945   - */
12946   - function isPreviewMode(editorUi = {}) {
12947   - const { editor: { editable } = {} } = editorUi
12948   - return !!editable
12949   - }
12950   -}
12951   -
12952   -
12953   -/**
12954   - * @description 调度中心
12955   - */
12956   -class DispatchCenter {
12957   -
12958   - /**
12959   - * @description 节点映射
12960   - * @type {Map<string, Map<string, object>>}
12961   - */
12962   - nodeMapping
12963   -
12964   - /**
12965   - * @description cmd ID 与 node 映射关系
12966   - * @type {Map<number, string>}
12967   - */
12968   - cmdIdMapping = new Map()
12969   -
12970   - /**
12971   - * @description
12972   - */
12973   - editorUi
12974   -
12975   - /**
12976   - * @description 当前页信息
12977   - */
12978   - currentPage
12979   -
12980   - /**
12981   - * @description 当前页中的所有cell
12982   - */
12983   - contentAllCell
12984   -
12985   - /**
12986   - * @description 图源信息
12987   - */
12988   - graph
12989   -
12990   - /**
12991   - * @description socket instance
12992   - * @type {Ws}
12993   - */
12994   - socket
12995   -
12996   - /**
12997   - * @description 事件总线
12998   - * @type {EventCenter}
12999   - */
13000   - eventBus
13001   -
13002   - /**
13003   - * @description 页面数据
13004   - * @type {{dataSources: [], act: [], event: []}}
13005   - */
13006   - contentData
13007   -
13008   - /**
13009   - * @description 处理数据源实例
13010   - * @type {HandleDataSource}
13011   - */
13012   - dataSourceHandlerInstance
13013   -
13014   - /**
13015   - * @description 处理数据动效实例
13016   - * @type {HandleDynamicEffect}
13017   - */
13018   - dynamicEffectInstance
13019   -
13020   - /**
13021   - * @description 处理数据交互实例
13022   - * @type {HandleDataInteraction}
13023   - */
13024   - dataInteractionInstance
13025   -
13026   - /**
13027   - * @description 更新队列
13028   - * @type {UpdateQueue}
13029   - */
13030   - updateQueueInstance
13031   -
13032   - /**
13033   - * @description cmd id
13034   - */
13035   - cmdIdPrimaryKey = 0
13036   -
13037   - /**
13038   - * @description 当前实例
13039   - * @type {DispatchCenter}
13040   - */
13041   - static instance
13042   -
13043   - /**
13044   - * @description 原页面ID 原页面content id
13045   - */
13046   - static rawContentId
13047   -
13048   - /**
13049   - * @description 判断事件监听器时候已经绑定过
13050   - */
13051   - static eventListenerIsExist = false
13052   -
13053   - static enumEventType = {
13054   - DOWN: 'DOWN',
13055   - UP: 'UP',
13056   - SINGLE: 'SINGLE',
13057   - DOUBLE: 'DOUBLE',
13058   - }
13059   -
13060   - static enumDynamicEffectType = {
13061   - DISPLAY: 'DISPLAY',
13062   - FLASH: 'FLASH',
13063   - ROTATE: 'ROTATE',
13064   - SWITCH: 'SWITCH',
13065   - }
13066   -
13067   - static enumPageType = {
13068   - PAGE: 'PAGE',
13069   - LINK: 'LINK',
13070   - PROPS: 'PROPS',
13071   - PARAMS_SETTING: 'PARAMS_SETTING'
13072   - }
13073   -
13074   -
13075   - constructor(editorUi, currentPage) {
13076   - this.nodeMapping = new Map()
13077   - this.editorUi = editorUi
13078   - this.init(editorUi, currentPage)
13079   - }
13080   -
13081   - /**
13082   - * @description 初始化实例
13083   - * @param editorUi
13084   - * @param currentPage
13085   - */
13086   - async init(editorUi, currentPage) {
13087   - this.createEventBus()
13088   - this.saveContentInfo(editorUi, currentPage)
13089   - this.connectSocket()
13090   - await this.getContentDataNode()
13091   - this.dataSourceHandlerInstance = new HandleDataSource(this)
13092   - this.dataInteractionInstance = new HandleDataInteraction(this)
13093   - this.dynamicEffectInstance = new HandleDynamicEffect(this)
13094   - this.updateQueueInstance = new UpdateQueue(this)
13095   - }
13096   -
13097   - /**
13098   - * @description 建立socket连接
13099   - */
13100   - connectSocket() {
13101   - Ws.instance?.destroy?.()
13102   - this.socket = Ws.getInstance({ url: GLOBAL_WS_URL(), onmessageCallback: this.socketOnmessage })
13103   - }
13104   -
13105   - /**
13106   - * @description 处理webSocket消息
13107   - * @param message
13108   - * @param event
13109   - * @param ws
13110   - */
13111   - socketOnmessage(message, event, ws) {
13112   - const { subscriptionId, data } = message
13113   - DispatchCenter.instance.publishEvent(subscriptionId, data, message, event, ws)
13114   - }
13115   -
13116   - /**
13117   - * @description 创建事件中心
13118   - */
13119   - createEventBus() {
13120   - this.eventBus = new EventCenter()
13121   - }
13122   -
13123   - /**
13124   - * @description 保存部分页面信息到实例上
13125   - * @param editorUi
13126   - * @param currentPage
13127   - */
13128   - saveContentInfo(editorUi, currentPage) {
13129   - const editor = editorUi.editor
13130   - this.graph = editor.graph
13131   - this.currentPage = currentPage
13132   - this.contentAllCell = this.graph.getDefaultParent().children || []
13133   - }
13134   -
13135   - /**
13136   - * @description 获取页面绑定的节点信息
13137   - */
13138   - async getContentDataNode() {
13139   - const { node: { id } = {} } = this.currentPage
13140   - if (!id) return
13141   - const [err, res] = await to(ConfigurationNodeApi.getConfigurationInfo('CONTENT', id))
13142   - this.contentData = res
13143   - }
13144   -
13145   - /**
13146   - * @description 发送消息去获取实时数据
13147   - */
13148   - sendMessageToGetRealTimeData(message) {
13149   - if (typeof message !== 'string') message = JSON.stringify(message)
13150   - this.socket.send(message)
13151   - }
13152   -
13153   - /**
13154   - * @description 通过传入NodeId获取cmdId
13155   - * @param nodeId
13156   - * @return {number}
13157   - */
13158   - getCmdId(nodeId) {
13159   - const cmdId = this.cmdIdPrimaryKey++
13160   - this.cmdIdMapping.set(cmdId, nodeId)
13161   - return cmdId
13162   - }
13163   -
13164   - /**
13165   - * @description 生成节点映射表
13166   - * @param dataSources
13167   - * @return {{cmdId: number, entityType: string, keys: *, scope: string, entityId: *}[]}
13168   - */
13169   - generatorDataSourceMapping(dataSources = []) {
13170   - return dataSources.map((datum) => {
13171   - const { deviceId, attr, nodeId, slaveDeviceId } = datum
13172   - const cmdId = this.getCmdId(nodeId)
13173   - const sendMsgTemplate = {
13174   - entityType: "DEVICE",
13175   - entityId: slaveDeviceId ? slaveDeviceId : deviceId,
13176   - scope: "LATEST_TELEMETRY",
13177   - cmdId,
13178   - keys: attr,
13179   - }
13180   - this.subscribeDataSources(datum, cmdId, attr)
13181   - return sendMsgTemplate
13182   - })
13183   - }
13184   -
13185   - /**
13186   - * @description 分发事件
13187   - */
13188   - publishEvent(eventName, data, message, event, ws) {
13189   - // data = data ? data : {}
13190   - this.eventBus.emit(eventName, message, event, ws)
13191   - // console.log(arguments)
13192   - // Object.keys(data).forEach(() => {
13193   - // this.eventBus.emit(eventName, message, event, ws)
13194   - // })
13195   - }
13196   -
13197   - /**
13198   - * @description 订阅数据源
13199   - * @param datum
13200   - * @param eventName
13201   - * @param key
13202   - */
13203   - subscribeDataSources(datum, eventName, key) {
13204   - const node = this.contentAllCell.find(item => item.id === datum.nodeId)
13205   - this.eventBus.on(eventName, (message) => {
13206   - node && this.updatePage(() => {
13207   - const { data } = message
13208   - const [[timespan, value]] = data[key]
13209   - node.setValue(value)
13210   - }, node)
13211   - })
13212   - }
13213   -
13214   - /**
13215   - * @description 更新页面
13216   - * @param callback
13217   - * @param cell
13218   - */
13219   - updatePage(callback, cell) {
13220   - this.graph.getModel().beginUpdate()
13221   - try {
13222   - callback()
13223   - this.graph.refresh(cell);
13224   - } finally {
13225   - this.graph.getModel().endUpdate()
13226   - }
13227   - }
13228   -
13229   -
13230   - /**
13231   - * @description 返回 DispatchCenter 实例 当contentID变化时重新创建实例
13232   - * @param editorUi
13233   - * @param currentPage
13234   - * @return {*}
13235   - */
13236   - static getInstance(editorUi, currentPage = {}) {
13237   - const { node: { id } = {} } = currentPage
13238   - if (!id) return
13239   - if (!DispatchCenter.instance || DispatchCenter.rawContentId !== id) {
13240   - DispatchCenter.instance?.dynamicEffectInstance?.cleanSetInterval?.()
13241   - DispatchCenter.instance?.updateQueueInstance?.cleanAllUpdateQueue?.()
13242   - DispatchCenter.instance = new DispatchCenter(editorUi, currentPage)
13243   - DispatchCenter.rawContentId = id
13244   - }
13245   -
13246   - return DispatchCenter.instance
13247   - }
13248   -
13249   -}
13250   -
13251   -class HandleDataSource {
13252   -
13253   - static enumConst = {
13254   -
13255   - /**
13256   - * @description 聚合方式
13257   - */
13258   - AGG: 'agg',
13259   -
13260   - /**
13261   - * @description 间隔方式
13262   - */
13263   - INTERVAL: 'interval',
13264   -
13265   - /**
13266   - * @description 单位
13267   - */
13268   - UNIT: 'unit',
13269   -
13270   - /**
13271   - * @description 开始时间
13272   - */
13273   - STARTTs: 'startTs',
13274   -
13275   - /**
13276   - * @description 结束时间
13277   - */
13278   - ENDTs: 'endTs',
13279   -
13280   - /**
13281   - * @description 范围
13282   - */
13283   - EFFECT_SCOPE: 'effectScope',
13284   -
13285   - /**
13286   - * @description 绑定数据类型
13287   - */
13288   - DATA_TYPE: 'dataType'
13289   - }
13290   -
13291   -
13292   - static enumDataBindType = {
13293   -
13294   - /**
13295   - * @description 历史
13296   - */
13297   - HISTORY: 'historyCmds',
13298   -
13299   - /**
13300   - * @description 事实
13301   - */
13302   - REAL: 'tsSubCmds'
13303   - }
13304   -
13305   - /**
13306   - * @description 数据源节点映射
13307   - * @type {Map<string, object>}
13308   - */
13309   - dataSourceNodeMapping = new Map()
13310   -
13311   - /**
13312   - * @description 派发队列
13313   - * @type {DispatchCenter}
13314   - */
13315   - DispatchInstance
13316   -
13317   - constructor(DispatchInstance) {
13318   - this.DispatchInstance = DispatchInstance
13319   - this.generatorCommonDataSourceMapping()
13320   - this.generatorChartDataSourceMapping()
13321   - }
13322   -
13323   - get graph() {
13324   - return this.DispatchInstance.graph
13325   - }
13326   -
13327   - /**
13328   - * @description 普通数据源绑定列表
13329   - */
13330   - get commonDataSourceBindList() {
13331   - return this.DispatchInstance.contentData?.dataSources?.filter(item => !item.additional && item.attr) || []
13332   - }
13333   -
13334   - /**
13335   - * @description 图表数据源绑定列表
13336   - */
13337   - get chartDataSourceBindList() {
13338   - return this.DispatchInstance.contentData?.dataSources?.filter(item => item.additional) || []
13339   - }
13340   -
13341   - get cmdIdMapping() {
13342   - return this.DispatchInstance.cmdIdMapping
13343   - }
13344   -
13345   - get basicAttr() {
13346   - return Sidebar.prototype.enumCellBasicAttribute
13347   - }
13348   -
13349   - get componentType() {
13350   - return Sidebar.prototype.enumComponentType
13351   - }
13352   -
13353   - get contentAllCell() {
13354   - return this.graph.getDefaultParent().children || []
13355   - }
13356   -
13357   - /**
13358   - * @description 生成普通数据源绑定映射关系
13359   - * @param dataSources
13360   - * @return {{cmdId: number, entityType: string, keys: *, scope: string, entityId: *}[]}
13361   - */
13362   - generatorCommonDataSourceMapping() {
13363   - const msg = this.commonDataSourceBindList.map((datum) => {
13364   - const { deviceId, attr, nodeId, slaveDeviceId } = datum
13365   - const cmdId = this.getCmdId(nodeId)
13366   - const sendMsgTemplate = {
13367   - entityType: "DEVICE",
13368   - entityId: slaveDeviceId ? slaveDeviceId : deviceId,
13369   - scope: "LATEST_TELEMETRY",
13370   - cmdId,
13371   - keys: attr,
13372   - }
13373   - this.dataSourceNodeMapping.set(nodeId, datum)
13374   - this.subscribeEvent(cmdId, this.updateCommonDataSource.bind(this))
13375   - return sendMsgTemplate
13376   - })
13377   - const { REAL } = HandleDataSource.enumDataBindType
13378   - if (msg.length) this.sendMsg({ [REAL]: msg })
13379   - }
13380   -
13381   -
13382   - /**
13383   - * @description 图表数据源绑定关系
13384   - * @param {any[]} dataSource
13385   - */
13386   - generatorChartDataSourceMapping() {
13387   - const realList = []
13388   - const historyList = []
13389   - const { HISTORY, REAL } = HandleDataSource.enumDataBindType
13390   - const { STARTTs, ENDTs } = HandleDataSource.enumConst
13391   - for (const item of this.chartDataSourceBindList) {
13392   - const { additional = {}, deviceId, attr, nodeId, slaveDeviceId } = item
13393   - if (!attr) continue
13394   - const { agg, interval = 1000, dataType, effectScope = 0 } = additional
13395   - const cmdId = this.getCmdId(nodeId)
13396   - const template = {
13397   - entityType: "DEVICE",
13398   - entityId: slaveDeviceId ? slaveDeviceId : deviceId,
13399   - cmdId,
13400   - interval: Number(interval),
13401   - agg,
13402   - keys: attr,
13403   - }
13404   - let scope = isNaN(effectScope) ? 0 : Number(effectScope)
13405   - if (dataType === HISTORY) {
13406   - template[STARTTs] = Date.now() - scope
13407   - template[ENDTs] = Date.now()
13408   - historyList.push(template)
13409   - this.subscribeEvent(cmdId, (message) => {
13410   - this.updateHistoryDataSource(message, agg)
13411   - })
13412   - }
13413   - else if (dataType === REAL) {
13414   - template[STARTTs] = Date.now() - scope
13415   - // template['timeWindow'] = interval
13416   - realList.push(template)
13417   - this.subscribeEvent(cmdId, (message) => {
13418   - this.updateRealTimeDataSource(message, agg)
13419   - })
13420   - }
13421   - this.dataSourceNodeMapping.set(nodeId, item)
13422   - }
13423   -
13424   - if (historyList.length || realList.length) this.sendMsg({ [HISTORY]: historyList, [REAL]: realList })
13425   - }
13426   -
13427   - /**
13428   - * @description 订阅事件 绑定回调
13429   - * @param eventName
13430   - * @param callback
13431   - */
13432   - subscribeEvent(eventName, callback) {
13433   - this.DispatchInstance.eventBus.on(eventName, callback)
13434   - }
13435   -
13436   - /**
13437   - * @description 更新变量值
13438   - * @param {} message
13439   - */
13440   - updateCommonDataSource(message) {
13441   - const { subscriptionId } = message
13442   - const node = this.getNodeByCmdId(subscriptionId)
13443   - const { attr } = this.getBindData(subscriptionId)
13444   - node && this.updatePage(() => {
13445   - const { data } = message
13446   - const type = this.getComponentType(node)
13447   - if (type === this.componentType.SWITCH) {
13448   - this.handleSwitchComponent(message)
13449   - return
13450   - }
13451   -
13452   - if (type === this.componentType.PARAMS_SETTING_BUTTON) {
13453   - this.handleParamSettingButton(message)
13454   - return
13455   - }
13456   -
13457   - if (type === this.componentType.IMAGE) {
13458   - this.handleImageComponent(message)
13459   - return
13460   - }
13461   -
13462   - if (!data) return
13463   - const [[timespan, value]] = data[attr]
13464   - node.setValue(value)
13465   - }, node)
13466   - }
13467   -
13468   - /**
13469   - * @description 处理switch 组件
13470   - * @param {} message
13471   - */
13472   - handleSwitchComponent(message) {
13473   - const { subscriptionId, data = {} } = message
13474   - const node = this.getNodeByCmdId(subscriptionId)
13475   - const { nodeId, attr } = this.getBindData(subscriptionId)
13476   - const [[timespan, receiveValue] = []] = data[attr] || []
13477   - const switchConfig = this.DispatchInstance.contentData.act.find(item => item.id === nodeId && item.type === 'SWITCH')
13478   - const { condition = [] } = switchConfig || {}
13479   - let reg = /image=[^;]+/g
13480   - let flag = false
13481   - const { SWITCH_STATE, SWITCH_VALUE, SWITCH_SEND_VALUE } = Sidebar.prototype.enumComponentType
13482   - const { SWITCH_STATE_NONE } = Sidebar.prototype.enumComponentTypeValue
13483   -
13484   - const getSendValue = (type) => {
13485   - return (condition.find(item => item.type !== type) || {}).value
13486   - }
13487   - for (const item of condition) {
13488   - const { value, imagePath, type } = item || {}
13489   - if (Number(receiveValue) === Number(value)) {
13490   - flag = true
13491   - this.updatePage(() => {
13492   - const style = node.getStyle()
13493   - const sendValue = getSendValue(type)
13494   - node.setStyle(style.replace(reg, `image=${imagePath}`))
13495   - node.setAttribute('label', '')
13496   - node.setAttribute(SWITCH_VALUE, receiveValue)
13497   - node.setAttribute(SWITCH_SEND_VALUE, sendValue)
13498   - node.setAttribute(SWITCH_STATE, type)
13499   - }, node)
13500   - break
13501   - }
13502   - }
13503   - if (!flag) {
13504   - this.updatePage(() => {
13505   - const style = node.getStyle()
13506   - node.setStyle(style.replace(reg, `image=images/thingskit/not-standard-value.svg`))
13507   - node.setAttribute('label', receiveValue)
13508   - node.setAttribute(SWITCH_VALUE, receiveValue)
13509   - node.setAttribute(SWITCH_STATE, SWITCH_STATE_NONE)
13510   - }, node)
13511   - }
13512   -
13513   - }
13514   -
13515   - handleParamSettingButton(message) {
13516   - const { subscriptionId, data = {} } = message
13517   - if (!data) return
13518   - const node = this.getNodeByCmdId(subscriptionId)
13519   - const { attr } = this.getBindData(subscriptionId)
13520   - const [[timespan, receiveValue] = []] = data[attr] || []
13521   - this.updatePage(() => {
13522   - node.setAttribute('label', `<button class="param-setting-button">${receiveValue}</button>`)
13523   - }, node)
13524   - }
13525   -
13526   - handleImageComponent(message) {
13527   - const { subscriptionId, data = {} } = message
13528   - const node = this.getNodeByCmdId(subscriptionId)
13529   - const { attr } = this.getBindData(subscriptionId)
13530   - const [[timespan, receiveValue] = []] = data[attr] || []
13531   - this.updatePage(() => {
13532   - node.setAttribute('label', `<img class="basic-component__image" alt="图片" src="${receiveValue}" />`)
13533   - }, node)
13534   - }
13535   -
13536   - /**
13537   - * @description 更新实时数据
13538   - * @param {} message
13539   - * @param {} agg 聚合方式
13540   - */
13541   - updateRealTimeDataSource(message, agg) {
13542   - const { data = {}, subscriptionId } = message
13543   - const node = this.getNodeByCmdId(subscriptionId)
13544   - if (!node) return
13545   - const enumConst = Sidebar.prototype.enumCellBasicAttribute
13546   - const chartInstanceMap = Sidebar.prototype.chartsInstanceMapping
13547   - const chartInstanceId = node.getAttribute(enumConst.CHART_INSTANCE_ID)
13548   - const chartInstanceType = node.getAttribute(enumConst.COMPONENT_TYPE)
13549   - const instance = chartInstanceMap.get(chartInstanceId)
13550   - const { attr = [[]] } = this.getBindData(subscriptionId)
13551   - const realDataList = data[attr] || []
13552   -
13553   - const action = agg === 'NONE' ? 'unshift' : 'push'
13554   -
13555   - // chart insstance 是否已经接受过一次消息推送
13556   - const isActive = instance.isActive
13557   - if (!isActive) {
13558   - instance.isActive = true
13559   - const chartOption = this.getChartComponentOption(chartInstanceType, { chartType: chartInstanceType, attr, dataList: realDataList, action, nodeId: node.id })
13560   - instance.setOption(chartOption)
13561   -
13562   - } else {
13563   - const oldOptions = instance.getOption()
13564   - const options = this.getRealTimeUpdateChartOption(chartInstanceType, { oldOptions, dataList: realDataList })
13565   - if (!instance) clearInterval(interval)
13566   - instance && instance.setOption(options)
13567   - }
13568   - }
13569   -
13570   - /**
13571   - * @description 更新历史数据
13572   - */
13573   - updateHistoryDataSource(message, agg) {
13574   - const { data = {}, subscriptionId } = message
13575   - const node = this.getNodeByCmdId(subscriptionId)
13576   - if (!node) return
13577   - const enumConst = Sidebar.prototype.enumCellBasicAttribute
13578   - const chartInstanceMap = Sidebar.prototype.chartsInstanceMapping
13579   - const chartInstanceId = node.getAttribute(enumConst.CHART_INSTANCE_ID)
13580   - const chartInstanceType = node.getAttribute(enumConst.COMPONENT_TYPE)
13581   - const instance = chartInstanceMap.get(chartInstanceId)
13582   - const { attr = [[]] } = this.getBindData(subscriptionId)
13583   - const historyDataList = data[attr] || []
13584   - const showNumberOf = 4
13585   - const action = agg === 'NONE' ? 'unshift' : 'push'
13586   -
13587   - const chartOption = this.getChartComponentOption(chartInstanceType, { dataList: historyDataList, attr, chartType: chartInstanceType, action })
13588   -
13589   - let interval
13590   - // TODO 清除定时器
13591   - function autoMove() {
13592   - if (seriesValue.length <= 5) return
13593   - interval = setInterval(() => {
13594   - if (Number(chartOption.dataZoom[0].endValue) === seriesValue.length - 1) {
13595   - chartOption.dataZoom[0].endValue = showNumberOf
13596   - chartOption.dataZoom[0].startValue = 0
13597   - } else {
13598   - chartOption.dataZoom[0].endValue = chartOption.dataZoom[0].endValue + 1
13599   - chartOption.dataZoom[0].startValue = chartOption.dataZoom[0].startValue + 1
13600   - }
13601   - if (!chartInstanceMap.has(chartInstanceId)) {
13602   - clearInterval(interval)
13603   - return
13604   - }
13605   - instance && instance.setOption(chartOption)
13606   -
13607   - }, 2000);
13608   - }
13609   -
13610   - function stop() {
13611   - clearInterval(interval)
13612   - }
13613   -
13614   - function goMove() {
13615   - autoMove()
13616   - }
13617   -
13618   - instance.setOption(chartOption)
13619   - // instance.on('mouseover', stop)
13620   - // instance.on('mouseout', goMove)
13621   - // autoMove()
13622   - }
13623   -
13624   - getChartComponentOption(chartInstanceType, params) {
13625   - const { LINE_CHART, BAR_CHART, DASHBOARD_CHART } = Sidebar.prototype.enumComponentType
13626   - switch (chartInstanceType) {
13627   - case LINE_CHART:
13628   - return this.getBasicChartOption(Object.assign(params, { chartType: 'line' }))
13629   - case BAR_CHART:
13630   - return this.getBasicChartOption(Object.assign(params, { chartType: 'bar' }))
13631   - case DASHBOARD_CHART:
13632   - return this.getDashboardChartOption(params)
13633   - default:
13634   - return {}
13635   - }
13636   - }
13637   -
13638   - getRealTimeUpdateChartOption(chartInstanceType, params) {
13639   - const { LINE_CHART, BAR_CHART, DASHBOARD_CHART } = Sidebar.prototype.enumComponentType
13640   - switch (chartInstanceType) {
13641   - case LINE_CHART:
13642   - return this.getRealTimeUpdateBasicChartOption(params)
13643   - case BAR_CHART:
13644   - return this.getRealTimeUpdateBasicChartOption(params)
13645   - case DASHBOARD_CHART:
13646   - return this.getRealTimeUpdateDashboardChartOption(params)
13647   - default:
13648   - return {}
13649   - }
13650   - }
13651   -
13652   - /**
13653   - *
13654   - * @param {@} params
13655   - * @returns
13656   - */
13657   - getBasicChartOption(params = { dataList: [], attr: '', chartType: 'bar', action }) {
13658   - const { dataList = [], attr = '', chartType = 'bar', action } = params
13659   -
13660   - const xAxisData = []
13661   - const seriesValue = []
13662   -
13663   - dataList.forEach(item => {
13664   - const [timespan, value] = item
13665   - xAxisData[action](new Date(Number(timespan)).toLocaleTimeString())
13666   - seriesValue[action](Number(value))
13667   - })
13668   -
13669   - return {
13670   - title: {
13671   - subtext: dataList.length ? '' : '暂无数据',
13672   - x: 'center',
13673   - y: 'center',
13674   - itemGap: -20,
13675   - subtextStyle: {
13676   - fontSize: 16
13677   - }
13678   - },
13679   - tooltip: {
13680   - trigger: 'axis',
13681   - axisPointer: {
13682   - type: 'shadow'
13683   - }
13684   - },
13685   - grid: {
13686   - left: '3%',
13687   - right: '3%',
13688   - bottom: '3%',
13689   - containLabel: true,
13690   - },
13691   - xAxis: {
13692   - name: '时间',
13693   - type: 'category',
13694   - data: xAxisData,
13695   - boundaryGap: true,
13696   - axisLabel: {
13697   - rotate: 70
13698   - },
13699   - axisPointer: {
13700   - label: {
13701   - formatter() {
13702   - return attr
13703   - }
13704   - }
13705   - }
13706   - },
13707   - yAxis: {
13708   - type: 'value'
13709   - },
13710   - series: [
13711   - {
13712   - data: seriesValue,
13713   - type: chartType,
13714   - }
13715   - ],
13716   - dataZoom: [
13717   - {
13718   - show: true,
13719   - type: 'inside'
13720   - }
13721   - ]
13722   - }
13723   - }
13724   -
13725   - getRealTimeUpdateBasicChartOption(params = { oldOptions: {}, dataList: [] }) {
13726   - const { oldOptions, dataList } = params
13727   - const xAxisData = oldOptions.xAxis[0].data || []
13728   - const seriesValue = oldOptions.series[0].data || []
13729   - const oldEndValue = Number(oldOptions.dataZoom[0].endValue) || 0
13730   - const oldStartValue = Number(oldOptions.dataZoom[0].startValue) || 0
13731   - const showNumberOf = 4
13732   -
13733   - for (let i = dataList.length - 1; i >= 0; i--) {
13734   - const [timespan, value] = dataList[i]
13735   - xAxisData.push(new Date(Number(timespan)).toLocaleTimeString())
13736   - seriesValue.push(Number(value))
13737   - }
13738   -
13739   - if (Number(oldOptions.dataZoom[0].endValue) === seriesValue.length - 1) {
13740   - oldOptions.dataZoom[0].endValue = showNumberOf
13741   - oldOptions.dataZoom[0].startValue = 0
13742   - } else {
13743   - oldOptions.dataZoom[0].endValue = oldOptions.dataZoom[0].endValue + 1
13744   - oldOptions.dataZoom[0].startValue = oldOptions.dataZoom[0].startValue + 1
13745   - }
13746   -
13747   - return {
13748   - title: {
13749   - subtext: ''
13750   - },
13751   - xAxis: {
13752   - data: xAxisData
13753   - },
13754   - series: [
13755   - {
13756   - data: seriesValue
13757   - }
13758   - ],
13759   - dataZoom: [
13760   - {
13761   - show: true,
13762   - type: 'inside',
13763   - }
13764   - ]
13765   - }
13766   - }
13767   -
13768   - getDashboardChartOption(params = { dataList: [], nodeId }) {
13769   - const { dataList = [], nodeId } = params
13770   - const dataSource = this.DispatchInstance.contentData.dataSources.find(item => item.nodeId === nodeId) || {}
13771   - const { additional: { unit = '°C' } = {} } = dataSource
13772   -
13773   - const [timespan, value] = dataList[0] || []
13774   - return {
13775   - series: [
13776   - {
13777   - type: 'gauge',
13778   - center: ['50%', '60%'],
13779   - radius: '100%',
13780   - startAngle: 200,
13781   - endAngle: -20,
13782   - min: 0,
13783   - max: 100,
13784   - splitNumber: 10,
13785   - itemStyle: {
13786   - color: '#5479c6'
13787   - // color: '#FFAB91'
13788   - },
13789   - progress: {
13790   - show: true,
13791   - width: 30
13792   - },
13793   - pointer: {
13794   - show: false
13795   - },
13796   - axisLine: {
13797   - lineStyle: {
13798   - width: 30
13799   - }
13800   - },
13801   - axisTick: {
13802   - distance: 0,
13803   - splitNumber: 5,
13804   - lineStyle: {
13805   - width: 2,
13806   - color: '#999'
13807   - }
13808   - },
13809   - splitLine: {
13810   - distance: 0,
13811   - length: 14,
13812   - lineStyle: {
13813   - width: 3,
13814   - color: '#999'
13815   - }
13816   - },
13817   - axisLabel: {
13818   - distance: 35,
13819   - color: '#999',
13820   - fontSize: 20
13821   - },
13822   - anchor: {
13823   - show: false
13824   - },
13825   - title: {
13826   - show: false
13827   - },
13828   - detail: {
13829   - valueAnimation: true,
13830   - width: '60%',
13831   - lineHeight: 40,
13832   - borderRadius: 8,
13833   - offsetCenter: [0, '-15%'],
13834   - fontSize: 25,
13835   - fontWeight: 'bolder',
13836   - formatter: `{value} ${unit}`,
13837   - color: 'auto'
13838   - },
13839   - data: [
13840   - {
13841   - value
13842   - }
13843   - ]
13844   - },
13845   - ]
13846   - }
13847   - }
13848   -
13849   - /**
13850   - * @description 获取仪表盘配置
13851   - */
13852   - getRealTimeUpdateDashboardChartOption(params = { dataList: [] }) {
13853   - const { dataList = [], oldOptions } = params
13854   - const [timespan, value] = dataList[0] || []
13855   - console.log(value)
13856   - return {
13857   - series: [
13858   - {
13859   - data: [
13860   - {
13861   - value
13862   - }
13863   - ]
13864   - },
13865   - ]
13866   - }
13867   - }
13868   -
13869   - /**
13870   - * @description 获取绑定的数据
13871   - * @param subscriptionId
13872   - * @param actionType
13873   - * @return {*}
13874   - */
13875   - getBindData(subscriptionId) {
13876   - const nodeId = this.getNodeIdByCmdId(subscriptionId)
13877   - const temp = this.dataSourceNodeMapping.get(nodeId) || {}
13878   - return temp
13879   - }
13880   -
13881   - /**
13882   - * @description 获取cmdId
13883   - * @param {string} nodeId
13884   - * @returns
13885   - */
13886   - getCmdId(nodeId) {
13887   - return this.DispatchInstance.getCmdId(nodeId)
13888   - }
13889   -
13890   - /**
13891   - * @description 通过cmdID获取节点id
13892   - * @param subscriptionId
13893   - * @return {string}
13894   - */
13895   - getNodeIdByCmdId(subscriptionId) {
13896   - return this.DispatchInstance.cmdIdMapping.get(subscriptionId)
13897   - }
13898   -
13899   - /**
13900   - * @description 通过cmdID 获取节点
13901   - * @param subscriptionId
13902   - * @return {*}
13903   - */
13904   - getNodeByCmdId(subscriptionId) {
13905   - const nodeId = this.getNodeIdByCmdId(subscriptionId)
13906   - return this.contentAllCell.find(item => item.id === nodeId)
13907   - }
13908   -
13909   - getComponentType(node) {
13910   - return node.getAttribute(this.basicAttr.COMPONENT_TYPE)
13911   - }
13912   -
13913   - /**
13914   - * @description 发送socket 消息
13915   - * @param {any} msg
13916   - * @returns
13917   - */
13918   - sendMsg(msg) {
13919   - return this.DispatchInstance.sendMessageToGetRealTimeData(msg)
13920   - }
13921   -
13922   - updatePage(callback, cell) {
13923   - return this.DispatchInstance.updatePage(callback, cell)
13924   - }
13925   -}
13926   -
13927   -class HandleDataInteraction {
13928   - /**
13929   - * @description 事件分发中心实例
13930   - * @type {DispatchCenter}
13931   - */
13932   - DispatchInstance
13933   -
13934   - /**
13935   - * @description 事件映射
13936   - * @type {Map<>}
13937   - */
13938   - static eventMapping = new Map()
13939   -
13940   - constructor(DispatchInstance) {
13941   - this.DispatchInstance = DispatchInstance
13942   - HandleDataInteraction.eventMapping = new Map()
13943   - this.init()
13944   - }
13945   -
13946   - init() {
13947   - this.generatorEventMapping()
13948   - this.createGraphEventListener()
13949   - }
13950   -
13951   - get eventMapping() {
13952   - return HandleDataInteraction.eventMapping
13953   - }
13954   -
13955   - /**
13956   - * @description DispatchCenter 实例中保存的 graph 对象
13957   - * @return {*}
13958   - */
13959   - get graph() {
13960   - return this.DispatchInstance.graph
13961   - }
13962   -
13963   - /**
13964   - * @description DispatchCenter 实例中保存的 editorUi 对象
13965   - * @return {*}
13966   - */
13967   - get editorUi() {
13968   - return this.DispatchInstance.editorUi
13969   - }
13970   -
13971   - /**
13972   - * @description DispatchCenter 实例中保存的 contentAllCell 对象
13973   - * @return {*}
13974   - */
13975   - get eventList() {
13976   - const { event = [] } = this.DispatchInstance.contentData
13977   - return event
13978   - }
13979   -
13980   - /**
13981   - * @description 获取页面数据
13982   - */
13983   - get contentData() {
13984   - return DispatchCenter.instance.contentData
13985   - }
13986   -
13987   - get contentAllCell() {
13988   - return this.graph.getDefaultParent().children || []
13989   - }
13990   -
13991   - /**
13992   - * @description 事件映射
13993   - */
13994   - generatorEventMapping() {
13995   - const event = this.eventList
13996   - for (const item of event) {
13997   - const { content, id: nodeId, enabled, type } = item
13998   - if (!enabled) continue
13999   - if (!this.eventMapping.has(nodeId)) this.eventMapping.set(nodeId, new Map())
14000   - const temp = this.eventMapping.get(nodeId)
14001   - temp.set(type, content)
14002   - }
14003   - }
14004   -
14005   - createGraphEventListener() {
14006   - if (DispatchCenter.eventListenerIsExist) return
14007   -
14008   - const graphDblClick = this.graph.dblClick;
14009   - this.graph.dblClick = (...args) => {
14010   - this.handleDoubleClickEvent(...args)
14011   - graphDblClick.apply(this.graph, args)
14012   - }
14013   -
14014   - const graphClick = this.graph.click;
14015   - this.graph.click = (...args) => {
14016   - this.handleClickEvent(...args)
14017   - graphClick.apply(this.graph, args)
14018   - }
14019   -
14020   - const mouseDownEvent = this.throttle(this.handleMouseDownEvent)
14021   - const mouseUpEvent = this.throttle(this.handleMouseUpEvent)
14022   - const graphFireMouseEvent = this.graph.fireMouseEvent;
14023   - this.graph.fireMouseEvent = (eventName, event, sender) => {
14024   - if (eventName === mxEvent.MOUSE_DOWN) {
14025   - // this.handleMouseDownEvent(eventName, event, sender)
14026   - mouseDownEvent(eventName, event, sender)
14027   - }
14028   - if (eventName === mxEvent.MOUSE_UP) {
14029   - mouseUpEvent(eventName, event, sender)
14030   - // this.handleMouseUpEvent(eventName, event, sender)
14031   - }
14032   - graphFireMouseEvent.apply(this.graph, [eventName, event, sender]);
14033   - };
14034   -
14035   - DispatchCenter.eventListenerIsExist = true
14036   - }
14037   -
14038   - /**
14039   - * @description 处理按下事件
14040   - * @param eventName
14041   - * @param event
14042   - * @param sender
14043   - */
14044   - handleMouseDownEvent(eventName, event, sender) {
14045   - const { state } = event
14046   - if (!state) return
14047   - const { cell = {} } = state
14048   - const { id } = cell || {}
14049   - const temp = this.eventMapping.get(id)
14050   - if (temp && temp.has(DispatchCenter.enumEventType.DOWN)) {
14051   - const content = temp.get(DispatchCenter.enumEventType.DOWN)
14052   - this.sendInstruction(content.data)
14053   - }
14054   - }
14055   -
14056   - /**
14057   - * @description 处理抬起事件
14058   - * @param eventName
14059   - * @param event
14060   - * @param sender
14061   - */
14062   - handleMouseUpEvent(eventName, event, sender) {
14063   - const { state } = event
14064   - if (!state) return
14065   - const { cell = {} } = state
14066   - const { id } = cell || {}
14067   - const temp = this.eventMapping.get(id)
14068   - if (temp && temp.has(DispatchCenter.enumEventType.UP)) {
14069   - const content = temp.get(DispatchCenter.enumEventType.UP)
14070   - this.sendInstruction(content.data)
14071   - }
14072   - }
14073   -
14074   - /**
14075   - * @description 鼠标单击事件事件
14076   - * @param event
14077   - */
14078   - handleClickEvent(event) {
14079   - const { state } = event
14080   - if (!state) return
14081   - const { cell = {} } = state
14082   - const { id } = cell || {}
14083   - const temp = this.eventMapping.get(id)
14084   - if (temp && temp.has(DispatchCenter.enumEventType.SINGLE)) {
14085   - const content = temp.get(DispatchCenter.enumEventType.SINGLE)
14086   - const { type, value } = content
14087   - if (type === DispatchCenter.enumPageType.PAGE && value) {
14088   - this.jumpPage(value)
14089   - } else if (type === DispatchCenter.enumPageType.LINK && value) {
14090   - window.open(value)
14091   - } else if (type === DispatchCenter.enumPageType.PARAMS_SETTING) {
14092   - this.paramsSetting(id, content)
14093   - }
14094   - }
14095   - }
14096   -
14097   - /**
14098   - * @description 鼠标双击事件
14099   - * @param event
14100   - * @param cell
14101   - */
14102   - handleDoubleClickEvent(event, cell = {}) {
14103   - if (!cell) return
14104   - const { id } = cell
14105   - const temp = this.eventMapping.get(id)
14106   - if (temp && temp.has(DispatchCenter.enumEventType.DOUBLE)) {
14107   - const content = temp.get(DispatchCenter.enumEventType.DOUBLE)
14108   - const { type, value } = content
14109   - if (type === DispatchCenter.enumPageType.PAGE && value) {
14110   - this.jumpPage(value)
14111   - } else if (type === DispatchCenter.enumPageType.LINK && value) {
14112   - window.open(value)
14113   - }
14114   - }
14115   - }
14116   -
14117   -
14118   - /**
14119   - * @description 下发指令
14120   - * @param list
14121   - */
14122   - sendInstruction(list = []) {
14123   - const queue = []
14124   - const fn = async (way, deviceId, data) => {
14125   - const [err, res = []] = await to(ConfigurationNodeApi.deviceIsOnLine(deviceId))
14126   - const { value } = res[0] || {}
14127   - if (value) {
14128   - await to(ConfigurationNodeApi.sendInstruction(way, deviceId, data))
14129   - } else {
14130   - UseLayUi.errorMsg('设备不在线!')
14131   - }
14132   - }
14133   - for (const item of list) {
14134   - const { deviceId, slaveDeviceId, value, way } = item
14135   - if (!value || !deviceId) continue
14136   - const data = {
14137   - method: "methodThingskit",
14138   - params: JSON.parse(value),
14139   - }
14140   - if (deviceId) {
14141   - queue.push(() => {
14142   - fn(way, deviceId, data)
14143   - })
14144   - }
14145   - // if (slaveDeviceId) {
14146   - // queue.push(() => {
14147   - // fn(way, slaveDeviceId, data)
14148   - // })
14149   - // } else if (deviceId) {
14150   - // queue.push(() => {
14151   - // fn(way, deviceId, data)
14152   - // })
14153   - // }
14154   - }
14155   -
14156   - Promise.all(queue.map(fn => fn()))
14157   - }
14158   -
14159   - throttle(fn, time = 1000) {
14160   - let now = Date.now
14161   - let oldTime = now()
14162   - return (...args) => {
14163   - let newTime = now()
14164   - if (newTime - oldTime > time) {
14165   - oldTime = now()
14166   - fn.apply(this, args)
14167   - }
14168   - }
14169   - }
14170   -
14171   - /**
14172   - * @description 跳转页面
14173   - */
14174   - jumpPage(page) {
14175   - try {
14176   - this.editorUi.handleCustomLink(`data:page/id,${page}`)
14177   - } catch (error) {
14178   - throw error
14179   - }
14180   - }
14181   -
14182   - /**
14183   - * @description 参数设置
14184   - */
14185   - paramsSetting(nodeId, content) {
14186   - const { layer, jquery: $, form } = layui
14187   - const { SWITCH_STATE, SWITCH_VALUE, SWITCH_SEND_VALUE, SWITCH, PARAMS_SETTING_BUTTON } = Sidebar.prototype.enumComponentType
14188   - const { SWITCH_STATE_NONE } = Sidebar.prototype.enumComponentTypeValue
14189   - const { COMPONENT_TYPE } = Sidebar.prototype.enumCellBasicAttribute
14190   - const contentData = this.contentData
14191   - const currentNode = this.contentAllCell.find(item => item.id === nodeId)
14192   -
14193   - const enumConst = {
14194   - VALUE: 'value',
14195   - ISSUED_WAY: 'way',
14196   - ONE_WAY: 'oneway',
14197   - TWO_WAY: 'twoway',
14198   - ATTR_PLACEHOLDER: 'attrPlaceholder'
14199   - }
14200   -
14201   - const enumActionEl = {
14202   - CONTAINER: 'container',
14203   - EDITOR: 'editor',
14204   - ISSUED_WAY_FILTER: 'wayFilter'
14205   -
14206   - }
14207   -
14208   - function createContent() {
14209   - return `
14210   - <div>
14211   - <div class="layui-form" lay-filter="${enumActionEl.ISSUED_WAY_FILTER}">
14212   - <div class="layui-form-item">
14213   - <label class="layui-form-label">下发值</label>
14214   - <div class="layui-input-block">
14215   - <input type="text" name="${enumConst.VALUE}" lay-verify="required" autocomplete="off" placeholder="请输入下发值" class="layui-input">
14216   - </div>
14217   - </div>
14218   - </div>
14219   - </div>`
14220   - }
14221   -
14222   - function jsonParse(value) {
14223   - try {
14224   - return JSON.parse(value)
14225   - } catch (error) {
14226   - return {}
14227   - }
14228   - }
14229   -
14230   - function handleSwitchComponent() {
14231   - const state = currentNode.getAttribute(SWITCH_STATE)
14232   - const value = currentNode.getAttribute(SWITCH_SEND_VALUE)
14233   - if (state === SWITCH_STATE_NONE) {
14234   - return
14235   - }
14236   - layer.confirm('是否确认下发命令?', async function (index) {
14237   - defaultHandler(value, () => layer.close(index))
14238   - });
14239   -
14240   -
14241   - }
14242   -
14243   - function replaceAttrPlaceholder(oldValue = {}, replaceAttr = '', replaceValue = '', newValue = {},) {
14244   - if (typeof oldValue !== 'object') return newValue
14245   -
14246   - for (const key of Object.keys(oldValue)) {
14247   - if (key === enumConst.ATTR_PLACEHOLDER) {
14248   - newValue[replaceAttr] = replaceValue
14249   - continue
14250   - }
14251   - if (typeof oldValue[key] === 'object') {
14252   - newValue[key] = replaceAttrPlaceholder(oldValue[key], replaceAttr, replaceValue)
14253   - continue
14254   - }
14255   - newValue[key] = oldValue[key]
14256   - }
14257   -
14258   - return newValue
14259   - }
14260   -
14261   - const submitThrottle = this.throttle(submit)
14262   - async function submit(callback) {
14263   - const { value } = form.val(enumActionEl.ISSUED_WAY_FILTER)
14264   - defaultHandler(value, callback)
14265   - }
14266   -
14267   - async function defaultHandler(value, callback) {
14268   - let { deviceId, attr } = contentData.dataSources.find(item => item.nodeId === nodeId) || {}
14269   - let { command, way } = content
14270   - const validate = new Validate([
14271   - { value, required: true, message: '下发值是必填项' },
14272   - { value: deviceId, required: true, message: '未绑定设备' },
14273   - { value: way, required: true, message: '未绑定指令下发方式(单向/双向)' },
14274   - { value: command, required: true, message: '未设置下发命令' },
14275   - { value: attr, required: true, message: '未绑定设备属性' },
14276   - ])
14277   - if (!validate.begin()) return
14278   - if (typeof command === 'string') command = jsonParse(command)
14279   - const data = replaceAttrPlaceholder(command, attr, value)
14280   - const instructionData = {
14281   - method: "methodThingskit",
14282   - params: data,
14283   - }
14284   -
14285   - const [err, res = []] = await to(ConfigurationNodeApi.deviceIsOnLine(deviceId))
14286   - const { value: onlineFlag } = res[0] || {}
14287   - if (onlineFlag) {
14288   - const [err, res] = await to(ConfigurationNodeApi.sendInstruction(way, deviceId, instructionData))
14289   - if (!err) {
14290   - UseLayUi.topSuccessMsg('操作成功')
14291   - callback && typeof callback === 'function' && callback()
14292   - }
14293   - } else {
14294   - UseLayUi.topErrorMsg('设备不在线!')
14295   - }
14296   - }
14297   -
14298   - function createLayer() {
14299   -
14300   - layer.open({
14301   - title: '参数设置',
14302   - content: createContent(),
14303   - area: '400px',
14304   - btn: ["应用", "取消"],
14305   - yes(index) {
14306   - submitThrottle(() => {
14307   - layer.close(index)
14308   - })
14309   - },
14310   - but2(index, layero) {
14311   -
14312   - },
14313   - async success(layero, index) {
14314   - $('.layui-layer-setwin a').removeAttr('href')
14315   - form.render()
14316   - },
14317   - })
14318   - }
14319   -
14320   -
14321   - function startProcess() {
14322   - const componentType = currentNode.getAttribute(COMPONENT_TYPE)
14323   - const handle = {
14324   - [SWITCH]: handleSwitchComponent,
14325   - [PARAMS_SETTING_BUTTON]: createLayer
14326   - }
14327   -
14328   - try {
14329   - handle[componentType]()
14330   - } catch (error) {
14331   -
14332   - }
14333   - }
14334   - startProcess()
14335   - }
14336   -}
14337   -
14338   -/**
14339   - * @description 处理数据动效
14340   - */
14341   -class HandleDynamicEffect {
14342   -
14343   - /**
14344   - * @description 事件分发中心实例
14345   - * @type {DispatchCenter}
14346   - */
14347   - DispatchInstance
14348   -
14349   - /**
14350   - * @description 开启的数据动效
14351   - * @type {any[]}
14352   - */
14353   - enableActList
14354   -
14355   - /**
14356   - * @description 视频记录列表
14357   - */
14358   - videoRecordList
14359   -
14360   - /**
14361   - * @description 动效节点映射
14362   - * @type {Map<string, {display: boolean, value: Map<string, any>}>}
14363   - */
14364   - actNodeMapping = new Map()
14365   -
14366   - /**
14367   - * @description clear setInterval
14368   - */
14369   - cleanSetInterval
14370   -
14371   - static enumConst = {
14372   - MAX: 'max',
14373   - MIN: 'min',
14374   - }
14375   -
14376   - static enumActType = {
14377   - FLASH: 'FLASH',
14378   - DISPLAY: 'DISPLAY',
14379   - ROTATE: 'ROTATE',
14380   - IMAGE: 'IMAGE',
14381   - RUNNING: 'RUNNING'
14382   - }
14383   -
14384   - static enumDisplayType = {
14385   - SHOW: 'show',
14386   - HIDDEN: 'hidden',
14387   - }
14388   -
14389   - static enumRunningType = {
14390   - RUN: 'run',
14391   - STOP: 'stop'
14392   - }
14393   -
14394   - static enumVideoConst = {
14395   - ORG_ID: 'orgId',
14396   - RECORD_ID: 'id',
14397   - VIDEO_URL: 'videoUrl',
14398   - ACCESSMODE: 'accessMode',
14399   - VIDEO_FLAG: 'videoComponentFlag'
14400   - }
14401   -
14402   - static enumVarImageConst = {
14403   -
14404   - /**
14405   - * @description 最小值
14406   - */
14407   - MIN: 'min',
14408   -
14409   - /**
14410   - * @description 最大值
14411   - */
14412   - MAX: 'max',
14413   -
14414   - /**
14415   - * @description 图片字段 key
14416   - */
14417   - IMAGE: 'image',
14418   -
14419   - /**
14420   - * @description 颜色
14421   - */
14422   - COLOR: 'color',
14423   -
14424   - /**
14425   - * @description 图片来源
14426   - */
14427   - IMAGE_ORIGIN: 'imageOrigin',
14428   -
14429   - /**
14430   - * @description 图库图形类别
14431   - */
14432   - IMAGE_GALLERY_CATEGORY: 'category',
14433   -
14434   - /**
14435   - * @description 图表图形路径
14436   - */
14437   - IMAGE_GALLERY_IMAGE_PATH: 'imagePath',
14438   -
14439   - /**
14440   - * @description 默认图片 flag
14441   - */
14442   - DEFAULT_IMAGE_FLAG: 'defaultImageFlag'
14443   - }
14444   -
14445   - static enumVideoAccessMode = {
14446   - MANUAL_ENTER: 0,
14447   - STREAMING: 1
14448   - }
14449   -
14450   - constructor(DispatchInstance) {
14451   - this.DispatchInstance = DispatchInstance
14452   - this.init()
14453   - }
14454   -
14455   - init() {
14456   - this.getEnableActList()
14457   - this.getVideoRecord()
14458   - this.generatorMappingRelation()
14459   - }
14460   -
14461   - get graph() {
14462   - return this.DispatchInstance.graph
14463   - }
14464   -
14465   - /**
14466   - * @description 只更新一次的更新事件
14467   - * @returns {*}
14468   - */
14469   - get insertOnceUpdateFn() {
14470   - return this.DispatchInstance.updateQueueInstance.insertOnceUpdateFn.bind(this.DispatchInstance.updateQueueInstance)
14471   - }
14472   -
14473   - /**
14474   - * @description 将持续更新时间放入更新队列
14475   - * @returns {*}
14476   - */
14477   - get insertContinueUpdateFn() {
14478   - return this.DispatchInstance.updateQueueInstance.insertContinueUpdateFn.bind(this.DispatchInstance.updateQueueInstance)
14479   - }
14480   -
14481   - /**
14482   - * @description 从更新队列中删除更新
14483   - * @returns {*}
14484   - */
14485   - get delUpdateFn() {
14486   - return this.DispatchInstance.updateQueueInstance.delUpdateFn.bind(this.DispatchInstance.updateQueueInstance)
14487   - }
14488   -
14489   - get contentAllCell() {
14490   - return this.graph.getDefaultParent().children || []
14491   - }
14492   -
14493   - /**
14494   - * @description 筛选出视频数据源
14495   - */
14496   - getVideoRecord() {
14497   - const { dataSources = [] } = this.DispatchInstance.contentData
14498   - const { VIDEO_FLAG } = HandleDynamicEffect.enumVideoConst
14499   - this.videoRecordList = dataSources.filter(item => item?.additional?.[VIDEO_FLAG])
14500   - }
14501   -
14502   - /**
14503   - * @description 获取已开启的数据动效
14504   - */
14505   - getEnableActList() {
14506   - const { act = [] } = this.DispatchInstance.contentData
14507   - // 过滤页面中没有的节点及未开启动效的节点
14508   - this.enableActList = act.filter(item => this.contentAllCell.find(each => each.id === item.id) && item.enabled)
14509   - // this.enableActList = act.filter(item => item.enabled)
14510   - }
14511   -
14512   - /**
14513   - * @description 生成映射关系 && 初始化推送消息
14514   - */
14515   - generatorMappingRelation() {
14516   - this.videoPlay()
14517   - const tsSubCmds = []
14518   - this.enableActList.forEach(each => {
14519   - const { id, type, attr, deviceId, slaveDeviceId } = each
14520   -
14521   - if (!this.actNodeMapping.has(id)) this.actNodeMapping.set(id, { display: true, value: new Map() })
14522   - const temp = this.actNodeMapping.get(id)
14523   - temp.value.set(type, each)
14524   -
14525   - const cmdId = this.DispatchInstance.getCmdId(id)
14526   -
14527   - tsSubCmds.push(this.generatorMessage(slaveDeviceId ? slaveDeviceId : deviceId, cmdId, attr))
14528   -
14529   - this.subscribeEvent(cmdId, this.dispatch(type))
14530   - })
14531   - if (tsSubCmds.length) this.sendMsg({ tsSubCmds })
14532   - }
14533   -
14534   - /**
14535   - * @description 推送消息
14536   - * @param msg
14537   - */
14538   - sendMsg(msg) {
14539   - this.DispatchInstance.sendMessageToGetRealTimeData(msg)
14540   - }
14541   -
14542   - /**
14543   - * @description 订阅事件 绑定回调
14544   - * @param eventName
14545   - * @param callback
14546   - */
14547   - subscribeEvent(eventName, callback) {
14548   - this.DispatchInstance.eventBus.on(eventName, callback)
14549   - }
14550   -
14551   - /**
14552   - * @description 创建消息
14553   - * @param deviceId
14554   - * @param cmdId
14555   - * @param attr
14556   - * @return {{cmdId, entityType: string, keys, scope: string, entityId}}
14557   - */
14558   - generatorMessage(deviceId, cmdId, attr) {
14559   - return {
14560   - entityType: "DEVICE",
14561   - entityId: deviceId,
14562   - scope: "LATEST_TELEMETRY",
14563   - cmdId,
14564   - keys: attr,
14565   - }
14566   - }
14567   -
14568   - /**
14569   - * @description 分发事件
14570   - * @param type
14571   - * @return Function
14572   - */
14573   - dispatch(type) {
14574   - let invoke = () => {
14575   - }
14576   - switch (type) {
14577   - case HandleDynamicEffect.enumActType.ROTATE:
14578   - invoke = this.rotate.bind(this)
14579   - break
14580   - case HandleDynamicEffect.enumActType.DISPLAY:
14581   - invoke = this.display.bind(this)
14582   - break
14583   - case HandleDynamicEffect.enumActType.FLASH:
14584   - invoke = this.flash.bind(this)
14585   - break
14586   - case HandleDynamicEffect.enumActType.IMAGE:
14587   - invoke = this.varImage.bind(this)
14588   - break
14589   - case HandleDynamicEffect.enumActType.RUNNING:
14590   - invoke = this.running.bind(this)
14591   - break
14592   - }
14593   - return invoke
14594   - }
14595   -
14596   - /**
14597   - * @description 旋转
14598   - * @param message
14599   - * @param attr
14600   - */
14601   - rotate(message) {
14602   - const { subscriptionId, data } = message
14603   - const node = this.getNodeByCmdId(subscriptionId)
14604   - const key = node.id + DispatchCenter.enumDynamicEffectType.ROTATE
14605   - if (!this.validatePriority(node.id)) {
14606   - this.delUpdateFn(key)
14607   - return
14608   - }
14609   - const { flag } = this.validate(subscriptionId, DispatchCenter.enumDynamicEffectType.ROTATE, data)
14610   - let deg = 0
14611   - const updateFn = () => {
14612   - if (deg === 360) deg = 0
14613   - deg += 20
14614   - let style = node.getStyle()
14615   - const reg = /rotation=(-?)\w+(;?)/g
14616   - style = style.replace(reg, '')
14617   - style += `rotation=${deg};`
14618   - node.setStyle(style)
14619   - this.graph.updateCellStyles(style, node)
14620   - }
14621   - if (!flag) {
14622   - this.delUpdateFn(key)
14623   - return
14624   - }
14625   - this.insertContinueUpdateFn(node, updateFn, key)
14626   - }
14627   -
14628   - /**
14629   - * @description 显示与隐藏
14630   - * @param message
14631   - * @param attr
14632   - */
14633   - display(message) {
14634   - const { subscriptionId, data = {} } = message
14635   - const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.DISPLAY, data)
14636   - if (!flag) return
14637   - const node = this.getNodeByCmdId(subscriptionId)
14638   - let isShow = false
14639   - if (condition.type === HandleDynamicEffect.enumDisplayType.SHOW) {
14640   - isShow = true
14641   - } else if (condition.type === HandleDynamicEffect.enumDisplayType.HIDDEN) {
14642   - isShow = false
14643   - }
14644   - const updateFn = () => {
14645   - if (!isShow) {
14646   - Object.keys(HandleDynamicEffect.enumActType).forEach(key => {
14647   - const delKey = node.id + key
14648   - this.delUpdateFn(delKey)
14649   - })
14650   - const temp = this.actNodeMapping.get(node.id)
14651   - temp.display = false
14652   - } else {
14653   - const temp = this.actNodeMapping.get(node.id)
14654   - temp.display = true
14655   - }
14656   -
14657   - node.setVisible(isShow)
14658   - }
14659   - this.insertOnceUpdateFn(node, updateFn)
14660   - }
14661   -
14662   - /**
14663   - * @description 闪烁
14664   - * @param message
14665   - * @param attr
14666   - */
14667   - flash(message) {
14668   - const { subscriptionId, data } = message
14669   - const node = this.getNodeByCmdId(subscriptionId)
14670   - const key = node.id + DispatchCenter.enumDynamicEffectType.FLASH
14671   - if (!this.validatePriority(node.id)) {
14672   - this.delUpdateFn(key)
14673   - return
14674   - }
14675   - const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.FLASH, data)
14676   - let flashFlag = false
14677   - const updateFn = () => {
14678   - node.setVisible(flashFlag)
14679   - flashFlag = !flashFlag
14680   - }
14681   - if (!flag) {
14682   - flashFlag = true
14683   - this.insertOnceUpdateFn(node, updateFn)
14684   - this.delUpdateFn(key)
14685   - return
14686   - }
14687   - this.insertContinueUpdateFn(node, updateFn, key)
14688   - }
14689   -
14690   - /**
14691   - * @description 处理变量图片
14692   - */
14693   - varImage(message) {
14694   - const { subscriptionId, data } = message
14695   - const node = this.getNodeByCmdId(subscriptionId)
14696   - const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.IMAGE, data)
14697   - if (flag && node) {
14698   - const { imagePath } = condition
14699   - this.insertOnceUpdateFn(
14700   - node,
14701   - () => {
14702   - node.setStyle(`image;image=${imagePath};imageAspect=0;`)
14703   - })
14704   - } else if (!flag && node) {
14705   - const { condition = [], attr } = this.getBindData(subscriptionId, HandleDynamicEffect.enumActType.IMAGE)
14706   - const flag = HandleDynamicEffect.enumVarImageConst.DEFAULT_IMAGE_FLAG
14707   - const defaultBindData = condition.find(item => item[flag])
14708   - if (defaultBindData) {
14709   - const { imagePath } = defaultBindData
14710   - if (!imagePath) return
14711   - this.insertOnceUpdateFn(
14712   - node,
14713   - () => {
14714   - node.setStyle(`image;image=${imagePath};imageAspect=0;`)
14715   - })
14716   - }
14717   - }
14718   - }
14719   -
14720   - running(message) {
14721   - const { subscriptionId, data = {} } = message
14722   - const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.RUNNING, data)
14723   - if (!flag) return
14724   - const node = this.getNodeByCmdId(subscriptionId)
14725   - let isRun = false
14726   - if (condition.type === HandleDynamicEffect.enumRunningType.RUN) {
14727   - isRun = true
14728   - } else if (condition.type === HandleDynamicEffect.enumRunningType.STOP) {
14729   - isRun = false
14730   - }
14731   -
14732   - const updateFn = () => {
14733   - const reg = /flowAnimation[^;]+/
14734   - const style = node.getStyle()
14735   - node.setStyle(style.replace(reg, `flowAnimation=${isRun ? 1 : 0}`))
14736   - }
14737   - this.insertOnceUpdateFn(node, updateFn)
14738   - }
14739   -
14740   - /**
14741   - * @description 播放视频
14742   - */
14743   - videoPlay() {
14744   - const enumAccessMode = HandleDynamicEffect.enumVideoAccessMode
14745   - const reg = /(?:.*)(?<=\.)/
14746   - const graph = this.graph
14747   - const createVideoTemplate = this.createVideoTemplate
14748   - const videoPlayConfig = {
14749   - controls: true,
14750   - autoPlay: true,
14751   - // bigPlayButton: true,
14752   - // textTrackDisplay: false,
14753   - // posterImage: false,
14754   - // errorDisplay: false,
14755   - }
14756   - for (const record of this.videoRecordList) {
14757   - const { additional = {}, nodeId } = record
14758   - const { accessMode, videoUrl, id } = additional
14759   - const cell = this.getCellByCellId(nodeId)
14760   - if (!cell) continue
14761   - if (Number(accessMode) === enumAccessMode.MANUAL_ENTER) {
14762   - handleVideoPlay(videoPlayConfig, cell, videoUrl)
14763   - } else {
14764   - getStreamingVideoPlayUrl(id, nodeId)
14765   - }
14766   - }
14767   -
14768   - async function getStreamingVideoPlayUrl(id, cell) {
14769   - const [err, res = {}] = await to(ConfigurationNodeApi.getStreamingVideoPlayUrl(id))
14770   - const { url } = res?.data || {}
14771   - if (!url) return
14772   - handleVideoPlay({ ...videoPlayConfig, hls: { withCredentials: true } }, cell, url)
14773   - }
14774   -
14775   - function handleVideoPlay(videoPlayConfig, cell, videoUrl) {
14776   - if (!cell) return
14777   - const { geometry = {} } = cell
14778   - const { width, height } = geometry
14779   - const idEl = getIdEl()
14780   - graph.getModel().beginUpdate()
14781   - try {
14782   - let type
14783   - if (videoUrl.replace(reg, '') === 'm3u8') type = 'application/x-mpegURL'
14784   - const template = createVideoTemplate(idEl, width, height, videoUrl, type)
14785   - cell.setAttribute('label', template)
14786   - graph.refresh(cell);
14787   - } finally {
14788   - graph.getModel().endUpdate()
14789   - videojs(idEl, videoPlayConfig, function () {
14790   - this.play()
14791   - })
14792   - }
14793   - }
14794   -
14795   - function getIdEl() {
14796   - return `video-play__${Date.now()}`
14797   - }
14798   - }
14799   -
14800   -
14801   - createVideoTemplate(idEl, width, height, videoUrl, videoType = 'video/mp4') {
14802   - const poster = `${Proxy_Prefix}/images/youtube.png`
14803   - const template = `<video id="${idEl}" class="video-js" controls preload="auto" muted="muted" width="${width}" height="${height}" poster="${poster}" data-setup='{}'>
14804   - <source src="${videoUrl}" type="${videoType}">
14805   - <p class="vjs-no-js">
14806   - 要查看此视频,请启用JavaScript,并考虑升级web浏览器.
14807   - </p>
14808   - </video>`
14809   - return template
14810   - }
14811   - /**
14812   - * @description 获取cell 通过cell id
14813   - */
14814   - getCellByCellId(id) {
14815   - const allCell = this.contentAllCell || []
14816   - return allCell.find(item => item.id === id)
14817   - }
14818   -
14819   -
14820   - /**
14821   - * @description 验证是否满足条件列表中的任意一条
14822   - * @param subscriptionId
14823   - * @param type
14824   - * @param value
14825   - * @return {{flag: boolean, condition: {}}}
14826   - */
14827   - validate(subscriptionId, type, value) {
14828   - const { condition = [], attr } = this.getBindData(subscriptionId, type)
14829   - const result = { condition: {}, flag: false }
14830   - for (let i = 0; i < condition.length; i++) {
14831   - const { min, max } = condition[i]
14832   - const [timespan, realValue] = value[attr][0]
14833   - result.flag = this.isExistInArea(min, max, realValue)
14834   - if (result.flag) {
14835   - result.condition = condition[i]
14836   - break
14837   - }
14838   - }
14839   - return result
14840   - }
14841   -
14842   - /**
14843   - * @description 判断一个数是否在区间范围内
14844   - * @param min 最小值
14845   - * @param max 最大值
14846   - * @param value 值
14847   - * @return {boolean}
14848   - */
14849   - isExistInArea(min, max, value) {
14850   - return Number(value) >= Number(min) && Number(value) <= Number(max)
14851   - }
14852   -
14853   - /**
14854   - * @description 获取绑定的数据
14855   - * @param subscriptionId
14856   - * @param actionType
14857   - * @return {*}
14858   - */
14859   - getBindData(subscriptionId, actionType) {
14860   - const nodeId = this.getNodeIdByCmdId(subscriptionId)
14861   - const temp = this.actNodeMapping.get(nodeId)
14862   - return temp.value.get(actionType)
14863   - }
14864   -
14865   - /**
14866   - * @description 通过cmdID获取节点id
14867   - * @param subscriptionId
14868   - * @return {string}
14869   - */
14870   - getNodeIdByCmdId(subscriptionId) {
14871   - return this.DispatchInstance.cmdIdMapping.get(subscriptionId)
14872   - }
14873   -
14874   - /**
14875   - * @description 通过cmdID 获取节点
14876   - * @param subscriptionId
14877   - * @return {*}
14878   - */
14879   - getNodeByCmdId(subscriptionId) {
14880   - const nodeId = this.getNodeIdByCmdId(subscriptionId)
14881   - return this.contentAllCell.find(item => item.id === nodeId)
14882   - }
14883   -
14884   - /**
14885   - * @description 验证数据动效优先级 显示隐藏优先级最高
14886   - * @param {string} nodeId
14887   - * @returns
14888   - */
14889   - validatePriority(nodeId) {
14890   - return this.actNodeMapping.get(nodeId).display
14891   - }
14892   -
14893   -}
14894   -
14895   -class UpdateQueue {
14896   -
14897   - /**
14898   - * @description 图实例
14899   - */
14900   - graph
14901   -
14902   - /**
14903   - * @description 更新队列
14904   - * @type { Map<number, {cell: any, fn: Function, key: string}[]> }
14905   - */
14906   - updateQueueMapping = new Map()
14907   -
14908   - /**
14909   - * @description 时间队列
14910   - * @type { Map<number, Function> }
14911   - */
14912   - timeQueue = new Map()
14913   -
14914   - constructor(DispatchCenterInstance) {
14915   - this.graph = DispatchCenterInstance.graph
14916   - window.timeMap = this.timeQueue
14917   - }
14918   -
14919   - /**
14920   - * @description 创建更新队列
14921   - * @param {number} time
14922   - */
14923   - createUpdateQueue(time) {
14924   - const callback = () => {
14925   - this.graph.getModel().beginUpdate()
14926   - try {
14927   - const updateQueue = this.updateQueueMapping.get(time)
14928   - updateQueue.forEach(each => {
14929   - const { cell: updateCell, fn: updateFn } = each
14930   - updateFn()
14931   - this.graph.refresh(updateCell);
14932   - })
14933   - } finally {
14934   - this.graph.getModel().endUpdate()
14935   - }
14936   - }
14937   - const cleanFn = RAFSetInterval(callback, time)
14938   - this.timeQueue.set(time, cleanFn)
14939   - }
14940   -
14941   - createIntervalQueue(time, callback) {
14942   - const cleanFn = RAFSetInterval(callback, time)
14943   - this.timeQueue.set(time, cleanFn)
14944   - }
14945   -
14946   - /**
14947   - * @description 持续更新
14948   - * @param cell 更新cell
14949   - * @param fn 更新方法
14950   - * @param key key
14951   - * @param time 间隔事时间
14952   - */
14953   - insertContinueUpdateFn(cell, fn, key, time = 100) {
14954   - if (!this.updateQueueMapping.has(time)) {
14955   - this.updateQueueMapping.set(time, [])
14956   - }
14957   - if (!this.timeQueue.get(time)) {
14958   - this.createUpdateQueue(time)
14959   - }
14960   - if (this.updateQueueMapping.get(time).find(item => item.key === key)) {
14961   - return
14962   - }
14963   - this.updateQueueMapping.get(time).push({ cell, fn, key })
14964   - }
14965   -
14966   - /**
14967   - * @description 只更新一次
14968   - * @param cell 更新cell
14969   - * @param fn 更新方法
14970   - */
14971   - insertOnceUpdateFn(cell, fn) {
14972   - this.graph.getModel().beginUpdate()
14973   - try {
14974   - fn()
14975   - this.graph.refresh(cell);
14976   - } finally {
14977   - this.graph.getModel().endUpdate()
14978   - }
14979   - }
14980   -
14981   - /**
14982   - * @description 从更新队列中移除不再更新的事件
14983   - * @param key
14984   - * @param time
14985   - */
14986   - delUpdateFn(key, time = 100) {
14987   - let temp = this.updateQueueMapping.get(time)
14988   - if (temp) {
14989   - const index = temp.findIndex(item => item.key === key)
14990   - if (~index) {
14991   - temp.splice(index, 1)
14992   - if (!temp.length) {
14993   - const cleanFn = this.timeQueue.get(time)
14994   - cleanFn()
14995   - this.timeQueue.delete(time)
14996   - }
14997   - }
14998   - }
14999   - }
15000   -
15001   - /**
15002   - * @description 清楚所有更新队列
15003   - */
15004   - cleanAllUpdateQueue() {
15005   - this.timeQueue.forEach(cleanFn => {
15006   - cleanFn()
15007   - })
15008   - }
15009   -}
15010   -
15011   -class RAFSetTimeoutImp {
15012   - constructor(callback, time = 0) {
15013   - this.callback = callback;
15014   - this.time = time;
15015   - this.now = Date.now;
15016   - this.current = this.now();
15017   - this.old = this.now();
15018   - const fn = () => {
15019   - if (this.current - this.old > this.time) {
15020   - this.callback();
15021   - this.old = this.now();
15022   - this.clean();
15023   - return;
15024   - }
15025   - this.current = this.now();
15026   - this.instance = window.requestAnimationFrame(fn);
15027   - };
15028   - this.instance = window.requestAnimationFrame(fn);
15029   - }
15030   -
15031   - clean() {
15032   - window.cancelAnimationFrame(this.instance);
15033   - this.instance = null;
15034   - }
15035   -}
15036   -
15037   -function RAFSetTimeout(callback, time) {
15038   - const instance = new RAFSetTimeoutImp(callback, time);
15039   - return instance.clean.bind(instance);
15040   -}
15041   -
15042   -class RAFSetIntervalImp {
15043   - constructor(callback, time = 0) {
15044   - this.callback = callback;
15045   - this.time = time;
15046   - this.now = Date.now;
15047   - this.current = this.now();
15048   - this.old = this.now();
15049   - const fn = () => {
15050   - if (this.current - this.old > this.time) {
15051   - this.callback();
15052   - this.old = this.now();
15053   - }
15054   - this.current = this.now();
15055   - this.instance = window.requestAnimationFrame(fn);
15056   - };
15057   - this.instance = window.requestAnimationFrame(fn);
15058   - }
15059   -
15060   - clean() {
15061   - window.cancelAnimationFrame(this.instance);
15062   - this.instance = null
15063   - }
15064   -}
15065   -
15066   -function RAFSetInterval(callback, time) {
15067   - const instance = new RAFSetIntervalImp(callback, time);
15068   - return instance.clean.bind(instance);
15069   -}
15070   -
15071   -
15072   -class Validate {
15073   - /**
15074   - * @description
15075   - * @type {{value: any, message: string, required?: boolean, validator?: any}[]} list
15076   - */
15077   - list = []
15078   -
15079   - /**
15080   - * @description
15081   - * @param {{value: any, message: string, required?: boolean, validator?: any}[]} ruleList
15082   - */
15083   - constructor(ruleList = []) {
15084   - this.list = ruleList
15085   - }
15086   -
15087   - /**
15088   - * @description 设置规则
15089   - * @param {{value: any, message: string, required?: boolean, validator?: any}} rule
15090   - */
15091   - set(rule) {
15092   - this.list.push(rule)
15093   - }
15094   -
15095   - begin() {
15096   - for (const rule of this.list) {
15097   - const { required, value, message, validator } = rule
15098   - if (required && !value) {
15099   - UseLayUi.topErrorMsg(message)
15100   - return false
15101   - }
15102   - }
15103   - return true
15104   - }
15105   -}
... ... @@ -22,26 +22,26 @@
22 22 <meta name="mobile-web-app-capable" content="yes">
23 23 <meta name="theme-color" content="#d89000">
24 24
25   - <link rel="stylesheet" href="./js/plugin/layui/css/layui.css?v=1663582316568">
  25 + <link rel="stylesheet" href="./js/plugin/layui/css/layui.css?v=1664184574262">
26 26
27 27 <!-- load configure file -->
28   - <script src="./js/config/config.js?v=1663582316568"></script>
  28 + <script src="./js/config/config.js?v=1664184574262"></script>
29 29
30 30 <!-- crypto-js -->
31   - <script src="./js/plugin/crypto-js/crypto-js.js?v=1663582316568"></script>
  31 + <script src="./js/plugin/crypto-js/crypto-js.js?v=1664184574262"></script>
32 32
33 33 <!-- storage persistent -->
34   - <script src="./js/const/persistentStorage.js?v=1663582316568"></script>
  34 + <script src="./js/const/persistentStorage.js?v=1664184574262"></script>
35 35 <!-- Global const -->
36   - <script src="./js/const/const.js?v=1663582316568"></script>
  36 + <script src="./js/const/const.js?v=1664184574262"></script>
37 37
38 38 <!-- Axios -->
39   - <script src="./js/plugin/axios/axios.min.js?v=1663582316568"></script>
40   - <script src="./js/plugin/axios/DefHttp.js?v=1663582316568"></script>
41   - <script src="./js/api/index.js?v=1663582316568"></script>
  39 + <script src="./js/plugin/axios/axios.min.js?v=1664184574262"></script>
  40 + <script src="./js/plugin/axios/DefHttp.js?v=1664184574262"></script>
  41 + <script src="./js/api/index.js?v=1664184574262"></script>
42 42
43 43 <!-- load script -->
44   - <script src="./js/config/loadScript.js?v=1663582316568"></script>
  44 + <script src="./js/config/loadScript.js?v=1664184574262"></script>
45 45
46 46 <!-- act editor -->
47 47 <!-- <script src="https://oss.yuntengcloud.com/iotdocs/thingskit-scada/ace.js"></script> -->
... ... @@ -54,7 +54,7 @@
54 54 <!-- <script src="https://vjs.zencdn.net/7.10.2/video.min.js"></script> -->
55 55 <!-- <script src="https://oss.yuntengcloud.com/iotdocs/thingskit-scada/video.min.js"></script> -->
56 56
57   - <script src="./js/plugin/layui/layui.js?v=1663582316568"></script>
  57 + <script src="./js/plugin/layui/layui.js?v=1664184574262"></script>
58 58 <!-- <link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/layui/2.6.8/css/layui.min.css"
59 59 integrity="sha512-iQBJbsNHXUcgEIgWThd2dr8tOdKPvICwqjPEZYY81z3eMya44A5MiAqfWSCh+Ee1YzNYkdrI982Qhwgr8LEYOQ=="
60 60 crossorigin="anonymous" referrerpolicy="no-referrer" />
... ... @@ -63,7 +63,7 @@
63 63 crossorigin="anonymous" referrerpolicy="no-referrer"></script> -->
64 64
65 65 <!-- 引入修改样式 -->
66   - <link rel="stylesheet" href="./styles/formatChange.css?v=1663582316568">
  66 + <link rel="stylesheet" href="./styles/formatChange.css?v=1664184574262">
67 67
68 68 <script type="text/javascript">
69 69 /**
... ... @@ -306,7 +306,7 @@
306 306 var supportedDomain = (hostName.substring(hostName.length - 8, hostName.length) === '.draw.io') ||
307 307 (hostName.substring(hostName.length - 13, hostName.length) === '.diagrams.net');
308 308
309   - const releaseVersion = '1663582316568'
  309 + const releaseVersion = '1664184574262'
310 310 const appMinSrc = Enable_OSS ? `${OSS_Prefix}app.min.js?v=${releaseVersion}` : `js/app.min.js?v=${releaseVersion}`
311 311 function loadAppJS() {
312 312 mxscript(appMinSrc, function () {
... ...