feat: 后端全量更新 - 含所有本次需求
- Contract.php: 返回合约账户余额(balance_contract) - My.php: 地址管理增加BTC/ETH - AppContract.php: 一键平仓(closeall) - AppProxy.php: 代理专属注册链接 + 分级权限(L1/L2) - site.php: 手续费减半(0.018→0.009) - agent_permission_setup.sql: 代理权限SQL - crypto_news_crawler.py: 新闻自动采集脚本
This commit is contained in:
+386
@@ -0,0 +1,386 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Regrouping Demo with Tree View</title>
|
||||
<!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
|
||||
<meta name="description" content="Keeping a TreeModel in synch with a GraphLinksModel in a Regrouping editor." />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script src="../release/go.js"></script>
|
||||
<script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework -->
|
||||
<script id="code">
|
||||
function init() {
|
||||
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
|
||||
var $ = go.GraphObject.make;
|
||||
|
||||
myDiagram =
|
||||
$(go.Diagram, "myDiagramDiv",
|
||||
{
|
||||
// what to do when a drag-drop occurs in the Diagram's background
|
||||
mouseDrop: function(e) { finishDrop(e, null); },
|
||||
layout: // Diagram has simple horizontal layout
|
||||
$(go.GridLayout,
|
||||
{ wrappingWidth: Infinity, alignment: go.GridLayout.Position, cellSize: new go.Size(1, 1) }),
|
||||
"commandHandler.archetypeGroupData": { isGroup: true, category: "OfNodes" },
|
||||
"undoManager.isEnabled": true,
|
||||
// when a node is selected in the main Diagram, select the corresponding tree node
|
||||
"ChangedSelection": function(e) {
|
||||
if (myChangingSelection) return;
|
||||
myChangingSelection = true;
|
||||
var diagnodes = new go.Set();
|
||||
myDiagram.selection.each(function(n) {
|
||||
diagnodes.add(myTreeView.findNodeForData(n.data));
|
||||
});
|
||||
myTreeView.clearSelection();
|
||||
myTreeView.selectCollection(diagnodes);
|
||||
myChangingSelection = false;
|
||||
}
|
||||
});
|
||||
|
||||
var myChangingSelection = false; // to protect against recursive selection changes
|
||||
|
||||
// when the document is modified, add a "*" to the title and enable the "Save" button
|
||||
myDiagram.addDiagramListener("Modified", function(e) {
|
||||
var button = document.getElementById("saveModel");
|
||||
if (button) button.disabled = !myDiagram.isModified;
|
||||
var idx = document.title.indexOf("*");
|
||||
if (myDiagram.isModified) {
|
||||
if (idx < 0) document.title += "*";
|
||||
} else {
|
||||
if (idx >= 0) document.title = document.title.substr(0, idx);
|
||||
}
|
||||
});
|
||||
|
||||
// There are two templates for Groups, "OfGroups" and "OfNodes".
|
||||
|
||||
// this function is used to highlight a Group that the selection may be dropped into
|
||||
function highlightGroup(e, grp, show) {
|
||||
if (!grp) return;
|
||||
e.handled = true;
|
||||
if (show) {
|
||||
// cannot depend on the grp.diagram.selection in the case of external drag-and-drops;
|
||||
// instead depend on the DraggingTool.draggedParts or .copiedParts
|
||||
var tool = grp.diagram.toolManager.draggingTool;
|
||||
var map = tool.draggedParts || tool.copiedParts; // this is a Map
|
||||
// now we can check to see if the Group will accept membership of the dragged Parts
|
||||
if (grp.canAddMembers(map.toKeySet())) {
|
||||
grp.isHighlighted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
grp.isHighlighted = false;
|
||||
}
|
||||
|
||||
// Upon a drop onto a Group, we try to add the selection as members of the Group.
|
||||
// Upon a drop onto the background, or onto a top-level Node, make selection top-level.
|
||||
// If this is OK, we're done; otherwise we cancel the operation to rollback everything.
|
||||
function finishDrop(e, grp) {
|
||||
var ok = (grp !== null
|
||||
? grp.addMembers(grp.diagram.selection, true)
|
||||
: e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
|
||||
if (!ok) e.diagram.currentTool.doCancel();
|
||||
}
|
||||
|
||||
myDiagram.groupTemplateMap.add("OfGroups",
|
||||
$(go.Group, go.Panel.Auto,
|
||||
{
|
||||
background: "transparent",
|
||||
// highlight when dragging into the Group
|
||||
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
|
||||
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
|
||||
computesBoundsAfterDrag: true,
|
||||
// when the selection is dropped into a Group, add the selected Parts into that Group;
|
||||
// if it fails, cancel the tool, rolling back any changes
|
||||
mouseDrop: finishDrop,
|
||||
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
|
||||
// Groups containing Groups lay out their members horizontally
|
||||
layout:
|
||||
$(go.GridLayout,
|
||||
{
|
||||
wrappingWidth: Infinity, alignment: go.GridLayout.Position,
|
||||
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4)
|
||||
})
|
||||
},
|
||||
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
|
||||
$(go.Shape, "Rectangle",
|
||||
{ fill: null, stroke: "#E69900", strokeWidth: 2 }),
|
||||
$(go.Panel, go.Panel.Vertical, // title above Placeholder
|
||||
$(go.Panel, go.Panel.Horizontal, // button next to TextBlock
|
||||
{ stretch: go.GraphObject.Horizontal, background: "#FFDD33", margin: 1 },
|
||||
$("SubGraphExpanderButton",
|
||||
{ alignment: go.Spot.Right, margin: 5 }),
|
||||
$(go.TextBlock,
|
||||
{
|
||||
alignment: go.Spot.Left,
|
||||
editable: true,
|
||||
margin: 5,
|
||||
font: "bold 18px sans-serif",
|
||||
stroke: "#9A6600"
|
||||
},
|
||||
new go.Binding("text", "text").makeTwoWay())
|
||||
), // end Horizontal Panel
|
||||
$(go.Placeholder,
|
||||
{ padding: 5, alignment: go.Spot.TopLeft })
|
||||
) // end Vertical Panel
|
||||
)); // end Group and call to add to template Map
|
||||
|
||||
myDiagram.groupTemplateMap.add("OfNodes",
|
||||
$(go.Group, go.Panel.Auto,
|
||||
{
|
||||
background: "transparent",
|
||||
ungroupable: true,
|
||||
// highlight when dragging into the Group
|
||||
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
|
||||
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
|
||||
computesBoundsAfterDrag: true,
|
||||
// when the selection is dropped into a Group, add the selected Parts into that Group;
|
||||
// if it fails, cancel the tool, rolling back any changes
|
||||
mouseDrop: finishDrop,
|
||||
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
|
||||
// Groups containing Nodes lay out their members vertically
|
||||
layout:
|
||||
$(go.GridLayout,
|
||||
{
|
||||
wrappingColumn: 1, alignment: go.GridLayout.Position,
|
||||
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4)
|
||||
})
|
||||
},
|
||||
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
|
||||
$(go.Shape, "Rectangle",
|
||||
{ fill: null, stroke: "#0099CC", strokeWidth: 2 }),
|
||||
$(go.Panel, go.Panel.Vertical, // title above Placeholder
|
||||
$(go.Panel, go.Panel.Horizontal, // button next to TextBlock
|
||||
{ stretch: go.GraphObject.Horizontal, background: "#33D3E5", margin: 1 },
|
||||
$("SubGraphExpanderButton",
|
||||
{ alignment: go.Spot.Right, margin: 5 }),
|
||||
$(go.TextBlock,
|
||||
{
|
||||
alignment: go.Spot.Left,
|
||||
editable: true,
|
||||
margin: 5,
|
||||
font: "bold 16px sans-serif",
|
||||
stroke: "#006080"
|
||||
},
|
||||
new go.Binding("text", "text").makeTwoWay())
|
||||
), // end Horizontal Panel
|
||||
$(go.Placeholder,
|
||||
{ padding: 5, alignment: go.Spot.TopLeft })
|
||||
) // end Vertical Panel
|
||||
)); // end Group and call to add to template Map
|
||||
|
||||
// Nodes have a trivial definition
|
||||
myDiagram.nodeTemplate =
|
||||
$(go.Node, go.Panel.Auto,
|
||||
{ // dropping on a Node is the same as dropping on its containing Group, even if it's top-level
|
||||
mouseDrop: function(e, nod) { finishDrop(e, nod.containingGroup); }
|
||||
},
|
||||
$(go.Shape, "Rectangle",
|
||||
{ fill: "#ACE600", stroke: "#558000", strokeWidth: 2 },
|
||||
new go.Binding("fill", "color")),
|
||||
$(go.TextBlock,
|
||||
{
|
||||
margin: 5,
|
||||
editable: true,
|
||||
font: "bold 13px sans-serif",
|
||||
stroke: "#446700"
|
||||
},
|
||||
new go.Binding("text", "text").makeTwoWay())
|
||||
);
|
||||
|
||||
var myChangingModel = false; // to protect against recursive model changes
|
||||
|
||||
myDiagram.addModelChangedListener(function(e) {
|
||||
if (e.model.skipsUndoManager) return;
|
||||
if (myChangingModel) return;
|
||||
myChangingModel = true;
|
||||
// don't need to start/commit a transaction because the UndoManager is shared with myTreeView
|
||||
if (e.modelChange === "nodeGroupKey" || e.modelChange === "nodeParentKey") {
|
||||
// handle structural change: group memberships
|
||||
var treenode = myTreeView.findNodeForData(e.object);
|
||||
if (treenode !== null) treenode.updateRelationshipsFromData();
|
||||
} else if (e.change === go.ChangedEvent.Property) {
|
||||
var treenode = myTreeView.findNodeForData(e.object);
|
||||
if (treenode !== null) treenode.updateTargetBindings();
|
||||
} else if (e.change === go.ChangedEvent.Insert && e.propertyName === "nodeDataArray") {
|
||||
// pretend the new data isn't already in the nodeDataArray for myTreeView
|
||||
myTreeView.model.nodeDataArray.splice(e.newParam, 1);
|
||||
// now add to the myTreeView model using the normal mechanisms
|
||||
myTreeView.model.addNodeData(e.newValue);
|
||||
} else if (e.change === go.ChangedEvent.Remove && e.propertyName === "nodeDataArray") {
|
||||
// remove the corresponding node from myTreeView
|
||||
var treenode = myTreeView.findNodeForData(e.oldValue);
|
||||
if (treenode !== null) myTreeView.remove(treenode);
|
||||
}
|
||||
myChangingModel = false;
|
||||
});
|
||||
|
||||
// setup the tree view; will be initialized with data by the load() function
|
||||
myTreeView =
|
||||
$(go.Diagram, "myTreeView",
|
||||
{
|
||||
initialContentAlignment: go.Spot.TopLeft,
|
||||
allowMove: false, // don't let users mess up the tree
|
||||
allowCopy: true, // but you might want this to be false
|
||||
"commandHandler.copiesTree": true,
|
||||
"commandHandler.copiesParentKey": true,
|
||||
allowDelete: true, // but you might want this to be false
|
||||
"commandHandler.deletesTree": true,
|
||||
allowHorizontalScroll: false,
|
||||
layout:
|
||||
$(go.TreeLayout,
|
||||
{
|
||||
alignment: go.TreeLayout.AlignmentStart,
|
||||
angle: 0,
|
||||
compaction: go.TreeLayout.CompactionNone,
|
||||
layerSpacing: 16,
|
||||
layerSpacingParentOverlap: 1,
|
||||
nodeIndentPastParent: 1.0,
|
||||
nodeSpacing: 0,
|
||||
setsPortSpot: false,
|
||||
setsChildPortSpot: false,
|
||||
arrangementSpacing: new go.Size(0, 0)
|
||||
}),
|
||||
// when a node is selected in the tree, select the corresponding node in the main diagram
|
||||
"ChangedSelection": function(e) {
|
||||
if (myChangingSelection) return;
|
||||
myChangingSelection = true;
|
||||
var diagnodes = new go.Set();
|
||||
myTreeView.selection.each(function(n) {
|
||||
diagnodes.add(myDiagram.findNodeForData(n.data));
|
||||
});
|
||||
myDiagram.clearSelection();
|
||||
myDiagram.selectCollection(diagnodes);
|
||||
myChangingSelection = false;
|
||||
}
|
||||
});
|
||||
|
||||
myTreeView.nodeTemplate =
|
||||
$(go.Node,
|
||||
// no Adornment: instead change panel background color by binding to Node.isSelected
|
||||
{ selectionAdorned: false },
|
||||
$("TreeExpanderButton",
|
||||
{
|
||||
width: 14,
|
||||
"ButtonBorder.fill": "white",
|
||||
"ButtonBorder.stroke": null,
|
||||
"_buttonFillOver": "rgba(0,128,255,0.25)",
|
||||
"_buttonStrokeOver": null
|
||||
}),
|
||||
$(go.Panel, "Horizontal",
|
||||
{ position: new go.Point(16, 0) },
|
||||
new go.Binding("background", "isSelected", function(s) { return (s ? "lightblue" : "white"); }).ofObject(),
|
||||
// Icon is not needed?
|
||||
//$(go.Picture,
|
||||
// {
|
||||
// width: 14, height: 14,
|
||||
// margin: new go.Margin(0, 4, 0, 0),
|
||||
// imageStretch: go.GraphObject.Uniform,
|
||||
// source: "images/50x40.png"
|
||||
// }),
|
||||
$(go.TextBlock,
|
||||
{ editable: true },
|
||||
new go.Binding("text").makeTwoWay())
|
||||
) // end Horizontal Panel
|
||||
); // end Node
|
||||
|
||||
// without lines
|
||||
myTreeView.linkTemplate = $(go.Link);
|
||||
|
||||
// cannot share the model itself, but can share all of the node data from the main Diagram,
|
||||
// pretending the "group" relationship is the "tree parent" relationship
|
||||
myTreeView.model = $(go.TreeModel, { nodeParentKeyProperty: "group" });
|
||||
|
||||
myTreeView.addModelChangedListener(function(e) {
|
||||
if (e.model.skipsUndoManager) return;
|
||||
if (myChangingModel) return;
|
||||
myChangingModel = true;
|
||||
// don't need to start/commit a transaction because the UndoManager is shared with myDiagram
|
||||
if (e.modelChange === "nodeGroupKey" || e.modelChange === "nodeParentKey") {
|
||||
// handle structural change: tree parent/children
|
||||
var node = myDiagram.findNodeForData(e.object);
|
||||
if (node !== null) node.updateRelationshipsFromData();
|
||||
} else if (e.change === go.ChangedEvent.Property) {
|
||||
// propagate simple data property changes back to the main Diagram
|
||||
var node = myDiagram.findNodeForData(e.object);
|
||||
if (node !== null) node.updateTargetBindings();
|
||||
} else if (e.change === go.ChangedEvent.Insert && e.propertyName === "nodeDataArray") {
|
||||
// pretend the new data isn't already in the nodeDataArray for the main Diagram model
|
||||
myDiagram.model.nodeDataArray.splice(e.newParam, 1);
|
||||
// now add to the myDiagram model using the normal mechanisms
|
||||
myDiagram.model.addNodeData(e.newValue);
|
||||
} else if (e.change === go.ChangedEvent.Remove && e.propertyName === "nodeDataArray") {
|
||||
// remove the corresponding node from the main Diagram
|
||||
var node = myDiagram.findNodeForData(e.oldValue);
|
||||
if (node !== null) myDiagram.remove(node);
|
||||
}
|
||||
myChangingModel = false;
|
||||
});
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
// save a model to and load a model from JSON text, displayed below the Diagram
|
||||
function save() {
|
||||
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
|
||||
myDiagram.isModified = false;
|
||||
}
|
||||
function load() {
|
||||
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
|
||||
|
||||
// share all of the data with the tree view
|
||||
myTreeView.model.nodeDataArray = myDiagram.model.nodeDataArray;
|
||||
|
||||
// share the UndoManager too!
|
||||
myTreeView.model.undoManager = myDiagram.model.undoManager;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<div id="sample">
|
||||
<div style="width: 100%; display: flex; justify-content: space-between">
|
||||
<div id="myTreeView" style="width: 150px; margin-right: 2px; background-color: whitesmoke; border: solid 1px black"></div>
|
||||
<div id="myDiagramDiv" style="flex-grow: 1; height: 500px; border: solid 1px black"></div>
|
||||
</div>
|
||||
<p>
|
||||
This sample demonstrates the synchronization of two different models, necessitated by their being different types:
|
||||
<a>TreeModel</a> for the tree view and <a>GraphLinksModel</a> for the general diagram on the right.
|
||||
Normally in such situations one would have a single model with two diagrams showing the shared model.
|
||||
However in this case there are two separate models but the model data, including the <a>Model.nodeDataArray</a>, are shared.
|
||||
That means the "group" property is used in the normal fashion in the GraphLinksModel but is used as the "parent"
|
||||
reference in the TreeModel.
|
||||
</p>
|
||||
<p>
|
||||
That introduces some complications when there are changes to the data, since they need to be reflected in other other model
|
||||
even though the data properties have already been changed!
|
||||
This is accomplished by having a Model Changed listener on each model that explicitly updates the other model.
|
||||
</p>
|
||||
<div id="buttons">
|
||||
<button id="saveModel" onclick="save()">Save</button>
|
||||
<button id="loadModel" onclick="load()">Load</button>
|
||||
</div>
|
||||
<textarea id="mySavedModel" style="width:100%;height:300px">
|
||||
{ "class": "go.GraphLinksModel",
|
||||
"nodeDataArray": [
|
||||
{"key":1, "text":"Main 1", "isGroup":true, "category":"OfGroups"},
|
||||
{"key":2, "text":"Main 2", "isGroup":true, "category":"OfGroups"},
|
||||
{"key":3, "text":"Group A", "isGroup":true, "category":"OfNodes", "group":1},
|
||||
{"key":4, "text":"Group B", "isGroup":true, "category":"OfNodes", "group":1},
|
||||
{"key":5, "text":"Group C", "isGroup":true, "category":"OfNodes", "group":2},
|
||||
{"key":6, "text":"Group D", "isGroup":true, "category":"OfNodes", "group":2},
|
||||
{"key":7, "text":"Group E", "isGroup":true, "category":"OfNodes", "group":6},
|
||||
{"text":"first A", "group":3, "key":-7},
|
||||
{"text":"second A", "group":3, "key":-8},
|
||||
{"text":"first B", "group":4, "key":-9},
|
||||
{"text":"second B", "group":4, "key":-10},
|
||||
{"text":"third B", "group":4, "key":-11},
|
||||
{"text":"first C", "group":5, "key":-12},
|
||||
{"text":"second C", "group":5, "key":-13},
|
||||
{"text":"first D", "group":6, "key":-14},
|
||||
{"text":"first E", "group":7, "key":-15}
|
||||
],
|
||||
"linkDataArray": [ ]}
|
||||
</textarea>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user