[Bps-public-commit] rt-extension-lifecycleui branch, master, updated. 8a4a824c8e8e9e81913d52565ba9953fb0352d80
Shawn Moore
shawn at bestpractical.com
Fri Sep 8 17:55:43 EDT 2017
The branch, master has been updated
via 8a4a824c8e8e9e81913d52565ba9953fb0352d80 (commit)
via 2286fdfe95e1c06f54c8ead1422c8f9f73510a04 (commit)
via 5b4e82c8955f5d5d8186bdd61dce7916bf2992ae (commit)
via 2e82183c182e9d6be205c20db02488cf0e5cabfa (commit)
via eccbfb727d04f9f206b77665d31bccabf34a22bb (commit)
via f74fb3355daf56e5938d8e973f3b7e193a7ae991 (commit)
via 6437939ec363baeb225c34a659bcdd32424c3b7c (commit)
via 5b7636420ac1c9558de6d1f325ff0a6d00688f58 (commit)
via f54ebb71151b05d0be77330bfb344686dae04a2c (commit)
via 8dabf9ca82d8cc2c8c44e737eec2b11cde559200 (commit)
via 4f8527c9ee6fa2dbda16398b5ca7c6317fd94bc3 (commit)
via a90d4b93c03a495ba50cc48e3014c0799d45ccc9 (commit)
via 0debf62d56b9b269f69a8175e0ab8e0e2251702d (commit)
via 2ba8415e627ed29bf9b275a0b82fa1b35c30b2af (commit)
via fca968ad066e92cb6dfbe82b645bbd01226ba4d0 (commit)
via 86b6519b2d2052a4648ea4a2f0404bec03f18f65 (commit)
via 0c6f9ac75c0f802e00b6f67d7c2d35334d79ea98 (commit)
via 5b583b6e365890177574285ee8eaa10b7f4552c5 (commit)
via d54601dc9b0fa5a6b2683f60353488f8a11d37a0 (commit)
via 0653f4538d4d6576b70b06d76f54ec3b3c3927f2 (commit)
via f058230e7537f1f2724cace1aef2e0789e0803ae (commit)
via 3b276849ea7979ce874e8332f25b2bfea7f20a9e (commit)
via 54d36bcd20035d4c33854102a0b4cb3195313a47 (commit)
via 3e9de82b31c76628d8b38084c55d8d69a7386f84 (commit)
via f7bbd0fbaa4f721d64f6e0423cf130c3d8e603b2 (commit)
via 2ce3c325523e07be4e9ab794020996d6631e7526 (commit)
via 9ad50859cc3ec1eb7affa1b5f9a641ce04a487ac (commit)
via 66f3d135d9fb234649fcf2b327e90e916ec5b2c7 (commit)
via cb6456483533ac3be4999f9ac5767a6ec647d1d6 (commit)
via cc68b0133ac0287977080ab86e1c220c2386ec1b (commit)
via 12d61a4d739996496d1af6e8dcde1d1e38f51d9f (commit)
from b26cb45ab608b0d0844cf07e65f5e659a5c65c04 (commit)
Summary of changes:
MANIFEST | 47 ++++++
html/Admin/Lifecycles/Create.html | 85 +++++++----
html/Admin/Lifecycles/Mappings.html | 88 +++++++++++
.../Elements/Tabs/Privileged | 1 +
html/Elements/LifecycleGraphExtras | 11 ++
html/Elements/LifecycleInspectorCanvas | 50 ++++--
html/Elements/LifecycleInspectorCircle | 1 +
html/Elements/LifecycleInspectorLine | 1 +
html/Elements/LifecycleInspectorPolygon | 1 +
html/Elements/LifecycleInspectorStatus | 34 +++--
html/Elements/LifecycleInspectorText | 5 +-
lib/RT/Extension/LifecycleUI.pm | 22 +++
static/css/lifecycleui-editor.css | 53 +++++--
static/css/lifecycleui-viewer-interactive.css | 38 ++++-
static/js/lifecycleui-editor.js | 170 ++++++++++++++++-----
static/js/lifecycleui-model.js | 75 ++++++---
static/js/lifecycleui-viewer-interactive.js | 10 ++
static/js/lifecycleui-viewer.js | 60 ++++++--
18 files changed, 591 insertions(+), 161 deletions(-)
create mode 100644 MANIFEST
create mode 100644 html/Admin/Lifecycles/Mappings.html
- Log -----------------------------------------------------------------
commit 12d61a4d739996496d1af6e8dcde1d1e38f51d9f
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:13:58 2017 +0000
Enhance interactive menus with superfish
diff --git a/static/css/lifecycleui-viewer-interactive.css b/static/css/lifecycleui-viewer-interactive.css
index 6a9f6c6..0e08906 100644
--- a/static/css/lifecycleui-viewer-interactive.css
+++ b/static/css/lifecycleui-viewer-interactive.css
@@ -18,3 +18,6 @@
text-decoration: none;
}
+.lifecycle-ui .status-menu .sf-menu.sf-vertical {
+ width: 12em;
+}
diff --git a/static/js/lifecycleui-viewer-interactive.js b/static/js/lifecycleui-viewer-interactive.js
index ee107d4..47400a8 100644
--- a/static/js/lifecycleui-viewer-interactive.js
+++ b/static/js/lifecycleui-viewer-interactive.js
@@ -34,6 +34,8 @@ jQuery(function () {
this.menuContainer.find('.status-menu.selected').removeClass('selected');
this.selectedMenu.addClass('selected');
+ this.selectedMenu.find(".toplevel").addClass('sf-menu sf-vertical sf-js-enabled sf-shadow').supersubs().superfish({ speed: 'fast' });
+
this._setMenuPosition();
};
commit cc68b0133ac0287977080ab86e1c220c2386ec1b
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:14:17 2017 +0000
Don't highlight disabled menu items on hover
diff --git a/static/css/lifecycleui-viewer-interactive.css b/static/css/lifecycleui-viewer-interactive.css
index 0e08906..c20a93f 100644
--- a/static/css/lifecycleui-viewer-interactive.css
+++ b/static/css/lifecycleui-viewer-interactive.css
@@ -9,15 +9,22 @@
display: block;
}
-.lifecycle-ui .status-menu .not-current,
-.lifecycle-ui .status-menu .no-transition,
-.lifecycle-ui .status-menu .no-permission,
-.lifecycle-ui .status-menu .hide-resolve-with-deps {
+.lifecycle-ui .status-menu a.not-current,
+.lifecycle-ui .status-menu a.no-transition,
+.lifecycle-ui .status-menu a.no-permission,
+.lifecycle-ui .status-menu a.hide-resolve-with-deps {
color: #AAAAAA;
cursor: default;
text-decoration: none;
}
+.lifecycle-ui .status-menu .not-current:hover,
+.lifecycle-ui .status-menu .no-transition:hover,
+.lifecycle-ui .status-menu .no-permission:hover,
+.lifecycle-ui .status-menu .hide-resolve-with-deps:hover {
+ background-color: #fff;
+}
+
.lifecycle-ui .status-menu .sf-menu.sf-vertical {
width: 12em;
}
diff --git a/static/js/lifecycleui-viewer-interactive.js b/static/js/lifecycleui-viewer-interactive.js
index 47400a8..79a0e8f 100644
--- a/static/js/lifecycleui-viewer-interactive.js
+++ b/static/js/lifecycleui-viewer-interactive.js
@@ -61,6 +61,14 @@ jQuery(function () {
Super.prototype.initializeViewer.call(self, node, name, config, focusStatus);
self.menuContainer = jQuery(node).find('.status-menus');
self.svg.on('click', function () { self.deselectStatus() });
+
+ // copy classes from <a> to <li> for improved styling
+ self.menuContainer.find('.status-menu li a').each(function () {
+ var link = jQuery(this);
+ var item = link.closest('li');
+ item.addClass(link.attr("class"));
+ item.removeClass('menu-item');
+ });
};
RT.LifecycleViewerInteractive = Interactive;
commit cb6456483533ac3be4999f9ac5767a6ec647d1d6
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:19:17 2017 +0000
More styling improvements for status menus
diff --git a/static/css/lifecycleui-viewer-interactive.css b/static/css/lifecycleui-viewer-interactive.css
index c20a93f..191a048 100644
--- a/static/css/lifecycleui-viewer-interactive.css
+++ b/static/css/lifecycleui-viewer-interactive.css
@@ -9,6 +9,12 @@
display: block;
}
+.lifecycle-ui .status-menu .sf-menu a:visited,
+.lifecycle-ui .status-menu .sf-menu a {
+ border: none;
+ color: #000;
+}
+
.lifecycle-ui .status-menu a.not-current,
.lifecycle-ui .status-menu a.no-transition,
.lifecycle-ui .status-menu a.no-permission,
@@ -26,5 +32,19 @@
}
.lifecycle-ui .status-menu .sf-menu.sf-vertical {
- width: 12em;
+ width: 10em;
+}
+
+.lifecycle-ui .status-menu .sf-menu.sf-vertical li {
+ width: 100%;
}
+
+.lifecycle-ui .status-menu .sf-menu.sf-shadow {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+ -moz-box-shadow: 2px 2px 8px -2px #999;
+ -webkit-box-shadow: 2px 2px 8px -2px #999;
+ box-shadow: 2px 2px 8px -2px #999;
+}
+
commit 66f3d135d9fb234649fcf2b327e90e916ec5b2c7
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:46:12 2017 +0000
Improve canvas menu using superfish
diff --git a/html/Elements/LifecycleInspectorCanvas b/html/Elements/LifecycleInspectorCanvas
index 20f5bb6..b64410a 100644
--- a/html/Elements/LifecycleInspectorCanvas
+++ b/html/Elements/LifecycleInspectorCanvas
@@ -58,38 +58,39 @@
{{/each}}
{{/select}}
</select><br>
-
- <button class="add-status"><&|/l&>Add Status</&></button><br>
- <ul>
- <li>Add Decoration...
+ <br>
+
+ <ul class="toplevel">
+ <li><a href="javascript:void(0)" class="menu-item add-status"><&|/l&>Add Status</&></a></li>
+ <li class="has-children"><a href="javascript:void(0)" class="menu-item">Add Decoration...</a>
<ul>
- <li><a href="#" class="add-text">Add Text</a></li>
- <li><a href="#" class="add-polygon" data-type="Triangle">Add Triangle</a></li>
- <li><a href="#" class="add-polygon" data-type="Rectangle">Add Rectangle</a></li>
- <li><a href="#" class="add-circle">Add Circle</a></li>
- <li><a href="#" class="add-line">Add Line</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-text">Add Text</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-polygon" data-type="Triangle">Add Triangle</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-polygon" data-type="Rectangle">Add Rectangle</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-circle">Add Circle</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-line">Add Line</a></li>
</ul>
</li>
- <li>Select Status...
+ <li class="has-children"><a href="javascript:void(0)" class="menu-item">Select Status...</a>
<ul>
{{#each lifecycle.statuses}}
- <li><a href="#" class="select-status" data-name="{{this}}">{{this}}</a></li>
+ <li><a href="javascript:void(0)" class="menu-item select-status" data-name="{{this}}">{{this}}</a></li>
{{/each}}
</ul>
</li>
- <li>Select Decoration...
+ <li class="has-children"><a href="javascript:void(0)" class="menu-item">Select Decoration...</a>
<ul>
{{#each lifecycle.decorations.text}}
- <li><a href="#" class="select-decoration" data-key="{{this._key}}">{{truncate this.text}}</a></li>
+ <li><a href="javascript:void(0)" class="menu-item select-decoration" data-key="{{this._key}}">{{truncate this.text}}</a></li>
{{/each}}
{{#each lifecycle.decorations.polygon}}
- <li><a href="#" class="select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
+ <li><a href="javascript:void(0)" class="menu-item select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
{{/each}}
{{#each lifecycle.decorations.circle}}
- <li><a href="#" class="select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
+ <li><a href="javascript:void(0)" class="menu-item select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
{{/each}}
{{#each lifecycle.decorations.line}}
- <li><a href="#" class="select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
+ <li><a href="javascript:void(0)" class="menu-item select-decoration" data-key="{{this._key}}">{{truncate this.label}}</a></li>
{{/each}}
</ul>
</li>
diff --git a/static/css/lifecycleui-editor.css b/static/css/lifecycleui-editor.css
index e047a1d..741d1c8 100644
--- a/static/css/lifecycleui-editor.css
+++ b/static/css/lifecycleui-editor.css
@@ -89,16 +89,6 @@
margin-top: 0;
}
-.lifecycle-ui .inspector .canvas ul {
- list-style-type: none;
- padding: 0;
-}
-
-.lifecycle-ui .inspector .canvas ul ul {
- padding-left: 3em;
- margin-bottom: 1em;
-}
-
.lifecycle-ui .inspector .hint {
vertical-align: super;
font-size: .8em;
@@ -108,3 +98,24 @@
.lifecycle-ui .invisible {
visibility: hidden;
}
+
+.lifecycle-ui .inspector .sf-menu a:visited,
+.lifecycle-ui .inspector .sf-menu a {
+ border: none;
+ color: #000;
+}
+
+.lifecycle-ui .inspector .sf-menu.sf-vertical {
+ margin-left: -1em;
+}
+
+.lifecycle-ui .inspector .sf-menu.sf-vertical,
+.lifecycle-ui .inspector .sf-menu.sf-vertical > li {
+ width: 175px;
+}
+
+.lifecycle-ui .inspector .sf-vertical li:hover ul,
+.lifecycle-ui .inspector .sf-vertical li.sfHover ul {
+ left: 175px;
+}
+
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index b43e6f6..2b94259 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -58,6 +58,8 @@ jQuery(function () {
inspector.find('.content').html(self.templates[type](params));
+ inspector.find(".toplevel").addClass('sf-menu sf-vertical sf-js-enabled sf-shadow').supersubs().superfish({ speed: 'fast' });
+
inspector.find(':checkbox[data-show-hide]').each(function () {
var field = jQuery(this);
var selector = field.data('show-hide');
commit 9ad50859cc3ec1eb7affa1b5f9a641ce04a487ac
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:48:46 2017 +0000
Add missing </span>
diff --git a/html/Elements/LifecycleInspectorStatus b/html/Elements/LifecycleInspectorStatus
index 035fa6c..206fd3b 100644
--- a/html/Elements/LifecycleInspectorStatus
+++ b/html/Elements/LifecycleInspectorStatus
@@ -8,7 +8,7 @@
<option value="inactive"><&|/l&>inactive</&></option>
{{/select}}
</select><br>
- <span title="<&|/l&>Can this status be selected on creation?</&>">Creation<span class="hint" >[?]</span>: <input type="checkbox" name="creation" {{#if status.creation}}checked=checked{{/if}}><br>
+ <span title="<&|/l&>Can this status be selected on creation?</&>">Creation<span class="hint" >[?]</span>: <input type="checkbox" name="creation" {{#if status.creation}}checked=checked{{/if}}></span><br>
Color: <span class="color-control" data-field="color"><span class="current-color" title="{{status.color}}" style="background-color: {{status.color}}"> </span> <button class="change-color"><&|/l&>Change</&></button></span><br>
Add Transition:
commit 2ce3c325523e07be4e9ab794020996d6631e7526
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 15:51:37 2017 +0000
Improve status transition menu to use superfish
diff --git a/html/Elements/LifecycleInspectorStatus b/html/Elements/LifecycleInspectorStatus
index 206fd3b..8aec7eb 100644
--- a/html/Elements/LifecycleInspectorStatus
+++ b/html/Elements/LifecycleInspectorStatus
@@ -11,21 +11,25 @@
<span title="<&|/l&>Can this status be selected on creation?</&>">Creation<span class="hint" >[?]</span>: <input type="checkbox" name="creation" {{#if status.creation}}checked=checked{{/if}}></span><br>
Color: <span class="color-control" data-field="color"><span class="current-color" title="{{status.color}}" style="background-color: {{status.color}}"> </span> <button class="change-color"><&|/l&>Change</&></button></span><br>
- Add Transition:
- <ul>
- {{#each lifecycle.statuses}}
- <li class="{{#if (canAddTransition ../status.name this ../lifecycle)}}{{else}}hidden{{/if}}"><a href="#" class="add-transition" data-from="{{../status.name}}" data-to="{{this}}"><&|/l, "{{this}}"&>to [_1]</&></a></li>
- {{/each}}
- </ul>
- Select Transition:
- <ul>
- {{#each lifecycle.statuses}}
- <li class="{{#if (canSelectTransition ../status.name this ../lifecycle)}}{{else}}hidden{{/if}}"><a href="#" class="select-transition" data-from="{{../status.name}}" data-to="{{this}}"><&|/l, "{{this}}"&>to [_1]</&></a></li>
- {{/each}}
- {{#each lifecycle.statuses}}
- <li class="{{#if (canSelectTransition this ../status.name ../lifecycle)}}{{else}}hidden{{/if}}"><a href="#" class="select-transition" data-to="{{../status.name}}" data-from="{{this}}"><&|/l, "{{this}}"&>from [_1]</&></a></li>
- {{/each}}
+ <ul class="toplevel">
+ <li><a href="javascript:void(0)" class="menu-item">Add Transition...</a>
+ <ul>
+ {{#each lifecycle.statuses}}
+ <li class="{{#if (canAddTransition ../status.name this ../lifecycle)}}{{else}}hidden{{/if}}"><a href="javascript:void(0)" class="menu-item add-transition" data-from="{{../status.name}}" data-to="{{this}}"><&|/l, "{{this}}"&>to [_1]</&></a></li>
+ {{/each}}
+ </ul>
+ <li><a href="javascript:void(0)" class="menu-item">Select Transition...</a>
+ <ul>
+ {{#each lifecycle.statuses}}
+ <li class="{{#if (canSelectTransition ../status.name this ../lifecycle)}}{{else}}hidden{{/if}}"><a href="#" class="menu-item select-transition" data-from="{{../status.name}}" data-to="{{this}}"><&|/l, "{{this}}"&>to [_1]</&></a></li>
+ {{/each}}
+ {{#each lifecycle.statuses}}
+ <li class="{{#if (canSelectTransition this ../status.name ../lifecycle)}}{{else}}hidden{{/if}}"><a href="#" class="menu-item select-transition" data-to="{{../status.name}}" data-from="{{this}}"><&|/l, "{{this}}"&>from [_1]</&></a></li>
+ {{/each}}
+ </ul>
+ </li>
</ul>
+
<button class="delete"><&|/l&>Delete Status</&></button>
</div>
</script>
commit f7bbd0fbaa4f721d64f6e0423cf130c3d8e603b2
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 16:02:25 2017 +0000
Always render a text background rect
diff --git a/static/css/lifecycleui-editor.css b/static/css/lifecycleui-editor.css
index 741d1c8..f8809ea 100644
--- a/static/css/lifecycleui-editor.css
+++ b/static/css/lifecycleui-editor.css
@@ -74,10 +74,13 @@
opacity: 1;
}
-.lifecycle-ui.editing svg.has-focus .decorations .text-background {
+.lifecycle-ui.editing .decorations .text-background {
stroke: none;
+ fill: none;
+}
+
+.lifecycle-ui.editing svg.has-focus .decorations .focus.text-background {
fill: white;
- opacity: 1;
filter: url(#focus);
}
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 2b94259..959f2c8 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -309,36 +309,47 @@ jQuery(function () {
this.renderDisplay();
};
- // add a rect under the focused text decoration for highlighting
+ // add rects under text decorations for highlighting
Editor.prototype.renderTextDecorations = function (initial) {
Super.prototype.renderTextDecorations.call(this, initial);
var self = this;
- if (!self._focusItem || self._focusItem._type != 'text') {
- self.decorationContainer.selectAll("rect")
- .data([])
- .exit()
- .remove();
- return;
- }
+ self.renderTextDecorationBackgrounds(initial);
+ };
- var d = self._focusItem;
- var label = self.decorationContainer.select("text[data-key='"+d._key+"']");
- var rect = label.node().getBoundingClientRect();
- var width = rect.width;
- var height = rect.height;
- var padding = 5;
+ Editor.prototype.renderTextDecorationBackgrounds = function (initial) {
+ var self = this;
+ var rects = self.decorationContainer.selectAll("rect.text-background")
+ .data(self.lifecycle.decorations.text, function (d) { return d._key });
- var background = self.decorationContainer.selectAll("rect")
- .data([d], function (d) { return d._key });
+ rects.exit()
+ .classed("removing", true)
+ .transition().duration(200)
+ .remove();
- background.enter().insert("rect", ":first-child")
+ rects.enter().insert("rect", ":first-child")
+ .attr("data-key", function (d) { return d._key })
.classed("text-background", true)
- .merge(background)
- .attr("x", self.xScale(d.x)-padding)
- .attr("y", self.yScale(d.y)-height-padding)
- .attr("width", width+padding*2)
- .attr("height", height+padding*2)
+ .on("click", function (d) {
+ d3.event.stopPropagation();
+ self.clickedDecoration(d);
+ })
+ .call(function (rects) { self.didEnterTextDecorations(rects) })
+ .merge(rects)
+ .classed("focus", function (d) { return self.isFocused(d) })
+ .each(function (d) {
+ var rect = d3.select(this);
+ var label = self.decorationContainer.select("text[data-key='"+d._key+"']");
+ var bbox = label.node().getBoundingClientRect();
+ var width = bbox.width;
+ var height = bbox.height;
+ var padding = 5;
+
+ rect.attr("x", self.xScale(d.x)-padding)
+ .attr("y", self.yScale(d.y)-height-padding)
+ .attr("width", width+padding*2)
+ .attr("height", height+padding*2);
+ });
};
Editor.prototype.renderPolygonDecorations = function (initial) {
commit 3e9de82b31c76628d8b38084c55d8d69a7386f84
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 16:16:06 2017 +0000
Highlight on hover
diff --git a/html/Elements/LifecycleGraphExtras b/html/Elements/LifecycleGraphExtras
index a46f56f..ad954b0 100644
--- a/html/Elements/LifecycleGraphExtras
+++ b/html/Elements/LifecycleGraphExtras
@@ -21,3 +21,14 @@
</feMerge>
</filter>
+<filter id="hover" x="-100%" y="-100%" height="300%" width="300%">
+ <feFlood result="flood" flood-color="#80A8FF" flood-opacity="1"></feFlood>
+ <feComposite in="flood" result="mask" in2="SourceGraphic" operator="in"></feComposite>
+ <feMorphology in="mask" result="dilated" operator="dilate" radius="5"></feMorphology>
+ <feGaussianBlur in="dilated" result="blurred" stdDeviation="3"></feGaussianBlur>
+ <feMerge>
+ <feMergeNode in="blurred"></feMergeNode>
+ <feMergeNode in="SourceGraphic"></feMergeNode>
+ </feMerge>
+</filter>
+
diff --git a/static/css/lifecycleui-editor.css b/static/css/lifecycleui-editor.css
index f8809ea..b76e4b2 100644
--- a/static/css/lifecycleui-editor.css
+++ b/static/css/lifecycleui-editor.css
@@ -122,3 +122,13 @@
left: 175px;
}
+.lifecycle-ui .statuses circle.hover,
+.lifecycle-ui .transitions .hover,
+.lifecycle-ui .decorations :not(text).hover {
+ opacity: 1;
+ filter: url(#hover);
+}
+
+.lifecycle-ui.editing .decorations .hover.text-background {
+ fill: white;
+}
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 959f2c8..5857017 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -190,6 +190,12 @@ jQuery(function () {
self.focusItem(d);
});
+ inspector.on('mouseenter', 'a.select-status', function (e) {
+ var statusName = jQuery(this).data('name');
+ var d = self.lifecycle.statusObjectForName(statusName);
+ self.hoverItem(d);
+ });
+
inspector.on('click', 'a.select-transition', function (e) {
e.preventDefault();
var button = jQuery(this);
@@ -200,6 +206,15 @@ jQuery(function () {
self.focusItem(d);
});
+ inspector.on('mouseenter', 'a.select-transition', function (e) {
+ var button = jQuery(this);
+ var fromStatus = button.data('from');
+ var toStatus = button.data('to');
+
+ var d = self.lifecycle.hasTransition(fromStatus, toStatus);
+ self.hoverItem(d);
+ });
+
inspector.on('click', 'a.select-decoration', function (e) {
e.preventDefault();
var key = jQuery(this).data('key');
@@ -207,6 +222,16 @@ jQuery(function () {
self.focusItem(d);
});
+ inspector.on('mouseenter', 'a.select-decoration', function (e) {
+ var key = jQuery(this).data('key');
+ var d = self.lifecycle.itemForKey(key);
+ self.hoverItem(d);
+ });
+
+ inspector.on('mouseleave', 'a.select-status, a.select-transition, a.select-decoration', function () {
+ self.hoverItem(null);
+ });
+
inspector.on('click', '.add-status', function (e) {
e.preventDefault();
self.addNewStatus();
@@ -509,6 +534,7 @@ jQuery(function () {
Super.prototype.defocus.call(this);
this.setInspectorContent(null);
this.removePointHandles();
+ this.hoverItem(null);
this.renderDisplay();
};
@@ -523,5 +549,13 @@ jQuery(function () {
this.renderDisplay();
};
+ Editor.prototype.hoverItem = function (item) {
+ this.svg.selectAll(".hover").classed('hover', false);
+
+ if (item) {
+ this.svg.selectAll("*[data-key='"+item._key+"']").classed('hover', true);
+ }
+ };
+
RT.LifecycleEditor = Editor;
});
commit 54d36bcd20035d4c33854102a0b4cb3195313a47
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 16:28:21 2017 +0000
Add select transition from/to menu
diff --git a/html/Elements/LifecycleInspectorCanvas b/html/Elements/LifecycleInspectorCanvas
index b64410a..602e702 100644
--- a/html/Elements/LifecycleInspectorCanvas
+++ b/html/Elements/LifecycleInspectorCanvas
@@ -78,6 +78,23 @@
{{/each}}
</ul>
</li>
+ <li class="has-children"><a href="javascript:void(0)" class="menu-item">Select Transition...</a>
+ <ul>
+ {{#each lifecycle.statuses}}
+ <li class="has-children"><a href="javascript:void(0)" class="menu-item select-status" data-name="{{this}}"><&|/l, "{{this}}"&>from [_1]</&></a>
+ <ul>
+ {{#with this as |from|}}
+ {{#with ../lifecycle as |lc|}}
+ {{#each lc.statuses}}
+ <li class="menu-item {{#if (canSelectTransition from this lc)}}{{else}}hidden{{/if}}"><a href="#" class="menu-item select-transition" data-from="{{from}}" data-to="{{this}}"><&|/l, "{{this}}"&>to [_1]</&></a></li>
+ {{/each}}
+ {{/with}}
+ {{/with}}
+ </ul>
+ </li>
+ {{/each}}
+ </ul>
+ </li>
<li class="has-children"><a href="javascript:void(0)" class="menu-item">Select Decoration...</a>
<ul>
{{#each lifecycle.decorations.text}}
commit 3b276849ea7979ce874e8332f25b2bfea7f20a9e
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 16:36:36 2017 +0000
Scaffolding for mappings UI
diff --git a/html/Admin/Lifecycles/Mappings.html b/html/Admin/Lifecycles/Mappings.html
new file mode 100644
index 0000000..cc18044
--- /dev/null
+++ b/html/Admin/Lifecycles/Mappings.html
@@ -0,0 +1,31 @@
+<& /Admin/Elements/Header, Title => $title &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
+
+<form action="<%RT->Config->Get('WebPath')%>/Admin/Lifecycles/Mappings.html" name="ModifyMappings" method="post" enctype="multipart/form-data">
+<input type="hidden" class="hidden" name="Name" value="<% $LifecycleObj->Name %>" />
+<input type="hidden" class="hidden" name="Type" value="<% $LifecycleObj->Type %>" />
+
+<& /Elements/Submit, Label => loc('Save Changes') &>
+
+</form>
+<%INIT>
+my ($title, @results);
+my $LifecycleObj = RT::Lifecycle->new();
+$LifecycleObj->Load(Name => $Name, Type => $Type);
+
+Abort("Invalid lifecycle") unless $LifecycleObj->Name
+ && $LifecycleObj->{data}{type} eq $Type;
+
+$title = loc("Modify lifecycle [_1]", $LifecycleObj->Name);
+
+# This code does automatic redirection if any updates happen.
+MaybeRedirectForResults(
+ Actions => \@results,
+ Arguments => { Name => $LifecycleObj->Name, Type => $LifecycleObj->Type },
+);
+</%INIT>
+<%ARGS>
+$Name => undef
+$Type => undef
+</%ARGS>
diff --git a/html/Callbacks/RT-Extension-LifecycleUI/Elements/Tabs/Privileged b/html/Callbacks/RT-Extension-LifecycleUI/Elements/Tabs/Privileged
index f2388ac..ea9bd5f 100644
--- a/html/Callbacks/RT-Extension-LifecycleUI/Elements/Tabs/Privileged
+++ b/html/Callbacks/RT-Extension-LifecycleUI/Elements/Tabs/Privileged
@@ -34,6 +34,7 @@ if ( $Path =~ m{^/Admin/Lifecycles} ) {
my $menu = PageMenu();
$menu->child( basics => title => loc('Modify'), path => "/Admin/Lifecycles/Modify.html?Type=" . $Type_uri . "&Name=" . $Name_uri );
+ $menu->child( mappings => title => loc('Mappings'), path => "/Admin/Lifecycles/Mappings.html?Type=" . $Type_uri . "&Name=" . $Name_uri );
}
}
else {
commit f058230e7537f1f2724cace1aef2e0789e0803ae
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 17:39:04 2017 +0000
Copy the initial points
Otherwise adding multiple polygons will result in their point handles being
linked
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index f196f51..5d119fe 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -604,7 +604,7 @@ jQuery(function () {
renderFill: true,
x: 0.5,
y: 0.5,
- points: this._initialPointsForPolygon[type]
+ points: JSON.parse(JSON.stringify(this._initialPointsForPolygon[type]))
};
this.decorations.polygon.push(item);
this._keyMap[item._key] = item;
commit 0653f4538d4d6576b70b06d76f54ec3b3c3927f2
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 17:43:43 2017 +0000
Put point handles in transform container
This way they render over top of everything else
diff --git a/static/css/lifecycleui-editor.css b/static/css/lifecycleui-editor.css
index b76e4b2..ac972a0 100644
--- a/static/css/lifecycleui-editor.css
+++ b/static/css/lifecycleui-editor.css
@@ -65,7 +65,6 @@
}
.lifecycle-ui.editing svg.has-focus .decorations .focus,
-.lifecycle-ui.editing svg.has-focus .decorations .point-handle,
.lifecycle-ui.editing svg.has-focus .transitions .focus {
opacity: 1;
}
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 5857017..e4fe8b7 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -381,7 +381,7 @@ jQuery(function () {
Super.prototype.renderPolygonDecorations.call(this, initial);
var self = this;
- var handles = self.decorationContainer.selectAll("circle.point-handle")
+ var handles = self.transformContainer.selectAll("circle.point-handle")
.data(self.pointHandles || [], function (d) { return d._key });
handles.exit()
commit d54601dc9b0fa5a6b2683f60353488f8a11d37a0
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:08:13 2017 +0000
First pass at lifecycle mapping UI
diff --git a/html/Admin/Lifecycles/Mappings.html b/html/Admin/Lifecycles/Mappings.html
index cc18044..0118fa2 100644
--- a/html/Admin/Lifecycles/Mappings.html
+++ b/html/Admin/Lifecycles/Mappings.html
@@ -6,7 +6,37 @@
<input type="hidden" class="hidden" name="Name" value="<% $LifecycleObj->Name %>" />
<input type="hidden" class="hidden" name="Type" value="<% $LifecycleObj->Type %>" />
-<& /Elements/Submit, Label => loc('Save Changes') &>
+% for my $Other (@lifecycles) {
+% my $FromMapping = $Other->MoveMap($LifecycleObj);
+% my $ToMapping = $LifecycleObj->MoveMap($Other);
+% my @OtherStatuses = $Other->Valid;
+
+ <&| /Widgets/TitleBox, title => $Other->Name &>
+
+<h3><&|/l, $Other->Name, $LifecycleObj->Name &>Changing from [_1] to [_2]:</&></h3>
+<table>
+% for my $OtherStatus (@OtherStatuses) {
+ <tr>
+ <td><% $OtherStatus %>:</td>
+ <td><& /Elements/SelectStatus, Statuses => \@MyStatuses, Default => $FromMapping->{$OtherStatus}, Name => 'map-' . $Other->Name . '-' . $OtherStatus . '--' . $LifecycleObj->Name&></td>
+ </tr>
+% }
+</table>
+
+<h3><&|/l, $LifecycleObj->Name, $Other->Name &>Changing from [_1] to [_2]:</&></h3>
+<table>
+% for my $MyStatus (@MyStatuses) {
+ <tr>
+ <td><% $MyStatus %>:</td>
+ <td><& /Elements/SelectStatus, Statuses => \@OtherStatuses, Default => $ToMapping->{$MyStatus}, Name => 'map-' . $LifecycleObj->Name . '-' . $MyStatus . '--' . $Other->Name &></td>
+ </tr>
+% }
+</table>
+
+ </&>
+% }
+
+<& /Elements/Submit, Name => 'Update', Label => loc('Save Changes') &>
</form>
<%INIT>
@@ -17,15 +47,42 @@ $LifecycleObj->Load(Name => $Name, Type => $Type);
Abort("Invalid lifecycle") unless $LifecycleObj->Name
&& $LifecycleObj->{data}{type} eq $Type;
-$title = loc("Modify lifecycle [_1]", $LifecycleObj->Name);
+my @MyStatuses = $LifecycleObj->Valid;
+
+$title = loc("Lifecycle [_1] Mappings", $LifecycleObj->Name);
# This code does automatic redirection if any updates happen.
MaybeRedirectForResults(
Actions => \@results,
Arguments => { Name => $LifecycleObj->Name, Type => $LifecycleObj->Type },
);
+
+my @lifecycle_names = grep { $_ ne 'approvals' } RT::Lifecycle->ListAll($Type);
+
+if ($Update) {
+ my %maps;
+ my $lifecycle_re = join '|', map { quotemeta($_) } @lifecycle_names;
+ for my $key (keys %ARGS) {
+ my ($from_lifecycle, $from_status, $to_lifecycle) = $key =~ /^map-($lifecycle_re)-(.*)--($lifecycle_re)$/ or next;
+ if (my $to_status = $ARGS{$key}) {
+ $maps{"$from_lifecycle -> $to_lifecycle"}{$from_status} = $to_status;
+ }
+ }
+
+ my ($ok, $msg) = RT::Extension::LifecycleUI->UpdateMaps(
+ CurrentUser => $session{CurrentUser},
+ Maps => \%maps,
+ );
+ push @results, $msg;
+}
+
+my @lifecycles = map { RT::Lifecycle->Load(Name => $_, Type => $Type) }
+ sort { loc($a) cmp loc($b) }
+ grep { $_ ne $Name }
+ @lifecycle_names;
</%INIT>
<%ARGS>
$Name => undef
$Type => undef
+$Update => undef
</%ARGS>
diff --git a/lib/RT/Extension/LifecycleUI.pm b/lib/RT/Extension/LifecycleUI.pm
index 0bade1a..bac5221 100644
--- a/lib/RT/Extension/LifecycleUI.pm
+++ b/lib/RT/Extension/LifecycleUI.pm
@@ -156,6 +156,28 @@ sub UpdateLifecycle {
return (1, $CurrentUser->loc("Lifecycle [_1] updated", $name));
}
+sub UpdateMaps {
+ my $class = shift;
+ my %args = (
+ CurrentUser => undef,
+ Maps => undef,
+ @_,
+ );
+
+ my $CurrentUser = $args{CurrentUser};
+ my $lifecycles = RT->Config->Get('Lifecycles');
+
+ %{ $lifecycles->{__maps__} } = (
+ %{ $lifecycles->{__maps__} || {} },
+ %{ $args{Maps} },
+ );
+
+ my ($ok, $msg) = $class->_SaveLifecycles($lifecycles, $CurrentUser);
+ return ($ok, $msg) if !$ok;
+
+ return (1, $CurrentUser->loc("Lifecycle mappings updated"));
+}
+
=head1 NAME
RT-Extension-LifecycleUI - manage lifecycles via admin UI
commit 5b583b6e365890177574285ee8eaa10b7f4552c5
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:10:58 2017 +0000
Hide "Lifecycle created" or "Lifecycle updated" message
It's valuable screen real estate
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index e4fe8b7..4ac57a4 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -528,6 +528,10 @@ jQuery(function () {
d3.select(node).select('button.redo').classed('invisible', !self.lifecycle.hasRedoStack());
};
self.lifecycle.undoStateChangedCallback();
+
+ setTimeout(function () {
+ jQuery('.results').slideUp();
+ }, 10*1000);
};
Editor.prototype.defocus = function () {
commit 0c6f9ac75c0f802e00b6f67d7c2d35334d79ea98
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:49:36 2017 +0000
Create objects at center of current viewport
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 4ac57a4..22ea669 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -469,23 +469,34 @@ jQuery(function () {
circles.call(this._createDrag());
};
+ Editor.prototype.viewportCenterPoint = function () {
+ var rect = this.svg.node().getBoundingClientRect();
+ var x = (rect.width / 2 - this._currentZoom.x)/this._currentZoom.k;
+ var y = (rect.height / 2 - this._currentZoom.y)/this._currentZoom.k;
+ return [this.xScaleInvert(x), this.yScaleInvert(y)];
+ };
+
Editor.prototype.addNewStatus = function () {
- var status = this.lifecycle.createStatus();
+ var p = this.viewportCenterPoint();
+ var status = this.lifecycle.createStatus(p[0], p[1]);
this.focusItem(status);
};
Editor.prototype.addNewTextDecoration = function () {
- var text = this.lifecycle.createTextDecoration();
+ var p = this.viewportCenterPoint();
+ var text = this.lifecycle.createTextDecoration(p[0], p[1]);
this.focusItem(text);
};
Editor.prototype.addNewPolygonDecoration = function (type) {
- var polygon = this.lifecycle.createPolygonDecoration(type);
+ var p = this.viewportCenterPoint();
+ var polygon = this.lifecycle.createPolygonDecoration(p[0], p[1], type);
this.focusItem(polygon);
};
Editor.prototype.addNewCircleDecoration = function () {
- var circle = this.lifecycle.createCircleDecoration();
+ var p = this.viewportCenterPoint();
+ var circle = this.lifecycle.createCircleDecoration(p[0], p[1]);
this.focusItem(circle);
};
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index 5d119fe..8c8324e 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -546,7 +546,7 @@ jQuery(function () {
point.y = y;
};
- Lifecycle.prototype.createStatus = function () {
+ Lifecycle.prototype.createStatus = function (x, y) {
this._saveUndoEntry();
var name;
@@ -565,8 +565,8 @@ jQuery(function () {
_type: 'status',
name: name,
type: 'initial',
- x: 0.5,
- y: 0.5,
+ x: x,
+ y: y
};
item.color = defaultColors(item._key);
@@ -575,22 +575,22 @@ jQuery(function () {
return item;
};
- Lifecycle.prototype.createTextDecoration = function () {
+ Lifecycle.prototype.createTextDecoration = function (x, y) {
this._saveUndoEntry();
var item = {
_key: _ELEMENT_KEY_SEQ++,
_type: 'text',
text: 'New label',
- x: 0.5,
- y: 0.5,
+ x: x,
+ y: y
};
this.decorations.text.push(item);
this._keyMap[item._key] = item;
return item;
};
- Lifecycle.prototype.createPolygonDecoration = function (type) {
+ Lifecycle.prototype.createPolygonDecoration = function (x, y, type) {
this._saveUndoEntry();
var item = {
@@ -602,8 +602,8 @@ jQuery(function () {
strokeStyle: 'solid',
fill: '#ffffff',
renderFill: true,
- x: 0.5,
- y: 0.5,
+ x: x,
+ y: y,
points: JSON.parse(JSON.stringify(this._initialPointsForPolygon[type]))
};
this.decorations.polygon.push(item);
@@ -611,7 +611,7 @@ jQuery(function () {
return item;
};
- Lifecycle.prototype.createCircleDecoration = function () {
+ Lifecycle.prototype.createCircleDecoration = function (x, y) {
this._saveUndoEntry();
var item = {
@@ -623,8 +623,8 @@ jQuery(function () {
strokeStyle: 'solid',
fill: '#ffffff',
renderFill: true,
- x: 0.5,
- y: 0.5,
+ x: x,
+ y: y,
r: 35
};
this.decorations.circle.push(item);
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index 3a81e9f..03c87f4 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -32,6 +32,7 @@ jQuery(function () {
};
Viewer.prototype.didZoom = function () {
+ this._currentZoom = d3.event.transform;
this.transformContainer.attr("transform", d3.event.transform);
};
@@ -393,7 +394,7 @@ jQuery(function () {
self._yScale = self.createScale(self.height, self.padding);
self._xScaleZero = self.createScale(self.width, 0);
self._yScaleZero = self.createScale(self.height, 0);
- self._zoomIdentity = d3.zoomIdentity;
+ self._zoomIdentity = self._currentZoom = d3.zoomIdentity;
self.lifecycle = new RT.Lifecycle(name);
self.lifecycle.initializeFromConfig(config);
commit 86b6519b2d2052a4648ea4a2f0404bec03f18f65
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:50:01 2017 +0000
Take radius as input parameter for creating circles
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 22ea669..950bab0 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -496,7 +496,7 @@ jQuery(function () {
Editor.prototype.addNewCircleDecoration = function () {
var p = this.viewportCenterPoint();
- var circle = this.lifecycle.createCircleDecoration(p[0], p[1]);
+ var circle = this.lifecycle.createCircleDecoration(p[0], p[1], self.statusCircleRadius);
this.focusItem(circle);
};
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index 8c8324e..4e7a863 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -611,7 +611,7 @@ jQuery(function () {
return item;
};
- Lifecycle.prototype.createCircleDecoration = function (x, y) {
+ Lifecycle.prototype.createCircleDecoration = function (x, y, r) {
this._saveUndoEntry();
var item = {
@@ -625,7 +625,7 @@ jQuery(function () {
renderFill: true,
x: x,
y: y,
- r: 35
+ r: r
};
this.decorations.circle.push(item);
this._keyMap[item._key] = item;
commit fca968ad066e92cb6dfbe82b645bbd01226ba4d0
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:58:08 2017 +0000
Give lines an x,y
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 950bab0..1e1e257 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -294,11 +294,7 @@ jQuery(function () {
_key: d._key + '-' + i,
i: i,
x: d.points[i].x,
- y: d.points[i].y,
- xScale: d._type == 'polygon' ? function (v) { return self.xScaleZero(v) } : function (v) { return self.xScale(v) },
- yScale: d._type == 'polygon' ? function (v) { return self.yScaleZero(v) } : function (v) { return self.yScale(v) },
- xScaleInvert: d._type == 'polygon' ? function (v) { return self.xScaleZeroInvert(v) } : function (v) { return self.xScaleInvert(v) },
- yScaleInvert: d._type == 'polygon' ? function (v) { return self.yScaleZeroInvert(v) } : function (v) { return self.yScaleInvert(v) }
+ y: d.points[i].y
});
}
self.pointHandles = points;
@@ -314,10 +310,10 @@ jQuery(function () {
};
Editor.prototype.didDragPointHandle = function (d, node) {
- var x = d.xScaleInvert(d3.event.x);
- var y = d.yScaleInvert(d3.event.y);
+ var x = this.xScaleZeroInvert(d3.event.x);
+ var y = this.yScaleZeroInvert(d3.event.y);
- if (d.xScale(x) == d.xScale(d.x) && d.yScale(y) == d.yScale(d.y)) {
+ if (this.xScaleZero(x) == this.xScaleZero(d.x) && this.yScaleZero(y) == this.yScaleZero(d.y)) {
return;
}
@@ -390,15 +386,22 @@ jQuery(function () {
handles.enter().append("circle")
.classed("point-handle", true)
.call(d3.drag()
- .subject(function (d) { return { x: d.xScale(d.x), y : d.yScale(d.y) } })
+ .subject(function (d) { return { x: self.xScaleZero(d.x), y : self.yScaleZero(d.y) } })
.on("start", function (d) { self.didBeginDrag(d, this) })
.on("drag", function (d) { self.didDragPointHandle(d) })
.on("end", function (d) { self.didEndDrag(d, this) })
)
.merge(handles)
- .attr("transform", function (d) { return self.inspectorNode._type == 'polygon' ? "translate(" + self.xScale(self.inspectorNode.x) + ", " + self.yScale(self.inspectorNode.y) + ")" : 'translate(0, 20)'})
- .attr("cx", function (d) { return d.xScale(d.x) })
- .attr("cy", function (d) { return d.yScale(d.y) })
+ .attr("transform", function (d) {
+ var x = self.xScale(self.inspectorNode.x);
+ var y = self.yScale(self.inspectorNode.y);
+ if (self.inspectorNode._type == 'line') {
+ y += 20;
+ }
+ return "translate(" + x + ", " + y + ")";
+ })
+ .attr("cx", function (d) { return self.xScaleZero(d.x) })
+ .attr("cy", function (d) { return self.yScaleZero(d.y) })
};
Editor.prototype.clickedStatus = function (d) {
@@ -501,7 +504,8 @@ jQuery(function () {
};
Editor.prototype.addNewLineDecoration = function () {
- var line = this.lifecycle.createLineDecoration();
+ var p = this.viewportCenterPoint();
+ var line = this.lifecycle.createLineDecoration(p[0], p[1]);
this.focusItem(line);
};
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index 4e7a863..28d208d 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -17,6 +17,10 @@ jQuery(function () {
};
Lifecycle.prototype._initialPointsForPolygon = {
+ Line: [
+ {x: -.07, y: 0},
+ {x: .07, y: 0},
+ ],
Triangle: [
{x: .07, y: .2},
{x: 0, y: 0},
@@ -632,7 +636,7 @@ jQuery(function () {
return item;
};
- Lifecycle.prototype.createLineDecoration = function () {
+ Lifecycle.prototype.createLineDecoration = function (x, y) {
this._saveUndoEntry();
var item = {
@@ -642,7 +646,9 @@ jQuery(function () {
style: 'solid',
startMarker: 'none',
endMarker: 'arrowhead',
- points: [{x:0.4, y:0.5}, {x:0.6, y:0.5}]
+ x: x,
+ y: y,
+ points: JSON.parse(JSON.stringify(this._initialPointsForPolygon.Line))
};
this.decorations.line.push(item);
this._keyMap[item._key] = item;
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index 03c87f4..e0364a9 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -277,10 +277,11 @@ jQuery(function () {
.merge(lines)
.classed("dashed", function (d) { return d.style == 'dashed' })
.classed("dotted", function (d) { return d.style == 'dotted' })
- .attr("x1", function (d) { return self.xScale(d.points[0].x) })
- .attr("y1", function (d) { return self.yScale(d.points[0].y) })
- .attr("x2", function (d) { return self.xScale(d.points[1].x) })
- .attr("y2", function (d) { return self.yScale(d.points[1].y) })
+ .attr("transform", function (d) { return "translate(" + self.xScale(d.x) + ", " + self.yScale(d.y) + ")" })
+ .attr("x1", function (d) { return self.xScaleZero(d.points[0].x) })
+ .attr("y1", function (d) { return self.yScaleZero(d.points[0].y) })
+ .attr("x2", function (d) { return self.xScaleZero(d.points[1].x) })
+ .attr("y2", function (d) { return self.yScaleZero(d.points[1].y) })
.classed("focus", function (d) { return self.isFocused(d) })
.attr("marker-start", function (d) { return d.startMarker == 'none' ? undefined : "url(#line_marker_" + d.startMarker + ")" })
.attr("marker-end", function (d) { return d.endMarker == 'none' ? undefined : "url(#line_marker_" + d.endMarker + ")" })
commit 2ba8415e627ed29bf9b275a0b82fa1b35c30b2af
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 18:58:41 2017 +0000
Drag and drop for line decorations
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 1e1e257..59aec0a 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -472,6 +472,10 @@ jQuery(function () {
circles.call(this._createDrag());
};
+ Editor.prototype.didEnterLineDecorations = function (lines) {
+ lines.call(this._createDrag());
+ };
+
Editor.prototype.viewportCenterPoint = function () {
var rect = this.svg.node().getBoundingClientRect();
var x = (rect.width / 2 - this._currentZoom.x)/this._currentZoom.k;
commit 0debf62d56b9b269f69a8175e0ab8e0e2251702d
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 19:01:47 2017 +0000
Adjust domain from 0,1 to 0,10000, and floor() on invert
This should help with floating point accuracy issues
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index 28d208d..862eb83 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -18,19 +18,19 @@ jQuery(function () {
Lifecycle.prototype._initialPointsForPolygon = {
Line: [
- {x: -.07, y: 0},
- {x: .07, y: 0},
+ {x: -700, y: 0},
+ {x: 700, y: 0},
],
Triangle: [
- {x: .07, y: .2},
- {x: 0, y: 0},
- {x: -.06, y: .2}
+ {x: 700, y: 2000},
+ {x: 0, y: 0},
+ {x: -600, y: 2000}
],
Rectangle: [
- {x: -.06, y: -.06},
- {x: .06, y: -.06},
- {x: .06, y: .06},
- {x: -.06, y: .06}
+ {x: -600, y: -600},
+ {x: 600, y: -600},
+ {x: 600, y: 600},
+ {x: -600, y: 600}
]
};
@@ -73,8 +73,8 @@ jQuery(function () {
var meta = self._statusMeta[statusName];
// arrange statuses evenly-spaced around a circle
if (!meta.x) {
- meta.x = (Math.sin(2 * Math.PI * (i/statusCount)) + 1) / 2;
- meta.y = (Math.cos(2 * Math.PI * (i/statusCount)) + 1) / 2;
+ meta.x = 10000 * (Math.sin(2 * Math.PI * (i/statusCount)) + 1) / 2;
+ meta.y = 10000 * (Math.cos(2 * Math.PI * (i/statusCount)) + 1) / 2;
};
if (!meta.color) {
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index e0364a9..a691c1c 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -9,7 +9,7 @@ jQuery(function () {
Viewer.prototype.createScale = function (size, padding) {
return d3.scaleLinear()
- .domain([0, 1])
+ .domain([0, 10000])
.range([padding, size - padding]);
};
@@ -18,10 +18,10 @@ jQuery(function () {
Viewer.prototype.yScale = function (y) { return this.gridScale(this._yScale(y)) };
Viewer.prototype.xScaleZero = function (x) { return this.gridScale(this._xScaleZero(x)) };
Viewer.prototype.yScaleZero = function (y) { return this.gridScale(this._yScaleZero(y)) };
- Viewer.prototype.xScaleInvert = function (x) { return this._xScale.invert(x) };
- Viewer.prototype.yScaleInvert = function (y) { return this._yScale.invert(y) };
- Viewer.prototype.xScaleZeroInvert = function (x) { return this._xScaleZero.invert(x) };
- Viewer.prototype.yScaleZeroInvert = function (y) { return this._yScaleZero.invert(y) };
+ Viewer.prototype.xScaleInvert = function (x) { return Math.floor(this._xScale.invert(x)) };
+ Viewer.prototype.yScaleInvert = function (y) { return Math.floor(this._yScale.invert(y)) };
+ Viewer.prototype.xScaleZeroInvert = function (x) { return Math.floor(this._xScaleZero.invert(x)) };
+ Viewer.prototype.yScaleZeroInvert = function (y) { return Math.floor(this._yScaleZero.invert(y)) };
Viewer.prototype.addZoomBehavior = function () {
var self = this;
commit a90d4b93c03a495ba50cc48e3014c0799d45ccc9
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 19:03:36 2017 +0000
Fix label bounding box not scaling
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 59aec0a..285bd33 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -362,9 +362,9 @@ jQuery(function () {
var rect = d3.select(this);
var label = self.decorationContainer.select("text[data-key='"+d._key+"']");
var bbox = label.node().getBoundingClientRect();
- var width = bbox.width;
- var height = bbox.height;
- var padding = 5;
+ var width = bbox.width / self._currentZoom.k;
+ var height = bbox.height / self._currentZoom.k;
+ var padding = 5 / self._currentZoom.k;
rect.attr("x", self.xScale(d.x)-padding)
.attr("y", self.yScale(d.y)-height-padding)
commit 4f8527c9ee6fa2dbda16398b5ca7c6317fd94bc3
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 19:29:02 2017 +0000
Implement multi-line text decorations
diff --git a/html/Elements/LifecycleInspectorText b/html/Elements/LifecycleInspectorText
index 7c7baae..d36f415 100644
--- a/html/Elements/LifecycleInspectorText
+++ b/html/Elements/LifecycleInspectorText
@@ -1,6 +1,6 @@
<script type="text/x-template" class="lifecycle-inspector-template" data-type="text">
<div class="text">
- Text: <input type="text" name="text" value="{{text.text}}" /><br><br>
+ Text: <textarea name="text" rows=5>{{text.text}}</textarea><br><br>
Bold: <input type="checkbox" name="bold" {{#if text.bold}}checked=checked{{/if}}><br>
Italic: <input type="checkbox" name="italic" {{#if text.italic}}checked=checked{{/if}}><br>
<button class="delete"><&|/l&>Delete Text</&></button>
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 285bd33..b7d01a8 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -367,7 +367,7 @@ jQuery(function () {
var padding = 5 / self._currentZoom.k;
rect.attr("x", self.xScale(d.x)-padding)
- .attr("y", self.yScale(d.y)-height-padding)
+ .attr("y", self.yScale(d.y)-padding)
.attr("width", width+padding*2)
.attr("height", height+padding*2);
});
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index a691c1c..7fce6b4 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -171,6 +171,24 @@ jQuery(function () {
.classed("focus-to", function (d) { return self.isFocusedTransition(d, false) });
};
+ Viewer.prototype._wrapTextDecoration = function (node, text) {
+ if (node.attr('data-text') == text) {
+ return;
+ }
+
+ var lines = text.split(/\n/),
+ lineHeight = 1.1;
+
+ if (node.attr('data-text')) {
+ node.selectAll("*").remove();
+ }
+ node.attr('data-text', text);
+
+ for (var i = 0; i < lines.length; ++i) {
+ node.append("tspan").attr("dy", (i+1) * lineHeight + "em").text(lines[i]);
+ }
+ };
+
Viewer.prototype.renderTextDecorations = function (initial) {
var self = this;
var labels = self.decorationContainer.selectAll("text")
@@ -191,10 +209,13 @@ jQuery(function () {
.merge(labels)
.attr("x", function (d) { return self.xScale(d.x) })
.attr("y", function (d) { return self.yScale(d.y) })
- .text(function (d) { return d.text })
.classed("bold", function (d) { return d.bold })
.classed("italic", function (d) { return d.italic })
.classed("focus", function (d) { return self.isFocused(d) })
+ .each(function (d) { self._wrapTextDecoration(d3.select(this), d.text) })
+ .selectAll("tspan")
+ .attr("x", function (d) { return self.xScale(d.x) })
+ .attr("y", function (d) { return self.yScale(d.y) })
};
Viewer.prototype.renderPolygonDecorations = function (initial) {
commit 8dabf9ca82d8cc2c8c44e737eec2b11cde559200
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 19:40:02 2017 +0000
Use a consistent padding across editor and viewer
This is important because gridSize can cause a jump in position
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index b7d01a8..cd0c480 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -3,7 +3,6 @@ jQuery(function () {
function Editor (container) {
Super.call(this);
- this.padding = this.statusCircleRadius * 2;
};
Editor.prototype = Object.create(Super.prototype);
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index 7fce6b4..5e07ab7 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -4,7 +4,7 @@ jQuery(function () {
this.height = 500;
this.statusCircleRadius = 35;
this.gridSize = 10;
- this.padding = this.statusCircleRadius;
+ this.padding = this.statusCircleRadius * 2;
};
Viewer.prototype.createScale = function (size, padding) {
commit f54ebb71151b05d0be77330bfb344686dae04a2c
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 19:47:26 2017 +0000
Zoom out on ticket display
diff --git a/static/js/lifecycleui-viewer.js b/static/js/lifecycleui-viewer.js
index 5e07ab7..1b60a60 100644
--- a/static/js/lifecycleui-viewer.js
+++ b/static/js/lifecycleui-viewer.js
@@ -324,9 +324,10 @@ jQuery(function () {
Viewer.prototype.centerOnItem = function (item, animated) {
var rect = this.svg.node().getBoundingClientRect();
- var x = rect.width/2 - this.xScale(item.x);
- var y = rect.height/2 - this.yScale(item.y);
- this._zoomIdentity = d3.zoomIdentity.translate(x, y);
+ var scale = this._zoomIdentityScale;
+ var x = rect.width/2 - this.xScale(item.x) * scale;
+ var y = rect.height/2 - this.yScale(item.y) * scale;
+ this._zoomIdentity = d3.zoomIdentity.translate(x, y).scale(this._zoomIdentityScale);
this.resetZoom(animated);
};
@@ -416,7 +417,13 @@ jQuery(function () {
self._yScale = self.createScale(self.height, self.padding);
self._xScaleZero = self.createScale(self.width, 0);
self._yScaleZero = self.createScale(self.height, 0);
- self._zoomIdentity = self._currentZoom = d3.zoomIdentity;
+
+ // zoom in a bit, but not too much
+ var scale = self.svg.node().getBoundingClientRect().width / self.width;
+ scale = scale ** .6;
+
+ self._zoomIdentityScale = scale;
+ self._zoomIdentity = self._currentZoom = d3.zoomIdentity.scale(self._zoomIdentityScale);
self.lifecycle = new RT.Lifecycle(name);
self.lifecycle.initializeFromConfig(config);
commit 5b7636420ac1c9558de6d1f325ff0a6d00688f58
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 20:04:55 2017 +0000
Re-implement create lifecycle page
diff --git a/html/Admin/Lifecycles/Create.html b/html/Admin/Lifecycles/Create.html
index 097abcd..802b782 100644
--- a/html/Admin/Lifecycles/Create.html
+++ b/html/Admin/Lifecycles/Create.html
@@ -1,23 +1,36 @@
<& /Admin/Elements/Header, Title => loc("Admin Lifecycles") &>
<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
<form action="<%RT->Config->Get('WebPath')%>/Admin/Lifecycles/Create.html" name="CreateLifecycle" method="post" enctype="multipart/form-data">
-<&|/l&>New lifecycle name</&>: <input name="Name" value="" />
-<hr />
+<table>
+<tr><td align="right"><&|/l&>Lifecycle Name</&>:</td>
+<td><input name="Name" value="<% $Name %>" /></td>
+</tr>
+<tr><td align="right"><&|/l&>Type</&>:</td>
+<td><select name="Type">
% for my $type (@types) {
-% my @lifecycles = @{ $lifecycles{$type} };
-<h2><&|/l, $type&>"[_1]" lifecycles</&></h2>
-% for my $lifecycle (@lifecycles) {
-<button type="submit" name="Clone" value="<% $type %>--<% $lifecycle %>"><&|/l, $lifecycle&>Clone "[_1]" lifecycle</&></button><br>
+<option value="<% $type %>" <% $type eq $Type ? "checked=checked" : "" %>><% loc($type) %></option>
% }
-<br>
-<button type="submit" name="Blank" value="<% $type %>"><&|/l, $type&>Blank "[_1]" lifecycle</&></button><br>
+</select></td></tr>
+
+<tr><td align="right"><&|/l&>Clone Lifecycle</&>:</td><td>
+<label><input type="radio" name="Clone" value="" <% ($Clone//'') eq '' ? "checked=checked" : "" %> /> (none)</label>
+
+% for my $type (@types) {
+% for my $lifecycle (@{ $lifecycles{$type} }) {
+<label><input type="radio" name="Clone" value="<% $lifecycle %>" <% ($Clone//'') eq $lifecycle ? "checked=checked" : "" %> /> <% $lifecycle %></label><br>
% }
-</form>
+% }
+</td></tr>
+</table>
+<& /Elements/Submit, Name => 'Create', Label => loc('Create') &>
<%INIT>
+my @results;
+
my @types = List::MoreUtils::uniq(
'ticket',
'asset',
@@ -32,34 +45,29 @@ for my $type (@types) {
RT::Lifecycle->ListAll($type);
}
-if (defined($Clone) || defined($Blank)) {
- my ($type, $clone_of);
-
- if (defined($Clone)) {
- ($type, $clone_of) = split '--', $Clone;
- }
- else {
- $type = $Blank;
- }
-
+if ($Create) {
my ($ok, $msg) = RT::Extension::LifecycleUI->CreateLifecycle(
CurrentUser => $session{CurrentUser},
Name => $Name,
- Type => $type,
- Clone => $clone_of,
+ Type => $Type,
+ Clone => $Clone,
);
- Abort($msg) if !$ok;
-
- MaybeRedirectForResults(
- Actions => [ $msg ],
- Path => 'Admin/Lifecycles/Modify.html',
- Arguments => { Type => $type, Name => $Name },
- );
+ if ($ok) {
+ MaybeRedirectForResults(
+ Actions => [ $msg ],
+ Path => 'Admin/Lifecycles/Modify.html',
+ Arguments => { Type => $Type, Name => $Name },
+ );
+ }
+ else {
+ push @results, $msg if !$ok;
+ }
}
</%INIT>
<%ARGS>
-$Clone => undef
-$Blank => undef
$Name => undef
+$Type => 'ticket'
+$Clone => undef
+$Create => undef
</%ARGS>
commit 6437939ec363baeb225c34a659bcdd32424c3b7c
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 20:12:40 2017 +0000
<option> uses selected not checked
diff --git a/html/Admin/Lifecycles/Create.html b/html/Admin/Lifecycles/Create.html
index 802b782..7f73e87 100644
--- a/html/Admin/Lifecycles/Create.html
+++ b/html/Admin/Lifecycles/Create.html
@@ -12,7 +12,7 @@
<tr><td align="right"><&|/l&>Type</&>:</td>
<td><select name="Type">
% for my $type (@types) {
-<option value="<% $type %>" <% $type eq $Type ? "checked=checked" : "" %>><% loc($type) %></option>
+<option value="<% $type %>" <% $type eq $Type ? "selected=selected" : "" %>><% loc($type) %></option>
% }
</select></td></tr>
commit f74fb3355daf56e5938d8e973f3b7e193a7ae991
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 20:12:49 2017 +0000
Show/hide lifecycles based on type dropdown
diff --git a/html/Admin/Lifecycles/Create.html b/html/Admin/Lifecycles/Create.html
index 7f73e87..b2d25a5 100644
--- a/html/Admin/Lifecycles/Create.html
+++ b/html/Admin/Lifecycles/Create.html
@@ -20,14 +20,31 @@
<label><input type="radio" name="Clone" value="" <% ($Clone//'') eq '' ? "checked=checked" : "" %> /> (none)</label>
% for my $type (@types) {
+<div class="type" data-type="<% $type %>">
% for my $lifecycle (@{ $lifecycles{$type} }) {
<label><input type="radio" name="Clone" value="<% $lifecycle %>" <% ($Clone//'') eq $lifecycle ? "checked=checked" : "" %> /> <% $lifecycle %></label><br>
% }
+</div>
% }
</td></tr>
</table>
<& /Elements/Submit, Name => 'Create', Label => loc('Create') &>
+
+<script type="text/javascript">
+jQuery(function () {
+ var showType = function (resetClone) {
+ var type = jQuery('select[name=Type]').val();
+ jQuery('.type').hide();
+ jQuery('.type[data-type="'+type+'"]').show();
+ if (resetClone) {
+ jQuery('input[name=Clone][value=""]').prop('checked', true);
+ }
+ };
+ showType(false);
+ jQuery('select[name=Type]').change(function () { showType(true) });
+});
+</script>
<%INIT>
my @results;
commit eccbfb727d04f9f206b77665d31bccabf34a22bb
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 20:47:52 2017 +0000
Hover focus on status we're adding transition to
diff --git a/static/css/lifecycleui-editor.css b/static/css/lifecycleui-editor.css
index ac972a0..08393a9 100644
--- a/static/css/lifecycleui-editor.css
+++ b/static/css/lifecycleui-editor.css
@@ -121,6 +121,10 @@
left: 175px;
}
+.lifecycle-ui .statuses text.hover {
+ opacity: 1;
+}
+
.lifecycle-ui .statuses circle.hover,
.lifecycle-ui .transitions .hover,
.lifecycle-ui .decorations :not(text).hover {
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index cd0c480..85411cc 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -195,6 +195,12 @@ jQuery(function () {
self.hoverItem(d);
});
+ inspector.on('mouseenter', 'a.add-transition', function (e) {
+ var statusName = jQuery(this).data('to');
+ var d = self.lifecycle.statusObjectForName(statusName);
+ self.hoverItem(d);
+ });
+
inspector.on('click', 'a.select-transition', function (e) {
e.preventDefault();
var button = jQuery(this);
@@ -227,7 +233,7 @@ jQuery(function () {
self.hoverItem(d);
});
- inspector.on('mouseleave', 'a.select-status, a.select-transition, a.select-decoration', function () {
+ inspector.on('mouseleave', 'a.select-status, a.add-transition, a.select-transition, a.select-decoration', function () {
self.hoverItem(null);
});
commit 2e82183c182e9d6be205c20db02488cf0e5cabfa
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 21:19:53 2017 +0000
Rename Text to Label in the UI
diff --git a/html/Elements/LifecycleInspectorCanvas b/html/Elements/LifecycleInspectorCanvas
index 602e702..1c54de7 100644
--- a/html/Elements/LifecycleInspectorCanvas
+++ b/html/Elements/LifecycleInspectorCanvas
@@ -64,7 +64,7 @@
<li><a href="javascript:void(0)" class="menu-item add-status"><&|/l&>Add Status</&></a></li>
<li class="has-children"><a href="javascript:void(0)" class="menu-item">Add Decoration...</a>
<ul>
- <li><a href="javascript:void(0)" class="menu-item add-text">Add Text</a></li>
+ <li><a href="javascript:void(0)" class="menu-item add-text">Add Label</a></li>
<li><a href="javascript:void(0)" class="menu-item add-polygon" data-type="Triangle">Add Triangle</a></li>
<li><a href="javascript:void(0)" class="menu-item add-polygon" data-type="Rectangle">Add Rectangle</a></li>
<li><a href="javascript:void(0)" class="menu-item add-circle">Add Circle</a></li>
diff --git a/html/Elements/LifecycleInspectorText b/html/Elements/LifecycleInspectorText
index d36f415..27e40b0 100644
--- a/html/Elements/LifecycleInspectorText
+++ b/html/Elements/LifecycleInspectorText
@@ -3,6 +3,6 @@
Text: <textarea name="text" rows=5>{{text.text}}</textarea><br><br>
Bold: <input type="checkbox" name="bold" {{#if text.bold}}checked=checked{{/if}}><br>
Italic: <input type="checkbox" name="italic" {{#if text.italic}}checked=checked{{/if}}><br>
- <button class="delete"><&|/l&>Delete Text</&></button>
+ <button class="delete"><&|/l&>Delete Label</&></button>
</div>
</script>
commit 5b4e82c8955f5d5d8186bdd61dce7916bf2992ae
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 21:24:34 2017 +0000
Automatically clear label placeholder text
diff --git a/html/Elements/LifecycleInspectorText b/html/Elements/LifecycleInspectorText
index 27e40b0..4481cd6 100644
--- a/html/Elements/LifecycleInspectorText
+++ b/html/Elements/LifecycleInspectorText
@@ -1,6 +1,6 @@
<script type="text/x-template" class="lifecycle-inspector-template" data-type="text">
<div class="text">
- Text: <textarea name="text" rows=5>{{text.text}}</textarea><br><br>
+ Text: <textarea name="text" rows=5 data-default="New label">{{text.text}}</textarea><br><br>
Bold: <input type="checkbox" name="bold" {{#if text.bold}}checked=checked{{/if}}><br>
Italic: <input type="checkbox" name="italic" {{#if text.italic}}checked=checked{{/if}}><br>
<button class="delete"><&|/l&>Delete Label</&></button>
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 85411cc..5a92bd1 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -289,6 +289,12 @@ jQuery(function () {
self.defocus();
}
});
+
+ inspector.on('focus', 'textarea[name=text]', function (e) {
+ if (jQuery(this).val() == jQuery(this).data('default')) {
+ jQuery(this).val("");
+ }
+ });
};
Editor.prototype.addPointHandles = function (d) {
commit 2286fdfe95e1c06f54c8ead1422c8f9f73510a04
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 21:29:43 2017 +0000
Implement cloning for decorations
diff --git a/html/Elements/LifecycleInspectorCircle b/html/Elements/LifecycleInspectorCircle
index b435af1..72f0cfe 100644
--- a/html/Elements/LifecycleInspectorCircle
+++ b/html/Elements/LifecycleInspectorCircle
@@ -11,6 +11,7 @@
</select>
</div>
Fill: <input type="checkbox" name="renderFill" {{#if circle.renderFill}}checked=checked{{/if}} data-show-hide=".color-control[data-field=fill]"> <span class="color-control" data-field="fill"><span class="current-color" title="{{circle.fill}}" style="background-color: {{circle.fill}}"> </span> <button class="change-color"><&|/l&>Change</&></button></span><br>
+ <button class="clone"><&|/l&>Clone Circle</&></button><br>
<button class="delete"><&|/l&>Delete Circle</&></button>
</div>
</script>
diff --git a/html/Elements/LifecycleInspectorLine b/html/Elements/LifecycleInspectorLine
index 076cbc9..9a66c56 100644
--- a/html/Elements/LifecycleInspectorLine
+++ b/html/Elements/LifecycleInspectorLine
@@ -22,6 +22,7 @@
<option value="dotted"><&|/l&>dotted</&></option>
{{/select}}
</select><br>
+ <button class="clone"><&|/l&>Clone Line</&></button><br>
<button class="delete"><&|/l&>Delete Line</&></button>
</div>
</script>
diff --git a/html/Elements/LifecycleInspectorPolygon b/html/Elements/LifecycleInspectorPolygon
index bcc99dc..3d9c054 100644
--- a/html/Elements/LifecycleInspectorPolygon
+++ b/html/Elements/LifecycleInspectorPolygon
@@ -11,6 +11,7 @@
</select>
</div>
Fill: <input type="checkbox" name="renderFill" {{#if polygon.renderFill}}checked=checked{{/if}} data-show-hide=".color-control[data-field=fill]"> <span class="color-control" data-field="fill"><span class="current-color" title="{{polygon.fill}}" style="background-color: {{polygon.fill}}"> </span> <button class="change-color"><&|/l&>Change</&></button></span><br>
+ <button class="clone"><&|/l&>Clone Polygon</&></button><br>
<button class="delete"><&|/l&>Delete Polygon</&></button>
</div>
</script>
diff --git a/html/Elements/LifecycleInspectorText b/html/Elements/LifecycleInspectorText
index 4481cd6..652dba3 100644
--- a/html/Elements/LifecycleInspectorText
+++ b/html/Elements/LifecycleInspectorText
@@ -3,6 +3,7 @@
Text: <textarea name="text" rows=5 data-default="New label">{{text.text}}</textarea><br><br>
Bold: <input type="checkbox" name="bold" {{#if text.bold}}checked=checked{{/if}}><br>
Italic: <input type="checkbox" name="italic" {{#if text.italic}}checked=checked{{/if}}><br>
+ <button class="clone"><&|/l&>Clone Label</&></button><br>
<button class="delete"><&|/l&>Delete Label</&></button>
</div>
</script>
diff --git a/static/js/lifecycleui-editor.js b/static/js/lifecycleui-editor.js
index 5a92bd1..e25951a 100644
--- a/static/js/lifecycleui-editor.js
+++ b/static/js/lifecycleui-editor.js
@@ -156,6 +156,13 @@ jQuery(function () {
}
});
+ inspector.on('click', 'button.clone', function (e) {
+ e.preventDefault();
+ var p = self.viewportCenterPoint();
+ var clone = self.lifecycle.cloneItem(self.inspectorNode, p[0], p[1]);
+ self.focusItem(clone);
+ });
+
inspector.on('click', 'button.add-action', function (e) {
e.preventDefault();
var action = lifecycle.createActionForTransition(self.inspectorNode);
@@ -514,7 +521,7 @@ jQuery(function () {
Editor.prototype.addNewCircleDecoration = function () {
var p = this.viewportCenterPoint();
- var circle = this.lifecycle.createCircleDecoration(p[0], p[1], self.statusCircleRadius);
+ var circle = this.lifecycle.createCircleDecoration(p[0], p[1], this.statusCircleRadius);
this.focusItem(circle);
};
diff --git a/static/js/lifecycleui-model.js b/static/js/lifecycleui-model.js
index 862eb83..47e37b9 100644
--- a/static/js/lifecycleui-model.js
+++ b/static/js/lifecycleui-model.js
@@ -776,6 +776,25 @@ jQuery(function () {
return frame;
};
+ Lifecycle.prototype.cloneItem = function (source, x, y) {
+ this._saveUndoEntry();
+
+ var clone = JSON.parse(JSON.stringify(source));
+ clone._key = _ELEMENT_KEY_SEQ++;
+ clone.x = x;
+ clone.y = y;
+
+ if (clone._type == 'polygon' || clone._type == 'circle' || clone._type == 'line' || clone._type == 'text') {
+ this.decorations[clone._type].push(clone);
+ }
+ else {
+ console.error("Unhandled type for clone: " + clone._type);
+ }
+
+ this._keyMap[clone._key] = clone;
+ return clone;
+ };
+
RT.Lifecycle = Lifecycle;
});
commit 8a4a824c8e8e9e81913d52565ba9953fb0352d80
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Sep 8 21:53:22 2017 +0000
0.01 releng
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..2f17a61
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,47 @@
+html/Admin/Lifecycles/Create.html
+html/Admin/Lifecycles/index.html
+html/Admin/Lifecycles/Mappings.html
+html/Admin/Lifecycles/Modify.html
+html/Callbacks/RT-Extension-LifecycleUI/Elements/Tabs/Privileged
+html/Callbacks/RT-Extension-LifecycleUI/Ticket/Elements/ShowSummary/AfterReminders
+html/Elements/LifecycleGraph
+html/Elements/LifecycleGraphExtras
+html/Elements/LifecycleInspector
+html/Elements/LifecycleInspectorAction
+html/Elements/LifecycleInspectorCanvas
+html/Elements/LifecycleInspectorCircle
+html/Elements/LifecycleInspectorLine
+html/Elements/LifecycleInspectorPolygon
+html/Elements/LifecycleInspectorStatus
+html/Elements/LifecycleInspectorText
+html/Elements/LifecycleInspectorTransition
+html/Elements/LifecycleInteractive
+inc/Module/Install.pm
+inc/Module/Install/Base.pm
+inc/Module/Install/Can.pm
+inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
+inc/Module/Install/Makefile.pm
+inc/Module/Install/Metadata.pm
+inc/Module/Install/ReadmeFromPod.pm
+inc/Module/Install/RTx.pm
+inc/Module/Install/RTx/Runtime.pm
+inc/Module/Install/Win32.pm
+inc/Module/Install/WriteAll.pm
+inc/unicore/Name.pm
+inc/YAML/Tiny.pm
+lib/RT/Extension/LifecycleUI.pm
+Makefile.PL
+MANIFEST This list of files
+META.yml
+README
+static/css/lifecycleui-editor.css
+static/css/lifecycleui-viewer-interactive.css
+static/css/lifecycleui-viewer.css
+static/css/lifecycleui.css
+static/js/d3.min.js
+static/js/handlebars-4.0.6.min.js
+static/js/lifecycleui-editor.js
+static/js/lifecycleui-model.js
+static/js/lifecycleui-viewer-interactive.js
+static/js/lifecycleui-viewer.js
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list