Skip to content

Commit c04020a

Browse files
Deleting properties, toast messages add
1 parent faf3b1f commit c04020a

File tree

9 files changed

+222
-14
lines changed

9 files changed

+222
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "cache-visual-editor",
33
"printableName": "Cache Visual Editor",
4-
"version": "0.4.7",
4+
"version": "0.4.9",
55
"description": "Visual class editor for InterSystems Caché",
66
"main": "index.js",
77
"keywords": [

source/cache/VisualEditor.REST.Editor.cls

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,23 @@ ClassMethod Save() As %Status
4848
continue
4949
}
5050

51-
// iterate over properties defined
5251
set props = properties(propertyName)
53-
for j=1:1:propDefs.Count() {
54-
set pname = propDefs.GetAt(j).Name
55-
if ($data(props.%data(pname))) {
56-
set $PROPERTY(pDef, pname) = $PROPERTY(props, pname)
52+
set deleted = 0
53+
if ($data(props.%data("$delete"))) {
54+
set error = $System.Status.GetErrorText(pDef.%Delete(pDef.%Oid()))
55+
set deleted = 1
56+
} else { // iterate over properties defined
57+
for j=1:1:propDefs.Count() {
58+
set pname = propDefs.GetAt(j).Name
59+
if ($data(props.%data(pname))) {
60+
set $PROPERTY(pDef, pname) = $PROPERTY(props, pname)
61+
}
5762
}
5863
}
5964

60-
set error = $System.Status.GetErrorText(pDef.%Save())
65+
if ('deleted) {
66+
set error = $System.Status.GetErrorText(pDef.%Save())
67+
}
6168
if (error '= "") {
6269
set errorLog = errorLog _ error _ $Char(10)
6370
} else {

source/client/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
<div class="page" id="classBuilder">
1818
<div class="header">
1919
<div class="panel">
20+
<div class="medium save icon" id="saveIndicator"></div>
2021
<div class="interactive medium menu icon"></div>
2122
<div class="interactive medium back icon" id="backButton"></div>
2223
<span class="title">
2324
<select id="topNamespace" class="topNamespace">
2425
<option>Loading...</option>
2526
</select><span id="topTitle"></span>
2627
</span>
27-
<div class="medium save icon" id="saveIndicator"></div>
2828
</div>
2929
</div>
3030
<div class="body" id="classBuilderBody">

source/client/js/classEditor/card/item.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { block, insertAfter, clearSelection, prepend } from "../../domUtils";
1+
import { block, insertAfter, clearSelection, prepend, detach } from "../../domUtils";
22
import { updateGrid } from "../index";
33
import { addChange } from "../changes";
4+
import { Toast } from "../../toast";
45

56
let MANIFEST = {
67
Class: {
@@ -310,7 +311,10 @@ export function enableItem ({headerElement, classData, classBlockName, classBloc
310311

311312
let isClass = !classBlockName,
312313
opened = false,
313-
container, controls;
314+
container, controls,
315+
savePath = isClass
316+
? [classData["Name"]]
317+
: [classData["Name"], classBlockName, classBlockPropName];
314318

315319
headerElement.addEventListener(`click`, () => {
316320
if (!container) {
@@ -322,6 +326,7 @@ export function enableItem ({headerElement, classData, classBlockName, classBloc
322326
del = block(`div`, `interactive normal icon delete`);
323327
controls.appendChild(add);
324328
controls.appendChild(del);
329+
325330
add.addEventListener(`mousedown`, () => { // form the list of not present properties
326331
while (add.firstChild)
327332
add.removeChild(add.firstChild);
@@ -348,11 +353,22 @@ export function enableItem ({headerElement, classData, classBlockName, classBloc
348353
propManifest: propManifest,
349354
propName: propName,
350355
propData: propManifest.default || "",
351-
savePath: isClass
352-
? [classData["Name"]]
353-
: [classData["Name"], classBlockName, classBlockPropName]
356+
savePath: savePath
354357
}))
355358
});
359+
360+
let lastTimeDelClicked = 0;
361+
del.addEventListener(`click`, e => e.stopPropagation());
362+
del.addEventListener(`click`, () => {
363+
let delta = (-lastTimeDelClicked + (lastTimeDelClicked = (new Date()).getTime()));
364+
if (delta > 5000) { // > 5 sec - show message "click again to delete"
365+
new Toast(Toast.TYPE_INFO, `Click again to delete`);
366+
} else { // delete
367+
addChange(savePath.concat(`$delete`), true);
368+
detach(headerElement);
369+
detach(container);
370+
}
371+
});
356372
}
357373
if (opened = !opened) {
358374
insertAfter(container, headerElement);

source/client/js/domUtils.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ export function block (element = "div", className, textContent) {
1212
return el;
1313
}
1414

15+
/**
16+
* Safely detach element from the DOM.
17+
* @param {HTMLElement} element
18+
*/
19+
export function detach (element) {
20+
if (element.parentNode)
21+
element.parentNode.removeChild(element);
22+
}
23+
1524
export function insertAfter (elem, refElem) {
1625
return refElem.parentNode.insertBefore(elem, refElem.nextSibling);
1726
}

source/client/js/toast/Toaster.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Toast } from "./index";
2+
3+
/**
4+
* @type {Toaster}
5+
*/
6+
export var toaster = new Toaster();
7+
8+
/**
9+
* Toasts controller. Toast is the message that appears on the screen for a little while. It is
10+
* useful for showing info messages.
11+
* @constructor
12+
*/
13+
function Toaster () {
14+
15+
/**
16+
* @type {Toast[]}
17+
*/
18+
this.toasts = [];
19+
20+
}
21+
22+
/**
23+
* @param {Toast} toast
24+
* @param {number} timeout
25+
*/
26+
Toaster.prototype.push = function (toast, timeout) {
27+
28+
let height = toast.attach(0),
29+
self = this;
30+
31+
this.toasts.forEach((toast) => {
32+
toast.seek(height);
33+
});
34+
this.toasts.push(toast);
35+
36+
setTimeout(() => {
37+
self.toasts.splice(0, 1)[0].detach();
38+
}, timeout);
39+
40+
};

source/client/js/toast/index.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { toaster } from "./Toaster.js";
2+
3+
Toast.TYPE_INFO = "info";
4+
Toast.TYPE_MESSAGE = "message";
5+
Toast.TYPE_WARNING = "warning";
6+
Toast.TYPE_ERROR = "error";
7+
Toast.TYPE_DONE = "done";
8+
9+
Toast.TIME_SHORT = 2000;
10+
Toast.TIME_NORMAL = 4000;
11+
Toast.TIME_LONG = 8000;
12+
13+
/**
14+
* On-screen toast message.
15+
* @param {string} type - Toast.TYPE_*
16+
* @param {string} text
17+
* @param {number} [timeout]
18+
* @constructor
19+
*/
20+
export function Toast (type, text, timeout = Toast.TIME_NORMAL) {
21+
22+
let el1 = document.createElement("div"),
23+
el2 = document.createElement("div");
24+
25+
el1.className = "toast";
26+
el2.className = `body ${type}`;
27+
el1.appendChild(el2);
28+
el2.innerHTML = `${text}`;
29+
el1.style.opacity = 0;
30+
31+
this.element = el1;
32+
this.position = 0;
33+
34+
toaster.push(this, timeout);
35+
36+
}
37+
38+
/**
39+
* Attaches toast to GUI and return the height of the element.
40+
*/
41+
Toast.prototype.attach = function (position) {
42+
43+
this.position = position;
44+
this.updateVisualPosition();
45+
document.body.appendChild(this.element);
46+
setTimeout(() => {
47+
this.element.style.opacity = 1;
48+
}, 0);
49+
50+
return this.element.offsetHeight;
51+
52+
};
53+
54+
/**
55+
* Seek the toast message by Y coordinate.
56+
* @param delta
57+
*/
58+
Toast.prototype.seek = function (delta) {
59+
60+
this.position += delta;
61+
this.updateVisualPosition();
62+
63+
};
64+
65+
/**
66+
* todo: upgrade to transform
67+
* @private
68+
*/
69+
Toast.prototype.updateVisualPosition = function () {
70+
71+
this.element.style.bottom = this.position + "px";
72+
73+
};
74+
75+
Toast.prototype.detach = function () {
76+
77+
let self = this;
78+
79+
if (!this.element.parentNode) return;
80+
81+
this.element.style.opacity = 0;
82+
setTimeout(() => {
83+
self.element.parentNode.removeChild(self.element);
84+
}, 300);
85+
86+
};

source/client/scss/index.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
@import "basic";
77
@import "grid/cards";
88
@import "classBuilder/card";
9-
@import "icons";
9+
@import "icons";
10+
@import "./toast/toast";
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@import "../mixins";
2+
3+
.toast {
4+
5+
position: absolute;
6+
right: 0;
7+
bottom: 0;
8+
z-index: 10000;
9+
@include transition(all .3s ease);
10+
11+
> .body {
12+
13+
font-size: 12pt;
14+
margin: 3px;
15+
padding: .3em;
16+
background: rgba(255, 255, 255, 0.8);
17+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
18+
19+
&.info {
20+
background: #fffcc8;
21+
}
22+
23+
&.info:before {
24+
content: "[INFO] ";
25+
}
26+
27+
&.warning {
28+
29+
background: #e8ab1f;
30+
31+
> .icon {
32+
color: white;
33+
}
34+
35+
}
36+
37+
&.error {
38+
color: white;
39+
text-shadow: 0 0 1px black;
40+
background: #ff4300;
41+
}
42+
43+
&.done {
44+
background: #c4ffc4;
45+
}
46+
47+
}
48+
49+
}

0 commit comments

Comments
 (0)