Skip to content

Commit

Permalink
highlighting fields on link hover, some help bug fixes and minor impr…
Browse files Browse the repository at this point in the history
…ovements
  • Loading branch information
nikitaeverywhere committed Oct 31, 2015
1 parent f5ca4ca commit d78c224
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 124 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ An UML Class explorer for InterSystems Caché.
+ Export diagrams as an image;
+ See Class methods, properties, parameters, SQL queries and more;
+ See any keywords and related information by hovering over everything with pointer;
+ Check which fields are connected by hovering over link;
+ View class methods code with syntax highlighting;
+ Zoom in and out;
+ Search on diagram or in class tree;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "CacheClassExplorer",
"version": "1.9",
"version": "1.10.4",
"description": "Class Explorer for InterSystems Caché",
"directories": {
"test": "test"
Expand Down
9 changes: 9 additions & 0 deletions web/css/classView.css
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ text {
fill: red;
}

.line-selected {
fill: red;
text-shadow: 0 1px 3px #CCC;
-webkit-transition: all .2s ease;
-moz-transition: all .2s ease;
-o-transition: all .2s ease;
transition: all .2s ease;
}

.inlineSearchBlock {
display: inline-block;
vertical-align: bottom;
Expand Down
63 changes: 31 additions & 32 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,21 +159,36 @@ <h2>Caché Class Explorer Help</h2>
<td>
<div name="injector">{
"classes": { "Registered": { } }
}</div>
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Persistent": { "ClassType": "persistent" } }
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Serial": { "ClassType": "serial" } }
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Data Type": { "ClassType": "datatype" } }
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Persistent": { "ClassType": "Persistent" } }
"classes": { "Index": { "ClassType": "index" } }
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Serial": { "ClassType": "Serial" } }
"classes": { "View": { "ClassType": "view" } }
}</div>
</td>
<td>
<div name="injector">{
"classes": { "Data Type": { "ClassType": "DataType" } }
"classes": { "Stream": { "ClassType": "stream" } }
}</div>
</td>
</tr>
Expand All @@ -185,13 +200,13 @@ <h2>Caché Class Explorer Help</h2>
<th colspan="2" class="leftAligned"><h2>Connection Types</h2></th>
</tr>
<tr>
<th class="leftAligned">Association</th>
<th class="leftAligned">Class Mention</th>
<td>
<div name="injector">{
"layoutDirection": "LR",
"classes": {
"Class A": { "properties": { "Property": { "Type": "Class B" } } },
"Class B": { "ClassType": "Persistent" }
"Class B": { "ClassType": "persistent" }
}
}</div>
</td>
Expand All @@ -202,8 +217,8 @@ <h2>Caché Class Explorer Help</h2>
<div name="injector">{
"layoutDirection": "LR",
"classes": {
"Class A": { "ClassType": "Persistent", "properties": { "Property": { "Cardinality": "one", "Type": "Class B" } } },
"Class B": { "ClassType": "Persistent", "properties": { "Property": { "Cardinality": "many", "Type": "Class A" } } }
"Class A": { "ClassType": "persistent", "properties": { "Property": { "Cardinality": "one", "Type": "Class B", "Inverse": "Property" } } },
"Class B": { "ClassType": "persistent", "properties": { "Property": { "Cardinality": "many", "Type": "Class A", "Inverse": "Property" } } }
}
}</div>
</td>
Expand All @@ -214,8 +229,8 @@ <h2>Caché Class Explorer Help</h2>
<div name="injector">{
"layoutDirection": "LR",
"classes": {
"Class B": { "ClassType": "Persistent", "properties": { "Property": { "Cardinality": "child", "Type": "Class A" } } },
"Class A": { "ClassType": "Persistent", "properties": { "Property": { "Cardinality": "parent", "Type": "Class B" } } }
"Class B": { "ClassType": "persistent", "properties": { "Property": { "Cardinality": "child", "Type": "Class A", "Inverse": "Property" } } },
"Class A": { "ClassType": "persistent", "properties": { "Property": { "Cardinality": "parent", "Type": "Class B", "Inverse": "Property" } } }
}
}</div>
</td>
Expand All @@ -226,8 +241,8 @@ <h2>Caché Class Explorer Help</h2>
<div name="injector">{
"layoutDirection": "LR",
"classes": {
"Derived Class": { "ClassType": "Persistent", "Super": "Inherited Class", "properties": { "Property": { "Type": "Nothing" } } },
"Inherited Class": { "ClassType": "DataType", "properties": { "Property": { "Type": "Nothing" } } }
"Derived Class": { "ClassType": "datatype", "Super": "Inherited Class", "properties": { "Property": { "Type": "Nothing" } } },
"Inherited Class": { "ClassType": "datatype", "properties": { "Property": { "Type": "Nothing" } } }
}
}</div>
</td>
Expand All @@ -253,7 +268,6 @@ <h2>Icons Description</h2>
<tr><td name="icon">earth</td><td>WEB Method</td></tr>
<tr><td name="icon">zed</td><td>ZEN Method</td></tr>
<tr><td name="icon">eye</td><td>Read Only</td></tr>

</table>
</div>
</div>
Expand All @@ -267,25 +281,10 @@ <h2>Icons Description</h2>
to get additional information. Non-hoverable elements are usually those which
does not have any keywords or comments defined.
</p>
<script>
var cont = [].slice.call(document.querySelectorAll("#helpView *[name=injector]")),
cont2 = [].slice.call(document.querySelectorAll("#helpView *[name=icon]")), i;
for (i in cont) {
var ue, json = {
classes: { "Unable to parse JSON": { } }
};
try { json = JSON.parse(cont[i].textContent) } catch (e) { }
cont[i].textContent = "";
ue = new CacheClassExplorer(null, cont[i]);
ue.classView.injectView(json);
}
for (i in cont2) {
var ico = lib.image[cont2[i].textContent];
if (ico) {
cont2[i].innerHTML = "<img src=\"" + ico + "\"/>"
}
}
</script>
<p>
All links except inheritance are <b>hoverable</b> too. Hovering over links will
highlight appropriate fields in linked classes.
</p>
</div>
</div>
</div>
Expand Down
27 changes: 27 additions & 0 deletions web/js/CacheClassExplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ var CacheClassExplorer = function (treeViewContainer, classViewContainer) {
}
this.classView = new ClassView(this, classViewContainer);
this.NAMESPACE = null;
this.HELP_INITIALIZED = false;

if (treeViewContainer) {
this.initSettings();
Expand Down Expand Up @@ -177,6 +178,31 @@ CacheClassExplorer.prototype.restoreFromURL = function () {

};

CacheClassExplorer.prototype.initHelp = function () {

if (this.HELP_INITIALIZED) return;
this.HELP_INITIALIZED = true;

var cont = [].slice.call(document.querySelectorAll("#helpView *[name=injector]")),
cont2 = [].slice.call(document.querySelectorAll("#helpView *[name=icon]")), i;
for (i in cont) {
var ue, json = {
classes: { "Unable to parse JSON": { } }
};
try { json = JSON.parse(cont[i].textContent) } catch (e) { }
cont[i].textContent = "";
ue = new CacheClassExplorer(null, cont[i]);
ue.classView.injectView(json);
}
for (i in cont2) {
var ico = lib.image[cont2[i].textContent];
if (ico) {
cont2[i].innerHTML = "<img src=\"" + ico + "\"/>"
}
}

};

CacheClassExplorer.prototype.init = function () {

var self = this,
Expand Down Expand Up @@ -214,6 +240,7 @@ CacheClassExplorer.prototype.init = function () {
}
});
this.elements.helpButton.addEventListener("click", function () {
self.initHelp();
self.elements.helpView.classList.add("active");
});
this.elements.closeHelp.addEventListener("click", function () {
Expand Down
75 changes: 70 additions & 5 deletions web/js/ClassView.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ ClassView.prototype.getPropertyHoverText = function (prop, type) {
: "<span class=\"syntax-keyword\">SoapAction</span>="
+ "<span class=\"syntax-string\">" + data + "</span>";
},
"Default": function (data) {
return "Default = " + lib.highlightCOS(data + "");
},
"SqlProc": 1,
"WebMethod": 1,
"ZenMethod": 1,
Expand Down Expand Up @@ -412,7 +415,7 @@ ClassView.prototype.getPropertyHoverText = function (prop, type) {

var txt = [], val;
for (i in prop) {
if (propText[i] && (prop[i] || i === "InitialExpression" || i === "ProcedureBlock")) {
if (propText[i] && (prop[i] || i === "InitialExpression" || i === "ProcedureBlock" || i === "Default")) {
val = propText[i] === 1
? "<span class=\"syntax-keyword\">" + i + "</span>"
: propText[i](prop[i], prop);
Expand Down Expand Up @@ -466,6 +469,7 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in params) {
keyWordsArray.push(n);
arr.push({
name: n,
text: n + (params[n]["Type"] ? ": " + params[n]["Type"] : ""),
hover: self.getPropertyHoverText(params[n], "parameter"),
icons: self.getPropertyIcons(params[n])
Expand All @@ -478,6 +482,7 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in ps) {
keyWordsArray.push(n);
arr.push({
name: n,
text: n + (ps[n]["Type"] ? ": " + ps[n]["Type"] : ""),
hover: self.getPropertyHoverText(ps[n], "property"),
icons: self.getPropertyIcons(ps[n])
Expand All @@ -490,6 +495,7 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in met) {
keyWordsArray.push(n);
arr.push({
name: n,
text: n + (met[n]["ReturnType"] ? ": " + met[n]["ReturnType"] : ""),
styles: (function (t) {
return t ? { textDecoration: "underline" } : {}
Expand All @@ -508,7 +514,8 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in qrs) {
keyWordsArray.push(n);
arr.push({
text: n,
name: n,
text: n + (qrs[n]["Type"] ? ": " + qrs[n]["Type"] : ""),
icons: self.getPropertyIcons(qrs[n]),
hover: self.getPropertyHoverText(qrs[n], "query"),
clickHandler: (function (q, className) {
Expand All @@ -519,7 +526,7 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
return arr;
})(classQueries),
classSigns: this.getClassSigns(classMetaData),
classType: classMetaData.$classType,
classType: classMetaData.ClassType || "registered",
SYMBOL_12_WIDTH: self.SYMBOL_12_WIDTH
});

Expand Down Expand Up @@ -678,7 +685,8 @@ ClassView.prototype.confirmRender = function (data) {
var link = function (type) {
var name = type === "inheritance" ? "Generalization" :
type === "aggregation" ? "Aggregation" : type === "composition" ? "Composition"
: "Association";
: "Association",
linkData;
for (p in data[type]) {
relFrom = (classes[p] || {}).instance;
for (pp in data[type][p]) {
Expand Down Expand Up @@ -714,8 +722,16 @@ ClassView.prototype.confirmRender = function (data) {
if (link.left) arr.push(getLabel(link.left, LINK_TEXT_MARGIN));
if (link.right) arr.push(getLabel(link.right, -LINK_TEXT_MARGIN));
return arr;
})(data[type][p][pp] || {})
})(linkData = data[type][p][pp] || {})
}));
if (linkData.from) {
connector._fromClass = linkData.from;
connector._fromClass.instance = relTo;
}
if (linkData.to) {
connector._toClass = linkData.to;
connector._toClass.instance = relFrom;
}
self.links.push(connector);
}
}
Expand Down Expand Up @@ -893,6 +909,53 @@ ClassView.prototype.searchOnDiagram = function (text) {

};

ClassView.prototype.bindLinkHighlight = function () {

var self = this,
highlighted = false,
fields = [];

var freeFields = function () {
fields.forEach(function (f) {
if (f.classList) f.classList.remove("line-selected");
});
fields = [];
};

this.paper.on("cell:mouseover", function (e) {
var link, view, el;
freeFields();
link = e.model || null;
if (!link) return;
if (link._fromClass && link._fromClass.instance && link._fromClass.in
&& (view = self.paper.findViewByModel(link._fromClass.instance))
&& view.el && view.el._LINE_ELEMENTS && view.el._LINE_ELEMENTS[link._fromClass.in]
&& (el = view.el._LINE_ELEMENTS[link._fromClass.in][link._fromClass.name])) {
fields.push(el);
}
if (link._toClass && link._toClass.instance && link._toClass.in
&& (view = self.paper.findViewByModel(link._toClass.instance))
&& view.el && view.el._LINE_ELEMENTS && view.el._LINE_ELEMENTS[link._toClass.in]
&& (el = view.el._LINE_ELEMENTS[link._toClass.in][link._toClass.name])) {
fields.push(el);
}
fields.forEach(function (f) {
if (f.classList) {
f.classList.add("line-selected");
} else {
console.warn("Your browser does not support CSS3 classList property.");
}
});
highlighted = !!fields.length;
});

this.paper.on("cell:mouseout", function (e) {
highlighted = false;
freeFields();
});

};

ClassView.prototype.init = function () {

var p, self = this,
Expand All @@ -912,6 +975,8 @@ ClassView.prototype.init = function () {
}
});

this.bindLinkHighlight();

// enables links re-routing when dragging objects
this.graph.on("change:position", function (object) {
if (_.contains(self.objects, object))
Expand Down
Loading

0 comments on commit d78c224

Please sign in to comment.