From 1a282b6c8cb835618fcf6d8cc42e86d9500fd288 Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Fri, 22 Apr 2022 21:39:42 +0200 Subject: [PATCH] Minor style adjustements --- dist/css/ueb-style.css | 2 +- dist/css/ueb-style.css.map | 2 +- dist/ueblueprint.js | 3056 +++++++++++++++++------------------ js/Configuration.js | 2 +- js/template/NodeTemplate.js | 4 +- scss/ueb-node.scss | 13 +- scss/ueb-pin.scss | 8 +- 7 files changed, 1544 insertions(+), 1543 deletions(-) diff --git a/dist/css/ueb-style.css b/dist/css/ueb-style.css index 0631f5e..0b55c34 100644 --- a/dist/css/ueb-style.css +++ b/dist/css/ueb-style.css @@ -1 +1 @@ -@font-face{font-family:"Roboto";font-style:light;src:url("../font/roboto-light.woff2") format("woff2"),url("../font/roboto-light.woff") format("woff")}@font-face{font-family:"Roboto";font-style:regular;src:url("../font/roboto-regular.woff2") format("woff2"),url("../font/roboto-regular.woff") format("woff")}ueb-blueprint{display:block;position:relative;font-family:Roboto,Noto,Oxygen,Ubuntu,"Open Sans","Helvetica Neue",sans-serif;font-size:var(--ueb-font-size);user-select:none}.ueb-viewport-header{display:flex;position:absolute;top:0;right:0;left:0;height:1.5em;background:rgba(0,0,0,.5);z-index:1}.ueb-viewport-zoom{margin-left:auto;color:#4d4d4db7;font-size:20px}.ueb-viewport-body{position:relative;height:var(--ueb-height, 30rem);overflow:hidden;scrollbar-width:0}ueb-blueprint[data-focused=true] .ueb-viewport-body{overflow:scroll}.ueb-grid{--ueb-grid-line-actual-width: calc(var(--ueb-grid-line-width) / var(--ueb-scale));position:absolute;min-width:100%;min-height:100%;width:calc((100% + var(--ueb-additional-x)*1px)/var(--ueb-scale));height:calc((100% + var(--ueb-additional-y)*1px)/var(--ueb-scale));background-color:#262626;background-image:linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),linear-gradient(to right, var(--ueb-grid-set-line-color), var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to bottom, var(--ueb-grid-set-line-color), var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to right, var(--ueb-grid-line-color), var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to bottom, var(--ueb-grid-line-color), var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent);background-size:100% var(--ueb-grid-line-actual-width),var(--ueb-grid-line-actual-width) 100%,calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)),calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)),var(--ueb-grid-actual-size) var(--ueb-grid-actual-size),var(--ueb-grid-actual-size) var(--ueb-grid-actual-size);background-position:calc(var(--ueb-translate-x)*1px) calc(var(--ueb-translate-y)*1px);background-repeat:repeat-x,repeat-y,repeat,repeat,repeat,repeat;transform:scale(var(--ueb-scale), var(--ueb-scale));transform-origin:0 0;overflow:hidden}ueb-blueprint[data-drag-scrolling=true] .ueb-grid{cursor:grabbing}ueb-blueprint[data-drag-scrolling=false] .ueb-grid{cursor:default}.ueb-zoom--.ueb,.ueb{--ueb-scale: 1;--ueb-grid-actual-size: var(--ueb-grid-size)}.ueb-zoom-7.ueb{--ueb-scale: 2}.ueb-zoom-6.ueb{--ueb-scale: 1.875}.ueb-zoom-5.ueb{--ueb-scale: 1.75}.ueb-zoom-4.ueb{--ueb-scale: 1.675}.ueb-zoom-3.ueb{--ueb-scale: 1.5}.ueb-zoom-2.ueb{--ueb-scale: 1.375}.ueb-zoom-1.ueb{--ueb-scale: 1.25}.ueb-zoom--1.ueb{--ueb-scale: 0.875}.ueb-zoom--2.ueb{--ueb-scale: 0.75}.ueb-zoom--3.ueb{--ueb-scale: 0.675}.ueb-zoom--4.ueb{--ueb-scale: 0.5;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2)}.ueb-zoom--5.ueb{--ueb-scale: 0.375;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2)}.ueb-zoom--6.ueb{--ueb-scale: 0.333333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--7.ueb{--ueb-scale: 0.3;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--8.ueb{--ueb-scale: 0.266666;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--9.ueb{--ueb-scale: 0.233333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--10.ueb{--ueb-scale: 0.2;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--11.ueb{--ueb-scale: 0.166666;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6)}.ueb-zoom--12.ueb{--ueb-scale: 0.133333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6)}.ueb-grid-content{position:relative;width:0;height:0;transform:translateX(calc(var(--ueb-translate-x) * 1px)) translateY(calc(var(--ueb-translate-y) * 1px))}.ueb-grid-content>div{width:0;height:0}.ueb-positioned,ueb-blueprint[data-selecting=true] ueb-selector{--ueb-computed-min-x: min(var(--ueb-from-x), var(--ueb-to-x));--ueb-computed-max-x: max(var(--ueb-from-x), var(--ueb-to-x));--ueb-computed-min-y: min(var(--ueb-from-y), var(--ueb-to-y));--ueb-computed-max-y: max(var(--ueb-from-y), var(--ueb-to-y));--ueb-computed-width: max(var(--ueb-from-x) - var(--ueb-to-x), var(--ueb-to-x) - var(--ueb-from-x));--ueb-computed-height: max(var(--ueb-from-y) - var(--ueb-to-y), var(--ueb-to-y) - var(--ueb-from-y));position:absolute;top:calc(var(--ueb-computed-min-y)*1px);left:calc(var(--ueb-computed-min-x)*1px);width:calc(var(--ueb-computed-width)*1px);height:calc(var(--ueb-computed-height)*1px)}ueb-selector{display:block;position:absolute;visibility:hidden;top:0;left:0;width:0;height:0;background-image:repeating-linear-gradient(90deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(180deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(1px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(180deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(0deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(0deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale)));background-size:100% calc(1px/var(--ueb-scale)),100% calc(3px/var(--ueb-scale)),100% calc(1px/var(--ueb-scale)),100% calc(3px/var(--ueb-scale)),calc(1px/var(--ueb-scale)) 100%,calc(3px/var(--ueb-scale)) 100%,calc(1px/var(--ueb-scale)) 100%,calc(3px/var(--ueb-scale)) 100%;background-position:0 calc(1px/var(--ueb-scale)),0 0,0 calc(100% - 1px/var(--ueb-scale)),0 100%,calc(1px/var(--ueb-scale)) 0,0 0,calc(100% - 1px/var(--ueb-scale)) 0,100% 0;background-repeat:no-repeat}ueb-blueprint[data-selecting=true] ueb-selector{visibility:visible}ueb-selector>*{visibility:visible}ueb-node{display:block;position:absolute;transform:translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px));border-radius:var(--ueb-node-radius);box-shadow:0 0 1px 0 #000,1px 4px 6px 0 rgba(0,0,0,.3);font-weight:lighter}ueb-blueprint[data-drag-scrolling=false][data-selecting=false] ueb-node{cursor:move}.ueb-node-border{margin:-3px;padding:3px;border-radius:calc(var(--ueb-node-radius)*1.4)}.ueb-selected>.ueb-node-border{background-image:linear-gradient(to right, #f1b000 0%, #f1b000 100%),linear-gradient(to bottom, #f1b000 0%, #cc6700 100%),linear-gradient(to right, #cc6700 0%, #cc6700 100%),linear-gradient(to bottom, #f1b000 0%, #cc6700 100%);background-size:100% 7px,7px 100%,100% 7px,7px 100%;background-position:top,right,bottom,left;background-repeat:repeat-x,repeat-y,repeat-x,repeat-y;outline:3px solid #cc6700;outline-offset:-6px}.ueb-node-content{position:relative;padding:1px;box-shadow:inset 0 0 2px 0 #000;border-radius:var(--ueb-node-radius);background:rgba(10,10,10,.8);overflow:hidden}.ueb-node-header{padding:.3em .7em;box-shadow:inset 5px 1px 5px -3px #92c381,inset 0 1px 2px 0 #313631,inset 0 2px 0 0 #92c381;border-radius:var(--ueb-node-radius) var(--ueb-node-radius) 0 0;background:linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%);color:silver;font-weight:600;white-space:nowrap}.ueb-node-name{display:inline-block;min-width:80%;background:radial-gradient(ellipse 95% 60% at 20% 50%, rgba(0, 0, 0, 0.5) 0%, transparent 90%);margin:-0.1em -1.6em;padding:.1em 1.6em}.ueb-node-body{display:flex;padding:1px 0;color:#fff;font-weight:100;white-space:nowrap}.ueb-node-inputs{margin-right:auto;padding-left:8px}.ueb-node-outputs{padding-right:8px}.ueb-node-expand{display:none}ueb-node[data-advanced-display] .ueb-node-expand{display:block}ueb-pin{display:block;margin:6px 0;padding:2px 2px}ueb-pin>*{display:inline-block;vertical-align:middle}ueb-node[data-advanced-display=Hidden] ueb-pin[data-advanced-view=true]{display:none}ueb-blueprint[data-drag-scrolling=false][data-selecting=false] ueb-pin:hover{background:var(--ueb-pin-background);cursor:crosshair}.ueb-node-outputs ueb-pin{text-align:right}.ueb-pin-icon-exec{display:inline-block;vertical-align:text-top}.ueb-pin-icon-value{display:inline-block;position:relative;width:1em;height:1em;vertical-align:baseline;margin:0 .4em -1px .1em}.ueb-pin-icon-value::before{content:"";display:block;position:absolute;top:0;right:0;bottom:0;left:0;border:2px solid var(--ueb-pin-color);border-radius:50%}ueb-pin.ueb-pin-fill .ueb-pin-icon-value::before{background:var(--ueb-pin-color)}.ueb-pin-icon-value::after{content:"";display:block;position:absolute;top:calc(50% - .3em);left:calc(100% + 1px);width:0;height:0;border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid var(--ueb-pin-color)}.ueb-pin-name{display:inline-block;vertical-align:middle}.ueb-pin-exec .ueb-pin-name{display:none}.ueb-pin-input{display:inline-block;vertical-align:middle;margin-left:3px;border:1px solid #a0a0a0;border-radius:3px;padding:1px 3px 1px 3px;color:silver}.ueb-pin-input:hover,.ueb-pin-input:active,.ueb-pin-input:focus,.ueb-pin-input:focus-within{background:#ffffff46;outline:none}.ueb-pin-input-content{display:block;outline:none;border:none;padding:0;min-width:10px;max-width:400px;max-height:16em;background:none;color:inherit;cursor:text;overflow:auto}.ueb-pin-input-content::-webkit-scrollbar{width:10px;height:10px}.ueb-pin-input-content::-webkit-scrollbar-thumb{background:#575757;border-radius:10px;margin:4px}ueb-link{--ueb-from-input-coefficient: calc(2 * var(--ueb-from-input) - 1);--ueb-y-opposite: clamp(0, var(--ueb-from-y) - var(--ueb-to-y) - 1, 1);display:block;min-width:calc(var(--ueb-link-min-width)*1px);visibility:hidden}ueb-link svg{--ueb-y-opposite-coefficient: calc(2* var(--ueb-y-opposite) - 1);position:absolute;top:0;left:0;width:100%;height:100%;min-height:1px;transform:scaleY(calc(var(--ueb-y-opposite-coefficient) * var(--ueb-from-input-coefficient)));overflow:visible}ueb-link svg path{visibility:visible;stroke:var(--ueb-pin-color);stroke-width:1}ueb-link.ueb-link-dragging svg path,ueb-link svg g:hover path{stroke-width:5;transition:stroke-width .8s}ueb-link-message{display:block;visibility:visible;position:absolute;top:calc(100%*(1 - var(--ueb-y-opposite)) + 22px);left:calc((1 - var(--ueb-from-input))*100% + (var(--ueb-from-input-coefficient))*var(--ueb-start-percentage) + 15px);border:1px solid #000;padding:4px 8px;border-radius:2px;background:linear-gradient(to bottom, #2a2a2a 0, #151515 50%, #2a2a2a 100%);color:var(--ueb-pin-dim-color);white-space:nowrap;z-index:1000000}.ueb{--ueb-pin-color: white;--ueb-pin-dim-color: #afafaf}.ueb-pin-boolean{--ueb-pin-color: #4d0000}.ueb-pin-class{--ueb-pin-color: #5800bb}.ueb-pin-float{--ueb-pin-color: #9ffb44}.ueb-pin-int{--ueb-pin-color: #1fe0ad}.ueb-pin-name{--ueb-pin-color: #cb81fc}.ueb-pin-object{--ueb-pin-color: #006603}.ueb-pin-rotator{--ueb-pin-color: #9eb1fc}.ueb-pin-string{--ueb-pin-color: #fc00d2;--ueb-pin-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent)}.ueb-pin-vector{--ueb-pin-color: #fcc823}/*# sourceMappingURL=ueb-style.css.map */ +@font-face{font-family:"Roboto";font-style:light;src:url("../font/roboto-light.woff2") format("woff2"),url("../font/roboto-light.woff") format("woff")}@font-face{font-family:"Roboto";font-style:regular;src:url("../font/roboto-regular.woff2") format("woff2"),url("../font/roboto-regular.woff") format("woff")}ueb-blueprint{display:block;position:relative;font-family:Roboto,Noto,Oxygen,Ubuntu,"Open Sans","Helvetica Neue",sans-serif;font-size:var(--ueb-font-size);user-select:none}.ueb-viewport-header{display:flex;position:absolute;top:0;right:0;left:0;height:1.5em;background:rgba(0,0,0,.5);z-index:1}.ueb-viewport-zoom{margin-left:auto;color:#4d4d4db7;font-size:20px}.ueb-viewport-body{position:relative;height:var(--ueb-height, 30rem);overflow:hidden;scrollbar-width:0}ueb-blueprint[data-focused=true] .ueb-viewport-body{overflow:scroll}.ueb-grid{--ueb-grid-line-actual-width: calc(var(--ueb-grid-line-width) / var(--ueb-scale));position:absolute;min-width:100%;min-height:100%;width:calc((100% + var(--ueb-additional-x)*1px)/var(--ueb-scale));height:calc((100% + var(--ueb-additional-y)*1px)/var(--ueb-scale));background-color:#262626;background-image:linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),linear-gradient(to right, var(--ueb-grid-set-line-color), var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to bottom, var(--ueb-grid-set-line-color), var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to right, var(--ueb-grid-line-color), var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent),linear-gradient(to bottom, var(--ueb-grid-line-color), var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), transparent var(--ueb-grid-line-actual-width), transparent);background-size:100% var(--ueb-grid-line-actual-width),var(--ueb-grid-line-actual-width) 100%,calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)),calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set)*var(--ueb-grid-actual-size)),var(--ueb-grid-actual-size) var(--ueb-grid-actual-size),var(--ueb-grid-actual-size) var(--ueb-grid-actual-size);background-position:calc(var(--ueb-translate-x)*1px) calc(var(--ueb-translate-y)*1px);background-repeat:repeat-x,repeat-y,repeat,repeat,repeat,repeat;transform:scale(var(--ueb-scale), var(--ueb-scale));transform-origin:0 0;overflow:hidden}ueb-blueprint[data-drag-scrolling=true] .ueb-grid{cursor:grabbing}ueb-blueprint[data-drag-scrolling=false] .ueb-grid{cursor:default}.ueb-zoom--.ueb,.ueb{--ueb-scale: 1;--ueb-grid-actual-size: var(--ueb-grid-size)}.ueb-zoom-7.ueb{--ueb-scale: 2}.ueb-zoom-6.ueb{--ueb-scale: 1.875}.ueb-zoom-5.ueb{--ueb-scale: 1.75}.ueb-zoom-4.ueb{--ueb-scale: 1.675}.ueb-zoom-3.ueb{--ueb-scale: 1.5}.ueb-zoom-2.ueb{--ueb-scale: 1.375}.ueb-zoom-1.ueb{--ueb-scale: 1.25}.ueb-zoom--1.ueb{--ueb-scale: 0.875}.ueb-zoom--2.ueb{--ueb-scale: 0.75}.ueb-zoom--3.ueb{--ueb-scale: 0.675}.ueb-zoom--4.ueb{--ueb-scale: 0.5;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2)}.ueb-zoom--5.ueb{--ueb-scale: 0.375;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2)}.ueb-zoom--6.ueb{--ueb-scale: 0.333333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--7.ueb{--ueb-scale: 0.3;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--8.ueb{--ueb-scale: 0.266666;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--9.ueb{--ueb-scale: 0.233333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--10.ueb{--ueb-scale: 0.2;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3)}.ueb-zoom--11.ueb{--ueb-scale: 0.166666;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6)}.ueb-zoom--12.ueb{--ueb-scale: 0.133333;--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6)}.ueb-grid-content{position:relative;width:0;height:0;transform:translateX(calc(var(--ueb-translate-x) * 1px)) translateY(calc(var(--ueb-translate-y) * 1px))}.ueb-grid-content>div{width:0;height:0}.ueb-positioned,ueb-blueprint[data-selecting=true] ueb-selector{--ueb-computed-min-x: min(var(--ueb-from-x), var(--ueb-to-x));--ueb-computed-max-x: max(var(--ueb-from-x), var(--ueb-to-x));--ueb-computed-min-y: min(var(--ueb-from-y), var(--ueb-to-y));--ueb-computed-max-y: max(var(--ueb-from-y), var(--ueb-to-y));--ueb-computed-width: max(var(--ueb-from-x) - var(--ueb-to-x), var(--ueb-to-x) - var(--ueb-from-x));--ueb-computed-height: max(var(--ueb-from-y) - var(--ueb-to-y), var(--ueb-to-y) - var(--ueb-from-y));position:absolute;top:calc(var(--ueb-computed-min-y)*1px);left:calc(var(--ueb-computed-min-x)*1px);width:calc(var(--ueb-computed-width)*1px);height:calc(var(--ueb-computed-height)*1px)}ueb-selector{display:block;position:absolute;visibility:hidden;top:0;left:0;width:0;height:0;background-image:repeating-linear-gradient(90deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(90deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(180deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(1px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(180deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(0deg, transparent, transparent calc(1px / var(--ueb-scale)), white calc(2px / var(--ueb-scale)), white calc(7px / var(--ueb-scale)), transparent calc(7px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale))),repeating-linear-gradient(0deg, black, black calc(8px / var(--ueb-scale)), transparent calc(9px / var(--ueb-scale)), transparent calc(11px / var(--ueb-scale)));background-size:100% calc(1px/var(--ueb-scale)),100% calc(3px/var(--ueb-scale)),100% calc(1px/var(--ueb-scale)),100% calc(3px/var(--ueb-scale)),calc(1px/var(--ueb-scale)) 100%,calc(3px/var(--ueb-scale)) 100%,calc(1px/var(--ueb-scale)) 100%,calc(3px/var(--ueb-scale)) 100%;background-position:0 calc(1px/var(--ueb-scale)),0 0,0 calc(100% - 1px/var(--ueb-scale)),0 100%,calc(1px/var(--ueb-scale)) 0,0 0,calc(100% - 1px/var(--ueb-scale)) 0,100% 0;background-repeat:no-repeat}ueb-blueprint[data-selecting=true] ueb-selector{visibility:visible}ueb-selector>*{visibility:visible}ueb-node{display:block;position:absolute;transform:translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px));border-radius:var(--ueb-node-radius);box-shadow:0 0 1px 0 #000,1px 4px 6px 0 rgba(0,0,0,.3);font-weight:lighter}ueb-blueprint[data-drag-scrolling=false][data-selecting=false] ueb-node{cursor:move}.ueb-node-border{margin:-3px;padding:3px;border-radius:calc(var(--ueb-node-radius)*1.4)}.ueb-selected>.ueb-node-border{background-image:linear-gradient(to right, #f1b000 0%, #f1b000 100%),linear-gradient(to bottom, #f1b000 0%, #cc6700 100%),linear-gradient(to right, #cc6700 0%, #cc6700 100%),linear-gradient(to bottom, #f1b000 0%, #cc6700 100%);background-size:100% 7px,7px 100%,100% 7px,7px 100%;background-position:top,right,bottom,left;background-repeat:repeat-x,repeat-y,repeat-x,repeat-y;outline:3px solid #cc6700;outline-offset:-6px}.ueb-node-content{position:relative;padding:1px;box-shadow:inset 0 0 2px 0 #000;border-radius:var(--ueb-node-radius);background:rgba(10,10,10,.8);overflow:hidden}.ueb-node-header{padding:.3em .7em;box-shadow:inset 5px 1px 5px -3px #83b37b,inset 0 1px 0 0 #111311,inset 0 2px 0 0 #83b37b;border-radius:var(--ueb-node-radius) var(--ueb-node-radius) 0 0;background:linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%);color:silver;font-weight:900;white-space:nowrap}.ueb-node-name{background:radial-gradient(ellipse 100% 100% at 30% 50%, rgba(0, 0, 0, 0.45) 20%, transparent 50%);margin:-0.1em -1.6em;padding:.1em 1.6em}.ueb-node-body{display:flex;padding:1px 0;color:#fff;font-weight:100;white-space:nowrap}.ueb-node-inputs{margin-right:20px;padding-left:8px}.ueb-node-outputs{margin-left:auto;padding-right:8px}.ueb-node-expand{display:none}ueb-node[data-advanced-display] .ueb-node-expand{display:block}ueb-pin{display:block;margin:6px 0;padding:2px 2px}ueb-pin>*{display:inline-block;vertical-align:middle}ueb-node[data-advanced-display=Hidden] ueb-pin[data-advanced-view=true]{display:none}ueb-blueprint[data-drag-scrolling=false][data-selecting=false] ueb-pin:hover{background:var(--ueb-pin-background);cursor:crosshair}.ueb-node-outputs ueb-pin{text-align:right}.ueb-pin-icon-exec{display:inline-block;vertical-align:text-top}.ueb-pin-icon-value{display:inline-block;position:relative;width:calc(1em - 1px);height:calc(1em - 1px);vertical-align:baseline;margin:0 .5em -1px .1em}.ueb-pin-icon-value::before{content:"";display:block;position:absolute;top:0;right:0;bottom:0;left:0;border:2px solid var(--ueb-pin-color);border-radius:50%}ueb-pin.ueb-pin-fill .ueb-pin-icon-value::before{background:var(--ueb-pin-color)}.ueb-pin-icon-value::after{content:"";display:block;position:absolute;top:calc(50% - .3em);left:calc(100% + 1px);width:0;height:0;border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid var(--ueb-pin-color)}.ueb-pin-name{display:inline-block;vertical-align:middle}.ueb-pin-exec .ueb-pin-name{display:none}.ueb-pin-input{display:inline-block;vertical-align:middle;margin-left:3px;border:1px solid #a0a0a0;border-radius:3px;padding:0 3px 0 3px;color:silver}.ueb-pin-input:hover,.ueb-pin-input:active,.ueb-pin-input:focus,.ueb-pin-input:focus-within{background:#ffffff46;outline:none}.ueb-pin-input-content{display:block;outline:none;border:none;padding:0;min-width:10px;max-width:400px;max-height:16em;background:none;color:inherit;cursor:text;overflow:auto}.ueb-pin-input-content::-webkit-scrollbar{width:10px;height:10px}.ueb-pin-input-content::-webkit-scrollbar-thumb{background:#575757;border-radius:10px;margin:4px}ueb-link{--ueb-from-input-coefficient: calc(2 * var(--ueb-from-input) - 1);--ueb-y-opposite: clamp(0, var(--ueb-from-y) - var(--ueb-to-y) - 1, 1);display:block;min-width:calc(var(--ueb-link-min-width)*1px);visibility:hidden}ueb-link svg{--ueb-y-opposite-coefficient: calc(2* var(--ueb-y-opposite) - 1);position:absolute;top:0;left:0;width:100%;height:100%;min-height:1px;transform:scaleY(calc(var(--ueb-y-opposite-coefficient) * var(--ueb-from-input-coefficient)));overflow:visible}ueb-link svg path{visibility:visible;stroke:var(--ueb-pin-color);stroke-width:1}ueb-link.ueb-link-dragging svg path,ueb-link svg g:hover path{stroke-width:5;transition:stroke-width .8s}ueb-link-message{display:block;visibility:visible;position:absolute;top:calc(100%*(1 - var(--ueb-y-opposite)) + 22px);left:calc((1 - var(--ueb-from-input))*100% + (var(--ueb-from-input-coefficient))*var(--ueb-start-percentage) + 15px);border:1px solid #000;padding:4px 8px;border-radius:2px;background:linear-gradient(to bottom, #2a2a2a 0, #151515 50%, #2a2a2a 100%);color:var(--ueb-pin-dim-color);white-space:nowrap;z-index:1000000}.ueb{--ueb-pin-color: white;--ueb-pin-dim-color: #afafaf}.ueb-pin-boolean{--ueb-pin-color: #4d0000}.ueb-pin-class{--ueb-pin-color: #5800bb}.ueb-pin-float{--ueb-pin-color: #9ffb44}.ueb-pin-int{--ueb-pin-color: #1fe0ad}.ueb-pin-name{--ueb-pin-color: #cb81fc}.ueb-pin-object{--ueb-pin-color: #006603}.ueb-pin-rotator{--ueb-pin-color: #9eb1fc}.ueb-pin-string{--ueb-pin-color: #fc00d2;--ueb-pin-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent)}.ueb-pin-vector{--ueb-pin-color: #fcc823}/*# sourceMappingURL=ueb-style.css.map */ diff --git a/dist/css/ueb-style.css.map b/dist/css/ueb-style.css.map index 34693f3..e10dfb5 100644 --- a/dist/css/ueb-style.css.map +++ b/dist/css/ueb-style.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../scss/style.scss","../../scss/ueb-node.scss","../../scss/ueb-pin.scss","../../scss/ueb-link.scss","../../scss/ueb-type-color.scss"],"names":[],"mappings":"AAAA,WACI,qBACA,iBACA,IACI,kGAIR,WACI,qBACA,mBACA,IACI,sGAIR,cACI,cACA,kBACA,8EACA,+BACA,iBAGJ,qBACI,aACA,kBACA,MACA,QACA,OACA,aACA,0BACA,UAGJ,mBACI,iBACA,gBACA,eAGJ,mBACI,kBACA,gCACA,gBACA,kBAGJ,oDACI,gBAGJ,UACI,kFACA,kBACA,eACA,gBACA,kEACA,mEACA,yBACA,iBAEI,s3BA0BJ,gBAEI,sZAQJ,sFACA,gEACA,oDACA,qBACA,gBAGJ,kDACI,gBAGJ,mDACI,eAGJ,qBAEI,eACA,6CAGJ,gBACI,eAGJ,gBACI,mBAGJ,gBACI,kBAGJ,gBACI,mBAGJ,gBACI,iBAGJ,gBACI,mBAGJ,gBACI,kBAGJ,iBACI,mBAGJ,iBACI,kBAGJ,iBACI,mBAGJ,iBACI,iBACA,uDAGJ,iBACI,mBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,iBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,sBACA,uDAGJ,kBACI,iBACA,uDAGJ,kBACI,sBACA,uDAGJ,kBACI,sBACA,uDAGJ,kBACI,kBACA,QACA,SACA,wGAGJ,sBACI,QACA,SAGJ,gEACI,8DACA,8DACA,8DACA,8DACA,oGACA,qGACA,kBACA,wCACA,yCACA,0CACA,4CAGJ,aACI,cACA,kBACA,kBACA,MACA,OACA,QACA,SACA,iBAEI,wlDAmDJ,gBAEI,gQAWJ,oBAEI,wJAOJ,4BAGJ,gDACI,mBAIJ,eACI,mBClUJ,SACI,cACA,kBACA,sGACA,qCACA,uDACA,oBAGJ,wEACI,YAGJ,iBACI,YACA,YACA,+CAGJ,+BACI,iBACI,kNAIJ,oDACA,0CACA,sDACA,0BACA,oBAGJ,kBACI,kBACA,YACA,gCACA,qCACA,6BACA,gBAGJ,iBACI,kBACA,4FACA,gEACA,8EACA,aACA,gBACA,mBAGJ,eACI,qBACA,cACA,+FACA,qBACA,mBAGJ,eACI,aACA,cACA,WACA,gBACA,mBAGJ,iBACI,kBACA,iBAGJ,kBACI,kBAGJ,iBACI,aAGJ,iDACI,cCjFJ,QACI,cACA,aACA,gBAEA,UACI,qBACA,sBAIR,wEACI,aAGJ,6EACI,qCACA,iBAGJ,0BACI,iBAGJ,mBACI,qBACA,wBAGJ,oBACI,qBACA,kBACA,UACA,WACA,wBACA,wBAGJ,4BACI,WACA,cACA,kBACA,MACA,QACA,SACA,OACA,sCACA,kBAGJ,iDACI,gCAGJ,2BACI,WACA,cACA,kBACA,qBACA,sBACA,QACA,SACA,kCACA,qCACA,4CAGJ,cACI,qBACA,sBAGJ,4BACI,aAGJ,eACI,qBACA,sBACA,gBACA,yBACA,kBACA,wBACA,aAEA,4FAII,qBACA,aAIR,uBACI,cACA,aACA,YACA,UACA,eACA,gBACA,gBACA,gBACA,cACA,YACA,cAEA,0CACI,WACA,YAGJ,gDACI,mBACA,mBACA,WCnHR,SACI,kEAEA,uEACA,cACA,8CAKA,kBAGJ,aACI,iEACA,kBACA,MACA,OACA,WACA,YACA,eACA,8FACA,iBAGJ,kBACI,mBACA,4BACA,eAGJ,8DAEI,eACA,4BAGJ,iBACI,cACA,mBACA,kBACA,kDACA,qHAOA,sBACA,gBACA,kBACA,4EACA,+BACA,mBACA,gBCvDJ,KAGI,uBACA,6BAGJ,iBAEI,yBAGJ,eAEI,yBAGJ,eAEI,yBAGJ,aAEI,yBAGJ,cAEI,yBAGJ,gBAGI,yBAGJ,iBAEI,yBAGJ,gBAEI,yBACA,mGAGJ,gBAEI","file":"ueb-style.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../../scss/style.scss","../../scss/ueb-node.scss","../../scss/ueb-pin.scss","../../scss/ueb-link.scss","../../scss/ueb-type-color.scss"],"names":[],"mappings":"AAAA,WACI,qBACA,iBACA,IACI,kGAIR,WACI,qBACA,mBACA,IACI,sGAIR,cACI,cACA,kBACA,8EACA,+BACA,iBAGJ,qBACI,aACA,kBACA,MACA,QACA,OACA,aACA,0BACA,UAGJ,mBACI,iBACA,gBACA,eAGJ,mBACI,kBACA,gCACA,gBACA,kBAGJ,oDACI,gBAGJ,UACI,kFACA,kBACA,eACA,gBACA,kEACA,mEACA,yBACA,iBAEI,s3BA0BJ,gBAEI,sZAQJ,sFACA,gEACA,oDACA,qBACA,gBAGJ,kDACI,gBAGJ,mDACI,eAGJ,qBAEI,eACA,6CAGJ,gBACI,eAGJ,gBACI,mBAGJ,gBACI,kBAGJ,gBACI,mBAGJ,gBACI,iBAGJ,gBACI,mBAGJ,gBACI,kBAGJ,iBACI,mBAGJ,iBACI,kBAGJ,iBACI,mBAGJ,iBACI,iBACA,uDAGJ,iBACI,mBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,iBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,sBACA,uDAGJ,kBACI,iBACA,uDAGJ,kBACI,sBACA,uDAGJ,kBACI,sBACA,uDAGJ,kBACI,kBACA,QACA,SACA,wGAGJ,sBACI,QACA,SAGJ,gEACI,8DACA,8DACA,8DACA,8DACA,oGACA,qGACA,kBACA,wCACA,yCACA,0CACA,4CAGJ,aACI,cACA,kBACA,kBACA,MACA,OACA,QACA,SACA,iBAEI,wlDAmDJ,gBAEI,gQAWJ,oBAEI,wJAOJ,4BAGJ,gDACI,mBAIJ,eACI,mBClUJ,SACI,cACA,kBACA,sGACA,qCACA,uDACA,oBAGJ,wEACI,YAGJ,iBACI,YACA,YACA,+CAGJ,+BACI,iBACI,kNAIJ,oDACA,0CACA,sDACA,0BACA,oBAGJ,kBACI,kBACA,YACA,gCACA,qCACA,6BACA,gBAGJ,iBACI,kBACA,0FAGA,gEACA,8EACA,aACA,gBACA,mBAGJ,eACI,mGACA,qBACA,mBAGJ,eACI,aACA,cACA,WACA,gBACA,mBAGJ,iBACI,kBACA,iBAGJ,kBACI,iBACA,kBAGJ,iBACI,aAGJ,iDACI,cClFJ,QACI,cACA,aACA,gBAEA,UACI,qBACA,sBAIR,wEACI,aAGJ,6EACI,qCACA,iBAGJ,0BACI,iBAGJ,mBACI,qBACA,wBAGJ,oBACI,qBACA,kBACA,sBACA,uBACA,wBACA,wBAGJ,4BACI,WACA,cACA,kBACA,MACA,QACA,SACA,OACA,sCACA,kBAGJ,iDACI,gCAGJ,2BACI,WACA,cACA,kBACA,qBACA,sBACA,QACA,SACA,kCACA,qCACA,4CAGJ,cACI,qBACA,sBAGJ,4BACI,aAGJ,eACI,qBACA,sBACA,gBACA,yBACA,kBACA,oBACA,aAEA,4FAII,qBACA,aAIR,uBACI,cACA,aACA,YACA,UACA,eACA,gBACA,gBACA,gBACA,cACA,YACA,cAEA,0CACI,WACA,YAGJ,gDACI,mBACA,mBACA,WCnHR,SACI,kEAEA,uEACA,cACA,8CAKA,kBAGJ,aACI,iEACA,kBACA,MACA,OACA,WACA,YACA,eACA,8FACA,iBAGJ,kBACI,mBACA,4BACA,eAGJ,8DAEI,eACA,4BAGJ,iBACI,cACA,mBACA,kBACA,kDACA,qHAOA,sBACA,gBACA,kBACA,4EACA,+BACA,mBACA,gBCvDJ,KAGI,uBACA,6BAGJ,iBAEI,yBAGJ,eAEI,yBAGJ,eAEI,yBAGJ,aAEI,yBAGJ,cAEI,yBAGJ,gBAGI,yBAGJ,iBAEI,yBAGJ,gBAEI,yBACA,mGAGJ,gBAEI","file":"ueb-style.css"} \ No newline at end of file diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index 5c94363..09acc21 100755 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -12,7 +12,7 @@ class Configuration { begin: "blueprint-focus", end: "blueprint-unfocus", } - static fontSize = "12px" + static fontSize = "12.5px" static gridAxisLineColor = "black" static gridExpandThreshold = 0.25 // remaining size factor threshold to cause an expansion event static gridLineColor = "#353535" @@ -145,71 +145,71 @@ class Configuration { } } -// @ts-check - -/** - * @typedef {import("../Blueprint").default} Blueprint - */ - -/** - * @template {HTMLElement} T - */ -class IInput { - - /** @type {T} */ - #target - get target() { - return this.#target - } - - /** @type {Blueprint} */ - #blueprint - get blueprint() { - return this.#blueprint - } - - /** @type {Object} */ - options - - /** - * @param {T} target - * @param {Blueprint} blueprint - * @param {Object} options - */ - constructor(target, blueprint, options) { - this.#target = target; - this.#blueprint = blueprint; - options.consumeEvent ??= false; - options.listenOnFocus ??= false; - options.unlistenOnTextEdit ??= false; - this.options = options; - let self = this; - this.listenHandler = _ => self.listenEvents(); - this.unlistenHandler = _ => self.unlistenEvents(); - if (this.options.listenOnFocus) { - this.blueprint.addEventListener(Configuration.focusEventName.begin, this.listenHandler); - this.blueprint.addEventListener(Configuration.focusEventName.end, this.unlistenHandler); - } - if (this.options.unlistenOnTextEdit) { - this.blueprint.addEventListener(Configuration.editTextEventName.begin, this.unlistenHandler); - this.blueprint.addEventListener(Configuration.editTextEventName.end, this.listenHandler); - } - } - - unlistenDOMElement() { - this.unlistenEvents(); - this.blueprint.removeEventListener(Configuration.focusEventName.begin, this.listenHandler); - this.blueprint.removeEventListener(Configuration.focusEventName.end, this.unlistenHandler); - this.blueprint.removeEventListener(Configuration.editTextEventName.begin, this.unlistenHandler); - this.blueprint.removeEventListener(Configuration.editTextEventName.end, this.listenHandler); - } - - /* Subclasses will probabily override the following methods */ - listenEvents() { - } - - unlistenEvents() { - } +// @ts-check + +/** + * @typedef {import("../Blueprint").default} Blueprint + */ + +/** + * @template {HTMLElement} T + */ +class IInput { + + /** @type {T} */ + #target + get target() { + return this.#target + } + + /** @type {Blueprint} */ + #blueprint + get blueprint() { + return this.#blueprint + } + + /** @type {Object} */ + options + + /** + * @param {T} target + * @param {Blueprint} blueprint + * @param {Object} options + */ + constructor(target, blueprint, options) { + this.#target = target; + this.#blueprint = blueprint; + options.consumeEvent ??= false; + options.listenOnFocus ??= false; + options.unlistenOnTextEdit ??= false; + this.options = options; + let self = this; + this.listenHandler = _ => self.listenEvents(); + this.unlistenHandler = _ => self.unlistenEvents(); + if (this.options.listenOnFocus) { + this.blueprint.addEventListener(Configuration.focusEventName.begin, this.listenHandler); + this.blueprint.addEventListener(Configuration.focusEventName.end, this.unlistenHandler); + } + if (this.options.unlistenOnTextEdit) { + this.blueprint.addEventListener(Configuration.editTextEventName.begin, this.unlistenHandler); + this.blueprint.addEventListener(Configuration.editTextEventName.end, this.listenHandler); + } + } + + unlistenDOMElement() { + this.unlistenEvents(); + this.blueprint.removeEventListener(Configuration.focusEventName.begin, this.listenHandler); + this.blueprint.removeEventListener(Configuration.focusEventName.end, this.unlistenHandler); + this.blueprint.removeEventListener(Configuration.editTextEventName.begin, this.unlistenHandler); + this.blueprint.removeEventListener(Configuration.editTextEventName.end, this.listenHandler); + } + + /* Subclasses will probabily override the following methods */ + listenEvents() { + } + + unlistenEvents() { + } } // @ts-check @@ -392,78 +392,78 @@ class Utility { } } -// @ts-check - -class IEntity { - - static attributes = {} - - constructor(values) { - /** - * @param {Object} target - * @param {Object} properties - * @param {Object} values - * @param {String} prefix - */ - const defineAllAttributes = (target, properties, values, prefix = "") => { - for (let property of Utility.mergeArrays( - Object.getOwnPropertyNames(properties), - Object.getOwnPropertyNames(values ?? {}) - )) { - if (!(property in properties)) { - console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}`); - } - let defaultValue = properties[property]; - const defaultType = (defaultValue instanceof TypeInitialization) - ? defaultValue.type - : (defaultValue instanceof Function) - ? defaultValue - : defaultValue?.constructor; - // Not instanceof because all objects are instenceof Object, exact match needed - if (defaultType === Object) { - target[property] = {}; - defineAllAttributes(target[property], properties[property], values[property], property + "."); - continue - } - /* - * The value can either be: - * - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World"). - * - TypeInitialization: contains the maximum amount of information about the attribute. - * - A type: the default value will be default constructed object without arguments. - * - A proper value. - */ - const value = Utility.objectGet(values, [property]); - if (value !== undefined) { - target[property] = TypeInitialization.sanitize(value, defaultType); - continue - } - if (defaultValue instanceof TypeInitialization) { - if (!defaultValue.showDefault) { - target[property] = undefined; // Declare undefined to preserve the order or attributes - continue - } - defaultValue = defaultValue.value; - } - if (defaultValue instanceof Array) { - target[property] = []; - continue - } - if (defaultValue instanceof Function) { - defaultValue = TypeInitialization.sanitize(new defaultValue(), defaultType); - } - target[property] = TypeInitialization.sanitize(defaultValue, defaultType); - } - }; - // @ts-expect-error - const attributes = this.constructor.attributes; - if (values.constructor !== Object && Object.getOwnPropertyNames(attributes).length == 1) { - // Where there is just one attribute, option can be the value of that attribute - values = { - [Object.getOwnPropertyNames(attributes)[0]]: values - }; - } - defineAllAttributes(this, attributes, values); - } +// @ts-check + +class IEntity { + + static attributes = {} + + constructor(values) { + /** + * @param {Object} target + * @param {Object} properties + * @param {Object} values + * @param {String} prefix + */ + const defineAllAttributes = (target, properties, values, prefix = "") => { + for (let property of Utility.mergeArrays( + Object.getOwnPropertyNames(properties), + Object.getOwnPropertyNames(values ?? {}) + )) { + if (!(property in properties)) { + console.warn(`Property ${prefix}${property} is not defined in ${this.constructor.name}`); + } + let defaultValue = properties[property]; + const defaultType = (defaultValue instanceof TypeInitialization) + ? defaultValue.type + : (defaultValue instanceof Function) + ? defaultValue + : defaultValue?.constructor; + // Not instanceof because all objects are instenceof Object, exact match needed + if (defaultType === Object) { + target[property] = {}; + defineAllAttributes(target[property], properties[property], values[property], property + "."); + continue + } + /* + * The value can either be: + * - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World"). + * - TypeInitialization: contains the maximum amount of information about the attribute. + * - A type: the default value will be default constructed object without arguments. + * - A proper value. + */ + const value = Utility.objectGet(values, [property]); + if (value !== undefined) { + target[property] = TypeInitialization.sanitize(value, defaultType); + continue + } + if (defaultValue instanceof TypeInitialization) { + if (!defaultValue.showDefault) { + target[property] = undefined; // Declare undefined to preserve the order or attributes + continue + } + defaultValue = defaultValue.value; + } + if (defaultValue instanceof Array) { + target[property] = []; + continue + } + if (defaultValue instanceof Function) { + defaultValue = TypeInitialization.sanitize(new defaultValue(), defaultType); + } + target[property] = TypeInitialization.sanitize(defaultValue, defaultType); + } + }; + // @ts-expect-error + const attributes = this.constructor.attributes; + if (values.constructor !== Object && Object.getOwnPropertyNames(attributes).length == 1) { + // Where there is just one attribute, option can be the value of that attribute + values = { + [Object.getOwnPropertyNames(attributes)[0]]: values + }; + } + defineAllAttributes(this, attributes, values); + } } // @ts-check @@ -532,26 +532,26 @@ class GuidEntity extends IEntity { } } -// @ts-check - -class IdentifierEntity extends IEntity { - - static attributes = { - value: String, - } - - constructor(options = {}) { - super(options); - /** @type {String} */ this.value; - } - - valueOf() { - return this.value - } - - toString() { - return this.value - } +// @ts-check + +class IdentifierEntity extends IEntity { + + static attributes = { + value: String, + } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.value; + } + + valueOf() { + return this.value + } + + toString() { + return this.value + } } // @ts-check @@ -579,43 +579,43 @@ class IntegerEntity extends IEntity { } } -// @ts-check - -class InvariantTextEntity extends IEntity { - - static lookbehind = "INVTEXT" - static attributes = { - value: String, - } - - constructor(options = {}) { - super(options); - /** @type {String} */ this.value; - } +// @ts-check + +class InvariantTextEntity extends IEntity { + + static lookbehind = "INVTEXT" + static attributes = { + value: String, + } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.value; + } } -// @ts-check - -class KeyBindingEntity extends IEntity { - - static attributes = { - ActionName: "", - bShift: false, - bCtrl: false, - bAlt: false, - bCmd: false, - Key: IdentifierEntity, - } - - constructor(options = {}) { - super(options); - /** @type {String} */ this.ActionName; - /** @type {Boolean} */ this.bShift; - /** @type {Boolean} */ this.bCtrl; - /** @type {Boolean} */ this.bAlt; - /** @type {Boolean} */ this.bCmd; - /** @type {IdentifierEntity} */ this.Key; - } +// @ts-check + +class KeyBindingEntity extends IEntity { + + static attributes = { + ActionName: "", + bShift: false, + bCtrl: false, + bAlt: false, + bCmd: false, + Key: IdentifierEntity, + } + + constructor(options = {}) { + super(options); + /** @type {String} */ this.ActionName; + /** @type {Boolean} */ this.bShift; + /** @type {Boolean} */ this.bCtrl; + /** @type {Boolean} */ this.bAlt; + /** @type {Boolean} */ this.bCmd; + /** @type {IdentifierEntity} */ this.Key; + } } // @ts-check @@ -1172,84 +1172,84 @@ class SerializerFactory { } } -// @ts-check - -class ISerializer { - - static grammar = Parsimmon.createLanguage(new Grammar()) - - constructor(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) { - this.entityType = entityType; - this.prefix = prefix ?? ""; - this.separator = separator ?? ","; - this.trailingSeparator = trailingSeparator ?? false; - this.attributeValueConjunctionSign = attributeValueConjunctionSign ?? "="; - this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join(".")); - } - - writeValue(value) { - if (value === null) { - return "()" - } - const serialize = v => SerializerFactory.getSerializer(Utility.getType(v)).write(v); - // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically) - switch (value?.constructor) { - case Function: - return this.writeValue(value()) - case Boolean: - return Utility.FirstCapital(value.toString()) - case Number: - return value.toString() - case String: - return `"${value}"` - } - if (value instanceof Array) { - return `(${value.map(v => serialize(v) + ",").join("")})` - } - if (value instanceof IEntity) { - return serialize(value) - } - } - - /** - * @param {String[]} key - * @param {Object} object - * @returns {String} - */ - subWrite(key, object) { - let result = ""; - let fullKey = key.concat(""); - const last = fullKey.length - 1; - for (const property of Object.getOwnPropertyNames(object)) { - fullKey[last] = property; - const value = object[property]; - if (object[property]?.constructor === Object) { - // Recursive call when finding an object - result += (result.length ? this.separator : "") - + this.subWrite(fullKey, value); - } else if (value !== undefined && this.showProperty(object, fullKey, value)) { - result += (result.length ? this.separator : "") - + this.prefix - + this.attributeKeyPrinter(fullKey) - + this.attributeValueConjunctionSign - + this.writeValue(value); - } - } - if (this.trailingSeparator && result.length && fullKey.length === 1) { - // append separator at the end if asked and there was printed content - result += this.separator; - } - return result - } - - showProperty(object, attributeKey, attributeValue) { - const attributes = this.entityType.attributes; - const attribute = Utility.objectGet(attributes, attributeKey); - if (attribute instanceof TypeInitialization) { - return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault - } - return true - } +// @ts-check + +class ISerializer { + + static grammar = Parsimmon.createLanguage(new Grammar()) + + constructor(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) { + this.entityType = entityType; + this.prefix = prefix ?? ""; + this.separator = separator ?? ","; + this.trailingSeparator = trailingSeparator ?? false; + this.attributeValueConjunctionSign = attributeValueConjunctionSign ?? "="; + this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join(".")); + } + + writeValue(value) { + if (value === null) { + return "()" + } + const serialize = v => SerializerFactory.getSerializer(Utility.getType(v)).write(v); + // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically) + switch (value?.constructor) { + case Function: + return this.writeValue(value()) + case Boolean: + return Utility.FirstCapital(value.toString()) + case Number: + return value.toString() + case String: + return `"${value}"` + } + if (value instanceof Array) { + return `(${value.map(v => serialize(v) + ",").join("")})` + } + if (value instanceof IEntity) { + return serialize(value) + } + } + + /** + * @param {String[]} key + * @param {Object} object + * @returns {String} + */ + subWrite(key, object) { + let result = ""; + let fullKey = key.concat(""); + const last = fullKey.length - 1; + for (const property of Object.getOwnPropertyNames(object)) { + fullKey[last] = property; + const value = object[property]; + if (object[property]?.constructor === Object) { + // Recursive call when finding an object + result += (result.length ? this.separator : "") + + this.subWrite(fullKey, value); + } else if (value !== undefined && this.showProperty(object, fullKey, value)) { + result += (result.length ? this.separator : "") + + this.prefix + + this.attributeKeyPrinter(fullKey) + + this.attributeValueConjunctionSign + + this.writeValue(value); + } + } + if (this.trailingSeparator && result.length && fullKey.length === 1) { + // append separator at the end if asked and there was printed content + result += this.separator; + } + return result + } + + showProperty(object, attributeKey, attributeValue) { + const attributes = this.entityType.attributes; + const attribute = Utility.objectGet(attributes, attributeKey); + if (attribute instanceof TypeInitialization) { + return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault + } + return true + } } // @ts-check @@ -1347,155 +1347,155 @@ class Copy extends IInput { */ const html = String.raw; -// @ts-check - -/** - * @typedef {import("../element/IElement").default} IElement - * @typedef {import("../input/IInput").default} IInput")} - */ - -/** - * @template {IElement} T - */ -class ITemplate { - - /** @type {IInput[]} */ - inputObjects = [] - - /** - * @param {T} entity - */ - render(entity) { - return "" - } - - /** - * @param {T} element - */ - setup(element) { - // TODO replace with the safer element.setHTML(...) when it will be availableBreack - element.innerHTML = this.render(element); - } - - /** - * @param {T} element - */ - inputSetup(element) { - this.inputObjects = this.createInputObjects(element); - } - - /** - * @param {T} element - */ - cleanup(element) { - this.inputObjects.forEach(v => v.unlistenDOMElement()); - } - - /** - * @param {T} element - * @returns {IInput[]} - */ - createInputObjects(element) { - return [] - } +// @ts-check + +/** + * @typedef {import("../element/IElement").default} IElement + * @typedef {import("../input/IInput").default} IInput")} + */ + +/** + * @template {IElement} T + */ +class ITemplate { + + /** @type {IInput[]} */ + inputObjects = [] + + /** + * @param {T} entity + */ + render(entity) { + return "" + } + + /** + * @param {T} element + */ + setup(element) { + // TODO replace with the safer element.setHTML(...) when it will be availableBreack + element.innerHTML = this.render(element); + } + + /** + * @param {T} element + */ + inputSetup(element) { + this.inputObjects = this.createInputObjects(element); + } + + /** + * @param {T} element + */ + cleanup(element) { + this.inputObjects.forEach(v => v.unlistenDOMElement()); + } + + /** + * @param {T} element + * @returns {IInput[]} + */ + createInputObjects(element) { + return [] + } } -// @ts-check - -class IKeyboardShortcut extends IInput { - - /** @type {KeyBindingEntity[]} */ - #activationKeys - - constructor(target, blueprint, options = {}) { - options.activateAnyKey ??= false; - options.activationKeys ??= []; - options.listenOnFocus ??= true; - options.unlistenOnTextEdit ??= true; // No shortcuts when inside of a text field - if (!(options.activationKeys instanceof Array)) { - options.activationKeys = [options.activationKeys]; - } - options.activationKeys = options.activationKeys.map(v => { - if (v instanceof KeyBindingEntity) { - return v - } - if (v.constructor === String) { - // @ts-expect-error - const parsed = ISerializer.grammar.KeyBinding.parse(v); - if (parsed.status) { - return parsed.value - } - } - throw new Error("Unexpected key value") - }); - - super(target, blueprint, options); - - this.#activationKeys = this.options.activationKeys ?? []; - - const wantsShift = keyEntry => keyEntry.bShift || keyEntry.Key == "LeftShift" || keyEntry.Key == "RightShift"; - const wantsCtrl = keyEntry => keyEntry.bCtrl || keyEntry.Key == "LeftControl" || keyEntry.Key == "RightControl"; - const wantsAlt = keyEntry => keyEntry.bAlt || keyEntry.Key == "LeftAlt" || keyEntry.Key == "RightAlt"; - - let self = this; - /** @param {KeyboardEvent} e */ - this.keyDownHandler = e => { - if ( - this.options.activateAnyKey - || self.#activationKeys.some(keyEntry => - wantsShift(keyEntry) == e.shiftKey - && wantsCtrl(keyEntry) == e.ctrlKey - && wantsAlt(keyEntry) == e.altKey - && Configuration.Keys[keyEntry.Key] == e.code - ) - ) { - if (options.consumeEvent) { - e.stopImmediatePropagation(); - } - self.fire(); - document.removeEventListener("keydown", self.keyDownHandler); - document.addEventListener("keyup", self.keyUpHandler); - } - }; - - /** @param {KeyboardEvent} e */ - this.keyUpHandler = e => { - if ( - this.options.activateAnyKey - || self.#activationKeys.some(keyEntry => - keyEntry.bShift && e.key == "Shift" - || keyEntry.bCtrl && e.key == "Control" - || keyEntry.bAlt && e.key == "Alt" - || keyEntry.bCmd && e.key == "Meta" - || Configuration.Keys[keyEntry.Key] == e.code - ) - ) { - if (options.consumeEvent) { - e.stopImmediatePropagation(); - } - self.unfire(); - document.removeEventListener("keyup", this.keyUpHandler); - document.addEventListener("keydown", this.keyDownHandler); - } - }; - - } - - listenEvents() { - document.addEventListener("keydown", this.keyDownHandler); - } - - unlistenEvents() { - document.removeEventListener("keydown", this.keyDownHandler); - } - - // Subclasses will want to override - - fire() { - } - - unfire() { - } +// @ts-check + +class IKeyboardShortcut extends IInput { + + /** @type {KeyBindingEntity[]} */ + #activationKeys + + constructor(target, blueprint, options = {}) { + options.activateAnyKey ??= false; + options.activationKeys ??= []; + options.listenOnFocus ??= true; + options.unlistenOnTextEdit ??= true; // No shortcuts when inside of a text field + if (!(options.activationKeys instanceof Array)) { + options.activationKeys = [options.activationKeys]; + } + options.activationKeys = options.activationKeys.map(v => { + if (v instanceof KeyBindingEntity) { + return v + } + if (v.constructor === String) { + // @ts-expect-error + const parsed = ISerializer.grammar.KeyBinding.parse(v); + if (parsed.status) { + return parsed.value + } + } + throw new Error("Unexpected key value") + }); + + super(target, blueprint, options); + + this.#activationKeys = this.options.activationKeys ?? []; + + const wantsShift = keyEntry => keyEntry.bShift || keyEntry.Key == "LeftShift" || keyEntry.Key == "RightShift"; + const wantsCtrl = keyEntry => keyEntry.bCtrl || keyEntry.Key == "LeftControl" || keyEntry.Key == "RightControl"; + const wantsAlt = keyEntry => keyEntry.bAlt || keyEntry.Key == "LeftAlt" || keyEntry.Key == "RightAlt"; + + let self = this; + /** @param {KeyboardEvent} e */ + this.keyDownHandler = e => { + if ( + this.options.activateAnyKey + || self.#activationKeys.some(keyEntry => + wantsShift(keyEntry) == e.shiftKey + && wantsCtrl(keyEntry) == e.ctrlKey + && wantsAlt(keyEntry) == e.altKey + && Configuration.Keys[keyEntry.Key] == e.code + ) + ) { + if (options.consumeEvent) { + e.stopImmediatePropagation(); + } + self.fire(); + document.removeEventListener("keydown", self.keyDownHandler); + document.addEventListener("keyup", self.keyUpHandler); + } + }; + + /** @param {KeyboardEvent} e */ + this.keyUpHandler = e => { + if ( + this.options.activateAnyKey + || self.#activationKeys.some(keyEntry => + keyEntry.bShift && e.key == "Shift" + || keyEntry.bCtrl && e.key == "Control" + || keyEntry.bAlt && e.key == "Alt" + || keyEntry.bCmd && e.key == "Meta" + || Configuration.Keys[keyEntry.Key] == e.code + ) + ) { + if (options.consumeEvent) { + e.stopImmediatePropagation(); + } + self.unfire(); + document.removeEventListener("keyup", this.keyUpHandler); + document.addEventListener("keydown", this.keyDownHandler); + } + }; + + } + + listenEvents() { + document.addEventListener("keydown", this.keyDownHandler); + } + + unlistenEvents() { + document.removeEventListener("keydown", this.keyDownHandler); + } + + // Subclasses will want to override + + fire() { + } + + unfire() { + } } // @ts-check @@ -1517,82 +1517,82 @@ class KeyboardCanc extends IKeyboardShortcut { } } -// @ts-check - -/** - * @typedef {import("../../Blueprint").default} Blueprint - */ - -/** - * @template {HTMLElement} T - * @extends {IInput} - */ -class IPointing extends IInput { - - constructor(target, blueprint, options) { - super(target, blueprint, options); - this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement; - } - - /** - * @param {MouseEvent} mouseEvent - */ - locationFromEvent(mouseEvent) { - return this.blueprint.compensateTranslation( - Utility.convertLocation( - [mouseEvent.clientX, mouseEvent.clientY], - this.movementSpace - ) - ) - } +// @ts-check + +/** + * @typedef {import("../../Blueprint").default} Blueprint + */ + +/** + * @template {HTMLElement} T + * @extends {IInput} + */ +class IPointing extends IInput { + + constructor(target, blueprint, options) { + super(target, blueprint, options); + this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement; + } + + /** + * @param {MouseEvent} mouseEvent + */ + locationFromEvent(mouseEvent) { + return this.blueprint.compensateTranslation( + Utility.convertLocation( + [mouseEvent.clientX, mouseEvent.clientY], + this.movementSpace + ) + ) + } } -// @ts-check - -class IMouseWheel extends IPointing { - - /** @type {(e: WheelEvent) => void} */ - #mouseWheelHandler - - /** @type {(e: WheelEvent) => void} */ - #mouseParentWheelHandler - - /** - * @param {HTMLElement} target - * @param {import("../../Blueprint").default} blueprint - * @param {Object} options - */ - constructor(target, blueprint, options) { - options.listenOnFocus = true; - super(target, blueprint, options); - this.looseTarget = options?.looseTarget ?? true; - let self = this; - - this.#mouseWheelHandler = e => { - e.preventDefault(); - const location = self.locationFromEvent(e); - self.wheel(Math.sign(e.deltaY), location); - }; - this.#mouseParentWheelHandler = e => e.preventDefault(); - - if (this.blueprint.focused) { - this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false); - } - } - - listenEvents() { - this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false); - this.movementSpace.parentElement?.addEventListener("wheel", this.#mouseParentWheelHandler); - } - - unlistenEvents() { - this.movementSpace.removeEventListener("wheel", this.#mouseWheelHandler, false); - this.movementSpace.parentElement?.removeEventListener("wheel", this.#mouseParentWheelHandler); - } - - /* Subclasses will override the following method */ - wheel(variation, location) { - } +// @ts-check + +class IMouseWheel extends IPointing { + + /** @type {(e: WheelEvent) => void} */ + #mouseWheelHandler + + /** @type {(e: WheelEvent) => void} */ + #mouseParentWheelHandler + + /** + * @param {HTMLElement} target + * @param {import("../../Blueprint").default} blueprint + * @param {Object} options + */ + constructor(target, blueprint, options) { + options.listenOnFocus = true; + super(target, blueprint, options); + this.looseTarget = options?.looseTarget ?? true; + let self = this; + + this.#mouseWheelHandler = e => { + e.preventDefault(); + const location = self.locationFromEvent(e); + self.wheel(Math.sign(e.deltaY), location); + }; + this.#mouseParentWheelHandler = e => e.preventDefault(); + + if (this.blueprint.focused) { + this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false); + } + } + + listenEvents() { + this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false); + this.movementSpace.parentElement?.addEventListener("wheel", this.#mouseParentWheelHandler); + } + + unlistenEvents() { + this.movementSpace.removeEventListener("wheel", this.#mouseWheelHandler, false); + this.movementSpace.parentElement?.removeEventListener("wheel", this.#mouseParentWheelHandler); + } + + /* Subclasses will override the following method */ + wheel(variation, location) { + } } // @ts-check @@ -1624,31 +1624,31 @@ class Zoom extends IMouseWheel { } } -// @ts-check - -class KeyboardEnableZoom extends IKeyboardShortcut { - - /** @type {Zoom} */ - #zoomInputObject - - /** - * @param {HTMLElement} target - * @param {import("../../Blueprint").default} blueprint - * @param {Object} options - */ - constructor(target, blueprint, options = {}) { - options.activationKeys = Configuration.enableZoomIn; - super(target, blueprint, options); - } - - fire() { - this.#zoomInputObject = this.blueprint.getInputObject(Zoom); - this.#zoomInputObject.enableZoonIn = true; - } - - unfire() { - this.#zoomInputObject.enableZoonIn = false; - } +// @ts-check + +class KeyboardEnableZoom extends IKeyboardShortcut { + + /** @type {Zoom} */ + #zoomInputObject + + /** + * @param {HTMLElement} target + * @param {import("../../Blueprint").default} blueprint + * @param {Object} options + */ + constructor(target, blueprint, options = {}) { + options.activationKeys = Configuration.enableZoomIn; + super(target, blueprint, options); + } + + fire() { + this.#zoomInputObject = this.blueprint.getInputObject(Zoom); + this.#zoomInputObject.enableZoonIn = true; + } + + unfire() { + this.#zoomInputObject.enableZoonIn = false; + } } // @ts-check @@ -1673,159 +1673,159 @@ class KeyboardSelectAll extends IKeyboardShortcut { } } -// @ts-check - -/** - * @typedef {import("../../Blueprint").default} Blueprint - */ - -/** - * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses. - * @template {HTMLElement} T - * @extends {IPointing} - */ -class IMouseClickDrag extends IPointing { - - /** @type {(e: MouseEvent) => void} */ - #mouseDownHandler - - /** @type {(e: MouseEvent) => void} */ - #mouseStartedMovingHandler - - /** @type {(e: MouseEvent) => void} */ - #mouseMoveHandler - - /** @type {(e: MouseEvent) => void} */ - #mouseUpHandler - - #trackingMouse = false - - started = false - - constructor(target, blueprint, options = {}) { - options.clickButton ??= 0; - options.consumeEvent ??= true; - options.exitAnyButton ??= true; - options.looseTarget ??= false; - options.moveEverywhere ??= false; - super(target, blueprint, options); - this.clickedPosition = [0, 0]; - - const movementListenedElement = this.options.moveEverywhere ? document.documentElement : this.movementSpace; - let self = this; - - this.#mouseDownHandler = e => { - this.blueprint.setFocused(true); - switch (e.button) { - case self.options.clickButton: - // Either doesn't matter or consider the click only when clicking on the parent, not descandants - if (self.options.looseTarget || e.target == e.currentTarget) { - if (this.options.consumeEvent) { - e.stopImmediatePropagation(); // Captured, don't call anyone else - } - // Attach the listeners - movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler); - document.addEventListener("mouseup", self.#mouseUpHandler); - self.clickedPosition = self.locationFromEvent(e); - self.clicked(self.clickedPosition); - } - break - default: - if (!self.options.exitAnyButton) { - self.#mouseUpHandler(e); - } - break - } - }; - - this.#mouseStartedMovingHandler = e => { - if (this.options.consumeEvent) { - e.stopImmediatePropagation(); // Captured, don't call anyone else - } - // Delegate from now on to self.#mouseMoveHandler - movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); - movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler); - // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false - const dragEvent = self.getEvent(Configuration.trackingMouseEventName.begin); - self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false; - // Do actual actions - self.startDrag(); - self.started = true; - }; - - this.#mouseMoveHandler = e => { - if (this.options.consumeEvent) { - e.stopImmediatePropagation(); // Captured, don't call anyone else - } - const location = self.locationFromEvent(e); - const movement = [e.movementX, e.movementY]; - self.dragTo(location, movement); - if (self.#trackingMouse) { - self.blueprint.mousePosition = self.locationFromEvent(e); - } - }; - - this.#mouseUpHandler = e => { - if (!self.options.exitAnyButton || e.button == self.options.clickButton) { - if (this.options.consumeEvent) { - e.stopImmediatePropagation(); // Captured, don't call anyone else - } - // Remove the handlers of "mousemove" and "mouseup" - movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); - movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler); - document.removeEventListener("mouseup", self.#mouseUpHandler); - if (self.started) { - self.endDrag(); - } - self.unclicked(); - if (self.#trackingMouse) { - const dragEvent = self.getEvent(Configuration.trackingMouseEventName.end); - this.target.dispatchEvent(dragEvent); - self.#trackingMouse = false; - } - self.started = false; - } - }; - - this.listenEvents(); - } - - listenEvents() { - this.target.addEventListener("mousedown", this.#mouseDownHandler); - if (this.options.clickButton == 2) { - this.target.addEventListener("contextmenu", e => e.preventDefault()); - } - } - - unlistenEvents() { - this.target.removeEventListener("mousedown", this.#mouseDownHandler); - } - - getEvent(eventName) { - return new CustomEvent(eventName, { - detail: { - tracker: this - }, - bubbles: true, - cancelable: true - }) - } - - /* Subclasses will override the following methods */ - clicked(location) { - } - - startDrag(location) { - } - - dragTo(location, movement) { - } - - endDrag() { - } - - unclicked(location) { - } +// @ts-check + +/** + * @typedef {import("../../Blueprint").default} Blueprint + */ + +/** + * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses. + * @template {HTMLElement} T + * @extends {IPointing} + */ +class IMouseClickDrag extends IPointing { + + /** @type {(e: MouseEvent) => void} */ + #mouseDownHandler + + /** @type {(e: MouseEvent) => void} */ + #mouseStartedMovingHandler + + /** @type {(e: MouseEvent) => void} */ + #mouseMoveHandler + + /** @type {(e: MouseEvent) => void} */ + #mouseUpHandler + + #trackingMouse = false + + started = false + + constructor(target, blueprint, options = {}) { + options.clickButton ??= 0; + options.consumeEvent ??= true; + options.exitAnyButton ??= true; + options.looseTarget ??= false; + options.moveEverywhere ??= false; + super(target, blueprint, options); + this.clickedPosition = [0, 0]; + + const movementListenedElement = this.options.moveEverywhere ? document.documentElement : this.movementSpace; + let self = this; + + this.#mouseDownHandler = e => { + this.blueprint.setFocused(true); + switch (e.button) { + case self.options.clickButton: + // Either doesn't matter or consider the click only when clicking on the parent, not descandants + if (self.options.looseTarget || e.target == e.currentTarget) { + if (this.options.consumeEvent) { + e.stopImmediatePropagation(); // Captured, don't call anyone else + } + // Attach the listeners + movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler); + document.addEventListener("mouseup", self.#mouseUpHandler); + self.clickedPosition = self.locationFromEvent(e); + self.clicked(self.clickedPosition); + } + break + default: + if (!self.options.exitAnyButton) { + self.#mouseUpHandler(e); + } + break + } + }; + + this.#mouseStartedMovingHandler = e => { + if (this.options.consumeEvent) { + e.stopImmediatePropagation(); // Captured, don't call anyone else + } + // Delegate from now on to self.#mouseMoveHandler + movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); + movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler); + // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false + const dragEvent = self.getEvent(Configuration.trackingMouseEventName.begin); + self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false; + // Do actual actions + self.startDrag(); + self.started = true; + }; + + this.#mouseMoveHandler = e => { + if (this.options.consumeEvent) { + e.stopImmediatePropagation(); // Captured, don't call anyone else + } + const location = self.locationFromEvent(e); + const movement = [e.movementX, e.movementY]; + self.dragTo(location, movement); + if (self.#trackingMouse) { + self.blueprint.mousePosition = self.locationFromEvent(e); + } + }; + + this.#mouseUpHandler = e => { + if (!self.options.exitAnyButton || e.button == self.options.clickButton) { + if (this.options.consumeEvent) { + e.stopImmediatePropagation(); // Captured, don't call anyone else + } + // Remove the handlers of "mousemove" and "mouseup" + movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); + movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler); + document.removeEventListener("mouseup", self.#mouseUpHandler); + if (self.started) { + self.endDrag(); + } + self.unclicked(); + if (self.#trackingMouse) { + const dragEvent = self.getEvent(Configuration.trackingMouseEventName.end); + this.target.dispatchEvent(dragEvent); + self.#trackingMouse = false; + } + self.started = false; + } + }; + + this.listenEvents(); + } + + listenEvents() { + this.target.addEventListener("mousedown", this.#mouseDownHandler); + if (this.options.clickButton == 2) { + this.target.addEventListener("contextmenu", e => e.preventDefault()); + } + } + + unlistenEvents() { + this.target.removeEventListener("mousedown", this.#mouseDownHandler); + } + + getEvent(eventName) { + return new CustomEvent(eventName, { + detail: { + tracker: this + }, + bubbles: true, + cancelable: true + }) + } + + /* Subclasses will override the following methods */ + clicked(location) { + } + + startDrag(location) { + } + + dragTo(location, movement) { + } + + endDrag() { + } + + unclicked(location) { + } } // @ts-check @@ -1919,188 +1919,188 @@ class MouseTracking extends IPointing { } } -// @ts-check - -/** - * @typedef {import("../Blueprint").default} Blueprint - * @typedef {import("../entity/IEntity").default} IEntity - * @typedef {import("../input/IInput").default} IInput - * @typedef {import("../template/ITemplate").default} ITemplate - */ - -/** - * @template {IEntity} T - * @template {ITemplate} U - */ -class IElement extends HTMLElement { - - /** @type {Blueprint} */ - #blueprint - get blueprint() { - return this.#blueprint - } - set blueprint(blueprint) { - this.#blueprint = blueprint; - } - - /** @type {T} */ - #entity - get entity() { - return this.#entity - } - set entity(entity) { - this.#entity = entity; - } - - /** @type {U} */ - #template - get template() { - return this.#template - } - set template(template) { - this.#template = template; - } - - /** @type {IInput[]} */ - inputObjects = [] - - /** - * @param {T} entity - * @param {U} template - */ - constructor(entity, template) { - super(); - this.#entity = entity; - this.#template = template; - this.inputObjects = []; - } - - getTemplate() { - return this.template - } - - connectedCallback() { - this.#blueprint = this.closest("ueb-blueprint"); - this.template.setup(this); - this.template.inputSetup(this); - } - - disconnectedCallback() { - this.template.cleanup(this); - } - - /** - * @param {IElement} element - */ - isSameGraph(element) { - return this.#blueprint && this.#blueprint == element?.blueprint - } - - /** - * @template {IInput} V - * @param {new (...args: any[]) => V} type - * @returns {V} - */ - getInputObject(type) { - return /** @type {V} */ (this.template.inputObjects.find(object => object.constructor == type)) - } - - // Subclasses will want to override - createInputObjects() { - return [] - } +// @ts-check + +/** + * @typedef {import("../Blueprint").default} Blueprint + * @typedef {import("../entity/IEntity").default} IEntity + * @typedef {import("../input/IInput").default} IInput + * @typedef {import("../template/ITemplate").default} ITemplate + */ + +/** + * @template {IEntity} T + * @template {ITemplate} U + */ +class IElement extends HTMLElement { + + /** @type {Blueprint} */ + #blueprint + get blueprint() { + return this.#blueprint + } + set blueprint(blueprint) { + this.#blueprint = blueprint; + } + + /** @type {T} */ + #entity + get entity() { + return this.#entity + } + set entity(entity) { + this.#entity = entity; + } + + /** @type {U} */ + #template + get template() { + return this.#template + } + set template(template) { + this.#template = template; + } + + /** @type {IInput[]} */ + inputObjects = [] + + /** + * @param {T} entity + * @param {U} template + */ + constructor(entity, template) { + super(); + this.#entity = entity; + this.#template = template; + this.inputObjects = []; + } + + getTemplate() { + return this.template + } + + connectedCallback() { + this.#blueprint = this.closest("ueb-blueprint"); + this.template.setup(this); + this.template.inputSetup(this); + } + + disconnectedCallback() { + this.template.cleanup(this); + } + + /** + * @param {IElement} element + */ + isSameGraph(element) { + return this.#blueprint && this.#blueprint == element?.blueprint + } + + /** + * @template {IInput} V + * @param {new (...args: any[]) => V} type + * @returns {V} + */ + getInputObject(type) { + return /** @type {V} */ (this.template.inputObjects.find(object => object.constructor == type)) + } + + // Subclasses will want to override + createInputObjects() { + return [] + } } -// @ts-check - -/** - * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate - * @typedef {import("../entity/IEntity").default} IEntity - */ - -/** - * @template {IEntity} T - * @template {SelectableDraggableTemplate} U - * @extends {IElement} - */ -class ISelectableDraggableElement extends IElement { - - constructor(...args) { - // @ts-expect-error - super(...args); - this.dragObject = null; - this.location = [0, 0]; - this.selected = false; - - let self = this; - this.dragHandler = (e) => { - self.addLocation(e.detail.value); - }; - } - - #setSelected(value = true) { - this.selected = value; - if (this.blueprint) { - if (this.selected) { - this.blueprint.addEventListener(Configuration.nodeDragEventName, this.dragHandler); - } else { - this.blueprint.removeEventListener(Configuration.nodeDragEventName, this.dragHandler); - } - } - this.template.applySelected(this); - } - - connectedCallback() { - super.connectedCallback(); - this.#setSelected(this.selected); - } - - /** - * @param {Number[]} value - */ - setLocation(value = [0, 0]) { - const d = [value[0] - this.location[0], value[1] - this.location[1]]; - this.location = value; - this.template.applyLocation(this); - if (this.blueprint) { - const dragLocalEvent = new CustomEvent(Configuration.nodeDragLocalEventName, { - detail: { - value: d - }, - bubbles: false, - cancelable: true - }); - this.dispatchEvent(dragLocalEvent); - } - } - - addLocation(value) { - this.setLocation([this.location[0] + value[0], this.location[1] + value[1]]); - } - - setSelected(value = true) { - if (this.selected != value) { - this.#setSelected(value); - } - } - - dispatchDragEvent(value) { - const dragEvent = new CustomEvent(Configuration.nodeDragEventName, { - detail: { - value: value - }, - bubbles: true, - cancelable: true - }); - this.dispatchEvent(dragEvent); - } - - snapToGrid() { - let snappedLocation = Utility.snapToGrid(this.location, Configuration.gridSize); - if (this.location[0] != snappedLocation[0] || this.location[1] != snappedLocation[1]) { - this.setLocation(snappedLocation); - } - } +// @ts-check + +/** + * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate + * @typedef {import("../entity/IEntity").default} IEntity + */ + +/** + * @template {IEntity} T + * @template {SelectableDraggableTemplate} U + * @extends {IElement} + */ +class ISelectableDraggableElement extends IElement { + + constructor(...args) { + // @ts-expect-error + super(...args); + this.dragObject = null; + this.location = [0, 0]; + this.selected = false; + + let self = this; + this.dragHandler = (e) => { + self.addLocation(e.detail.value); + }; + } + + #setSelected(value = true) { + this.selected = value; + if (this.blueprint) { + if (this.selected) { + this.blueprint.addEventListener(Configuration.nodeDragEventName, this.dragHandler); + } else { + this.blueprint.removeEventListener(Configuration.nodeDragEventName, this.dragHandler); + } + } + this.template.applySelected(this); + } + + connectedCallback() { + super.connectedCallback(); + this.#setSelected(this.selected); + } + + /** + * @param {Number[]} value + */ + setLocation(value = [0, 0]) { + const d = [value[0] - this.location[0], value[1] - this.location[1]]; + this.location = value; + this.template.applyLocation(this); + if (this.blueprint) { + const dragLocalEvent = new CustomEvent(Configuration.nodeDragLocalEventName, { + detail: { + value: d + }, + bubbles: false, + cancelable: true + }); + this.dispatchEvent(dragLocalEvent); + } + } + + addLocation(value) { + this.setLocation([this.location[0] + value[0], this.location[1] + value[1]]); + } + + setSelected(value = true) { + if (this.selected != value) { + this.#setSelected(value); + } + } + + dispatchDragEvent(value) { + const dragEvent = new CustomEvent(Configuration.nodeDragEventName, { + detail: { + value: value + }, + bubbles: true, + cancelable: true + }); + this.dispatchEvent(dragEvent); + } + + snapToGrid() { + let snappedLocation = Utility.snapToGrid(this.location, Configuration.gridSize); + if (this.location[0] != snappedLocation[0] || this.location[1] != snappedLocation[1]) { + this.setLocation(snappedLocation); + } + } } // @ts-check @@ -2296,311 +2296,311 @@ class LinkTemplate extends ITemplate { } } -// @ts-check - -/** - * @typedef {import("./PinElement").default} PinElement - * @typedef {import("./LinkMessageElement").default} LinkMessageElement - * @typedef {import("../entity/IEntity").default} IEntity - */ - -/** - * @extends {IElement} - */ -class LinkElement extends IElement { - - /** @type {PinElement} */ - #source - get sourcePin() { - return this.#source - } - set sourcePin(pin) { - if (this.#source == pin) { - return - } - if (this.#source) { - const nodeElement = this.#source.getNodeElement(); - nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); - nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler); - if (this.#destination) { - this.#unlinkPins(); - } - } - this.#source = pin; - if (this.#source) { - const nodeElement = this.#source.getNodeElement(); - this.originatesFromInput = pin.isInput(); - nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); - nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler); - this.setSourceLocation(); - if (this.#destination) { - this.#linkPins(); - } - } - this.template.applyPins(this); - } - - /** @type {PinElement} */ - #destination - get destinationPin() { - return this.#destination - } - set destinationPin(pin) { - if (this.#destination == pin) { - return - } - if (this.#destination) { - const nodeElement = this.#destination.getNodeElement(); - nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); - nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler); - if (this.#source) { - this.#unlinkPins(); - } - } - this.#destination = pin; - if (this.#destination) { - const nodeElement = this.#destination.getNodeElement(); - nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); - nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler); - this.setDestinationLocation(); - if (this.#source) { - this.#linkPins(); - } - } - this.template.applyPins(this); - } - - #nodeDeleteHandler - #nodeDragSourceHandler - #nodeDragDestinatonHandler - sourceLocation = [0, 0] - /** @type {SVGPathElement} */ - pathElement - /** @type {LinkMessageElement} */ - linkMessageElement - originatesFromInput = false - destinationLocation = [0, 0] - - /** - * @param {PinElement} source - * @param {PinElement} destination - */ - constructor(source, destination) { - super({}, new LinkTemplate()); - const self = this; - this.#nodeDeleteHandler = _ => self.remove(); - this.#nodeDragSourceHandler = e => self.addSourceLocation(e.detail.value); - this.#nodeDragDestinatonHandler = e => self.addDestinationLocation(e.detail.value); - if (source) { - this.sourcePin = source; - } - if (destination) { - this.destinationPin = destination; - } - if (source && destination) { - this.#linkPins(); - } - } - - #linkPins() { - this.#source.linkTo(this.#destination); - this.#destination.linkTo(this.#source); - } - - #unlinkPins() { - if (this.#source && this.#destination) { - this.#source.unlinkFrom(this.#destination); - this.#destination.unlinkFrom(this.#source); - } - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.#unlinkPins(); - } - - /** - * @returns {Number[]} - */ - getSourceLocation() { - return this.sourceLocation - } - - /** - * @param {Number[]} offset - */ - addSourceLocation(offset) { - const location = [ - this.sourceLocation[0] + offset[0], - this.sourceLocation[1] + offset[1] - ]; - this.sourceLocation = location; - this.template.applyFullLocation(this); - } - - /** - * @param {Number[]} location - */ - setSourceLocation(location = null) { - if (location == null) { - location = this.#source.template.getLinkLocation(this.#source); - } - this.sourceLocation = location; - this.template.applySourceLocation(this); - } - - getDestinationLocation() { - return this.destinationLocation - } - - /** - * @param {Number[]} offset - */ - addDestinationLocation(offset) { - const location = [ - this.destinationLocation[0] + offset[0], - this.destinationLocation[1] + offset[1] - ]; - this.setDestinationLocation(location); - } - - /** - * @param {Number[]} location - */ - setDestinationLocation(location = null) { - if (location == null) { - location = this.#destination.template.getLinkLocation(this.#destination); - } - this.destinationLocation = location; - this.template.applyFullLocation(this); - } - - /** - * @param {LinkMessageElement} linkMessage - */ - setLinkMessage(linkMessage) { - if (linkMessage) { - this.template.applyLinkMessage(this, linkMessage); - } else if (this.linkMessageElement) { - this.linkMessageElement.remove(); - this.linkMessageElement = null; - } - } - - startDragging() { - this.template.applyStartDragging(this); - } - - finishDragging() { - this.template.applyFinishDragging(this); - } -} - -customElements.define("ueb-link", LinkElement); +// @ts-check + +/** + * @typedef {import("./PinElement").default} PinElement + * @typedef {import("./LinkMessageElement").default} LinkMessageElement + * @typedef {import("../entity/IEntity").default} IEntity + */ + +/** + * @extends {IElement} + */ +class LinkElement extends IElement { + + /** @type {PinElement} */ + #source + get sourcePin() { + return this.#source + } + set sourcePin(pin) { + if (this.#source == pin) { + return + } + if (this.#source) { + const nodeElement = this.#source.getNodeElement(); + nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); + nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler); + if (this.#destination) { + this.#unlinkPins(); + } + } + this.#source = pin; + if (this.#source) { + const nodeElement = this.#source.getNodeElement(); + this.originatesFromInput = pin.isInput(); + nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); + nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler); + this.setSourceLocation(); + if (this.#destination) { + this.#linkPins(); + } + } + this.template.applyPins(this); + } + + /** @type {PinElement} */ + #destination + get destinationPin() { + return this.#destination + } + set destinationPin(pin) { + if (this.#destination == pin) { + return + } + if (this.#destination) { + const nodeElement = this.#destination.getNodeElement(); + nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); + nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler); + if (this.#source) { + this.#unlinkPins(); + } + } + this.#destination = pin; + if (this.#destination) { + const nodeElement = this.#destination.getNodeElement(); + nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler); + nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler); + this.setDestinationLocation(); + if (this.#source) { + this.#linkPins(); + } + } + this.template.applyPins(this); + } + + #nodeDeleteHandler + #nodeDragSourceHandler + #nodeDragDestinatonHandler + sourceLocation = [0, 0] + /** @type {SVGPathElement} */ + pathElement + /** @type {LinkMessageElement} */ + linkMessageElement + originatesFromInput = false + destinationLocation = [0, 0] + + /** + * @param {PinElement} source + * @param {PinElement} destination + */ + constructor(source, destination) { + super({}, new LinkTemplate()); + const self = this; + this.#nodeDeleteHandler = _ => self.remove(); + this.#nodeDragSourceHandler = e => self.addSourceLocation(e.detail.value); + this.#nodeDragDestinatonHandler = e => self.addDestinationLocation(e.detail.value); + if (source) { + this.sourcePin = source; + } + if (destination) { + this.destinationPin = destination; + } + if (source && destination) { + this.#linkPins(); + } + } + + #linkPins() { + this.#source.linkTo(this.#destination); + this.#destination.linkTo(this.#source); + } + + #unlinkPins() { + if (this.#source && this.#destination) { + this.#source.unlinkFrom(this.#destination); + this.#destination.unlinkFrom(this.#source); + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#unlinkPins(); + } + + /** + * @returns {Number[]} + */ + getSourceLocation() { + return this.sourceLocation + } + + /** + * @param {Number[]} offset + */ + addSourceLocation(offset) { + const location = [ + this.sourceLocation[0] + offset[0], + this.sourceLocation[1] + offset[1] + ]; + this.sourceLocation = location; + this.template.applyFullLocation(this); + } + + /** + * @param {Number[]} location + */ + setSourceLocation(location = null) { + if (location == null) { + location = this.#source.template.getLinkLocation(this.#source); + } + this.sourceLocation = location; + this.template.applySourceLocation(this); + } + + getDestinationLocation() { + return this.destinationLocation + } + + /** + * @param {Number[]} offset + */ + addDestinationLocation(offset) { + const location = [ + this.destinationLocation[0] + offset[0], + this.destinationLocation[1] + offset[1] + ]; + this.setDestinationLocation(location); + } + + /** + * @param {Number[]} location + */ + setDestinationLocation(location = null) { + if (location == null) { + location = this.#destination.template.getLinkLocation(this.#destination); + } + this.destinationLocation = location; + this.template.applyFullLocation(this); + } + + /** + * @param {LinkMessageElement} linkMessage + */ + setLinkMessage(linkMessage) { + if (linkMessage) { + this.template.applyLinkMessage(this, linkMessage); + } else if (this.linkMessageElement) { + this.linkMessageElement.remove(); + this.linkMessageElement = null; + } + } + + startDragging() { + this.template.applyStartDragging(this); + } + + finishDragging() { + this.template.applyFinishDragging(this); + } +} + +customElements.define("ueb-link", LinkElement); + +// @ts-check + +/** + * @typedef {import("../element/LinkMessageElement").default} LinkMessageElement + */ + +class LinkMessageTemplate extends ITemplate { + + /** + * @param {LinkMessageElement} linkMessage + */ + render(linkMessage) { + return html` + + + ` + } + + /** + * Applies the style to the element. + * @param {LinkMessageElement} linkMessage + */ + setup(linkMessage) { + super.setup(linkMessage); + const linkMessageSetup = _ => + /** @type {HTMLElement} */(linkMessage.querySelector(".ueb-link-message")).innerText = linkMessage.message( + linkMessage.linkElement.sourcePin, + linkMessage.linkElement.destinationPin + ); + linkMessage.linkElement = linkMessage.closest("ueb-link"); + if (linkMessage.linkElement) { + linkMessageSetup(); + } else { + window.customElements.whenDefined("ueb-link-message").then(linkMessageSetup); + } + } + +} + +// @ts-check + +/** + * @typedef {import("./PinElement").default} PinElement + * @typedef {import("./LinkElement").default} LinkElement + * @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval + */ + +/** + * @extends {IElement} + */ +class LinkMessageElement extends IElement { + + static convertType = _ => new LinkMessageElement( + "ueb-icon-conver-type", + /** @type {LinkRetrieval} */ + (s, d) => `Convert ${s.getType()} to ${d.getType()}.` + ) + static correct = _ => new LinkMessageElement( + "ueb-icon-correct", + /** @type {LinkRetrieval} */ + (s, d) => "" + ) + static directionsIncompatible = _ => new LinkMessageElement( + "ueb-icon-directions-incompatible", + /** @type {LinkRetrieval} */ + (s, d) => "Directions are not compatbile." + ) + static placeNode = _ => new LinkMessageElement( + "ueb-icon-place-node", + /** @type {LinkRetrieval} */ + (s, d) => "Place a new node." + ) + static replaceLink = _ => new LinkMessageElement( + "ueb-icon-replace-link", + /** @type {LinkRetrieval} */ + (s, d) => "Replace existing input connections." + ) + static sameNode = _ => new LinkMessageElement( + "ueb-icon-same-node", + /** @type {LinkRetrieval} */ + (s, d) => "Both are on the same node." + ) + static typesIncompatible = _ => new LinkMessageElement( + "ueb-icon-types-incompatible", + /** @type {LinkRetrieval} */ + (s, d) => `${s.getType()} is not compatible with ${d.getType()}.` + ) + + /** @type {String} */ + icon + /** @type {LinkRetrieval} */ + message + /** @type {LinkElement} */ + linkElement + + constructor(icon, message) { + super({}, new LinkMessageTemplate()); + this.icon = icon; + this.message = message; + } -// @ts-check - -/** - * @typedef {import("../element/LinkMessageElement").default} LinkMessageElement - */ - -class LinkMessageTemplate extends ITemplate { - - /** - * @param {LinkMessageElement} linkMessage - */ - render(linkMessage) { - return html` - - - ` - } - - /** - * Applies the style to the element. - * @param {LinkMessageElement} linkMessage - */ - setup(linkMessage) { - super.setup(linkMessage); - const linkMessageSetup = _ => - /** @type {HTMLElement} */(linkMessage.querySelector(".ueb-link-message")).innerText = linkMessage.message( - linkMessage.linkElement.sourcePin, - linkMessage.linkElement.destinationPin - ); - linkMessage.linkElement = linkMessage.closest("ueb-link"); - if (linkMessage.linkElement) { - linkMessageSetup(); - } else { - window.customElements.whenDefined("ueb-link-message").then(linkMessageSetup); - } - } - } -// @ts-check - -/** - * @typedef {import("./PinElement").default} PinElement - * @typedef {import("./LinkElement").default} LinkElement - * @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval - */ - -/** - * @extends {IElement} - */ -class LinkMessageElement extends IElement { - - static convertType = _ => new LinkMessageElement( - "ueb-icon-conver-type", - /** @type {LinkRetrieval} */ - (s, d) => `Convert ${s.getType()} to ${d.getType()}.` - ) - static correct = _ => new LinkMessageElement( - "ueb-icon-correct", - /** @type {LinkRetrieval} */ - (s, d) => "" - ) - static directionsIncompatible = _ => new LinkMessageElement( - "ueb-icon-directions-incompatible", - /** @type {LinkRetrieval} */ - (s, d) => "Directions are not compatbile." - ) - static placeNode = _ => new LinkMessageElement( - "ueb-icon-place-node", - /** @type {LinkRetrieval} */ - (s, d) => "Place a new node." - ) - static replaceLink = _ => new LinkMessageElement( - "ueb-icon-replace-link", - /** @type {LinkRetrieval} */ - (s, d) => "Replace existing input connections." - ) - static sameNode = _ => new LinkMessageElement( - "ueb-icon-same-node", - /** @type {LinkRetrieval} */ - (s, d) => "Both are on the same node." - ) - static typesIncompatible = _ => new LinkMessageElement( - "ueb-icon-types-incompatible", - /** @type {LinkRetrieval} */ - (s, d) => `${s.getType()} is not compatible with ${d.getType()}.` - ) - - /** @type {String} */ - icon - /** @type {LinkRetrieval} */ - message - /** @type {LinkElement} */ - linkElement - - constructor(icon, message) { - super({}, new LinkMessageTemplate()); - this.icon = icon; - this.message = message; - } - -} - customElements.define("ueb-link-message", LinkMessageElement); // @ts-check @@ -2809,265 +2809,265 @@ class PinTemplate extends ITemplate { } } -// @ts-check - -/** - * @typedef {import("../element/PinElement").default} PinElement - */ - -class ExecPinTemplate extends PinTemplate { - - /** - * @param {PinElement} pin - */ - renderIcon(pin) { - return html` - - - - ` - } +// @ts-check + +/** + * @typedef {import("../element/PinElement").default} PinElement + */ + +class ExecPinTemplate extends PinTemplate { + + /** + * @param {PinElement} pin + */ + renderIcon(pin) { + return html` + + + + ` + } } -/** - * @typedef {import("../../element/PinElement").default} PinElement - */ - -/** - * @extends IMouseClickDrag - */ -class MouseIgnore extends IMouseClickDrag { - - constructor(target, blueprint, options = {}) { - options.consumeEvent = true; - super(target, blueprint, options); - } +/** + * @typedef {import("../../element/PinElement").default} PinElement + */ + +/** + * @extends IMouseClickDrag + */ +class MouseIgnore extends IMouseClickDrag { + + constructor(target, blueprint, options = {}) { + options.consumeEvent = true; + super(target, blueprint, options); + } } -// @ts-check - -/** - * @typedef {import("../element/PinElement").default} PinElement - */ - -class StringPinTemplate extends PinTemplate { - - /** @type {HTMLElement} */ - input = null - - hasInput() { - return true - } - - /** - * @param {PinElement} pin - */ - renderInput(pin) { - if (pin.isInput()) { - return html` -
-
-
- ` - } - return "" - } - - /** - * @param {PinElement} pin - */ - setup(pin) { - super.setup(pin); - if (this.input = pin.querySelector(".ueb-pin-input-content")) { - this.onFocusHandler = (e) => { - pin.blueprint.dispatchEditTextEvent(true); - }; - this.onFocusOutHandler = (e) => { - e.preventDefault(); - document.getSelection().removeAllRanges(); // Deselect text inside the input - pin.blueprint.dispatchEditTextEvent(false); - }; - this.input.addEventListener("focus", this.onFocusHandler); - this.input.addEventListener("focusout", this.onFocusOutHandler); - } - } - - /** - * @param {PinElement} pin - */ - cleanup(pin) { - super.cleanup(pin); - if (this.input) { - this.input.removeEventListener("focus", this.onFocusHandler); - this.input.removeEventListener("focusout", this.onFocusOutHandler); - } - } - - /** - * @param {PinElement} pin - */ - createInputObjects(pin) { - if (pin.isInput()) { - return [ - ...super.createInputObjects(pin), - new MouseIgnore(pin.querySelector(".ueb-pin-input-content"), pin.blueprint), - ] - } - return super.createInputObjects(pin) - } +// @ts-check + +/** + * @typedef {import("../element/PinElement").default} PinElement + */ + +class StringPinTemplate extends PinTemplate { + + /** @type {HTMLElement} */ + input = null + + hasInput() { + return true + } + + /** + * @param {PinElement} pin + */ + renderInput(pin) { + if (pin.isInput()) { + return html` +
+
+
+ ` + } + return "" + } + + /** + * @param {PinElement} pin + */ + setup(pin) { + super.setup(pin); + if (this.input = pin.querySelector(".ueb-pin-input-content")) { + this.onFocusHandler = (e) => { + pin.blueprint.dispatchEditTextEvent(true); + }; + this.onFocusOutHandler = (e) => { + e.preventDefault(); + document.getSelection().removeAllRanges(); // Deselect text inside the input + pin.blueprint.dispatchEditTextEvent(false); + }; + this.input.addEventListener("focus", this.onFocusHandler); + this.input.addEventListener("focusout", this.onFocusOutHandler); + } + } + + /** + * @param {PinElement} pin + */ + cleanup(pin) { + super.cleanup(pin); + if (this.input) { + this.input.removeEventListener("focus", this.onFocusHandler); + this.input.removeEventListener("focusout", this.onFocusOutHandler); + } + } + + /** + * @param {PinElement} pin + */ + createInputObjects(pin) { + if (pin.isInput()) { + return [ + ...super.createInputObjects(pin), + new MouseIgnore(pin.querySelector(".ueb-pin-input-content"), pin.blueprint), + ] + } + return super.createInputObjects(pin) + } +} + +// @ts-check + +/** + * @typedef {import("../entity/GuidEntity").default} GuidEntity + * @typedef {import("../entity/PinEntity").default} PinEntity + * @typedef {import("../entity/PinReferenceEntity").default} PinReferenceEntity + * @typedef {import("./NodeElement").default} NodeElement + */ + +/** + * @extends {IElement} + */ +class PinElement extends IElement { + + static #typeTemplateMap = { + "exec": ExecPinTemplate, + "string": StringPinTemplate, + } + + #color = "" + + /** @type {NodeElement} */ + nodeElement + + /** @type {HTMLElement} */ + clickableElement + + connections = 0 + + constructor(entity) { + super( + entity, + new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)() + ); + } + + connectedCallback() { + super.connectedCallback(); + this.#color = window.getComputedStyle(this).getPropertyValue("--ueb-pin-color"); + } + + /** @return {GuidEntity} */ + GetPinId() { + return this.entity.PinId + } + + /** @return {String} */ + GetPinIdValue() { + return this.GetPinId().value + } + + /** + * @returns {String} + */ + getPinName() { + return this.entity.PinName + } + + /** + * @returns {String} + */ + getPinDisplayName() { + return this.entity.PinName + } + + isInput() { + return this.entity.isInput() + } + + isOutput() { + return this.entity.isOutput() + } + + isLinked() { + return this.entity.isLinked() + } + + getType() { + return this.entity.getType() + } + + getClickableElement() { + return this.clickableElement + } + + getColor() { + return this.#color + } + + getLinkLocation() { + return this.template.getLinkLocation(this) + } + + /** + * @returns {NodeElement} + */ + getNodeElement() { + return this.closest("ueb-node") + } + + getLinks() { + return this.entity.LinkedTo ?? [] + } + + sanitizeLinks() { + this.entity.LinkedTo = this.getLinks().filter(pinReference => { + let pin = this.blueprint.getPin(pinReference); + if (pin) { + let link = this.blueprint.getLink(this, pin, true); + if (!link) { + this.blueprint.addGraphElement(new LinkElement(this, pin)); + } + } + return pin + }); + } + + /** + * @param {PinElement} targetPinElement + */ + linkTo(targetPinElement) { + this.entity.linkTo(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity); + this.template.applyConnected(this); + } + + /** + * @param {PinElement} targetPinElement + */ + unlinkFrom(targetPinElement) { + this.entity.unlinkFrom(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity); + this.template.applyConnected(this); + } + + /** + * + * @param {PinElement} originalPinElement + * @param {PinReferenceEntity} newReference + */ + redirectLink(originalPinElement, newReference) { + const index = this.entity.LinkedTo.findIndex(pinReference => + pinReference.objectName.toString() == originalPinElement.getPinName() + && pinReference.pinGuid == originalPinElement.entity.PinId + ); + if (index >= 0) { + this.entity.LinkedTo[index] = newReference; + return true + } + return false + } } -// @ts-check - -/** - * @typedef {import("../entity/GuidEntity").default} GuidEntity - * @typedef {import("../entity/PinEntity").default} PinEntity - * @typedef {import("../entity/PinReferenceEntity").default} PinReferenceEntity - * @typedef {import("./NodeElement").default} NodeElement - */ - -/** - * @extends {IElement} - */ -class PinElement extends IElement { - - static #typeTemplateMap = { - "exec": ExecPinTemplate, - "string": StringPinTemplate, - } - - #color = "" - - /** @type {NodeElement} */ - nodeElement - - /** @type {HTMLElement} */ - clickableElement - - connections = 0 - - constructor(entity) { - super( - entity, - new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)() - ); - } - - connectedCallback() { - super.connectedCallback(); - this.#color = window.getComputedStyle(this).getPropertyValue("--ueb-pin-color"); - } - - /** @return {GuidEntity} */ - GetPinId() { - return this.entity.PinId - } - - /** @return {String} */ - GetPinIdValue() { - return this.GetPinId().value - } - - /** - * @returns {String} - */ - getPinName() { - return this.entity.PinName - } - - /** - * @returns {String} - */ - getPinDisplayName() { - return this.entity.PinName - } - - isInput() { - return this.entity.isInput() - } - - isOutput() { - return this.entity.isOutput() - } - - isLinked() { - return this.entity.isLinked() - } - - getType() { - return this.entity.getType() - } - - getClickableElement() { - return this.clickableElement - } - - getColor() { - return this.#color - } - - getLinkLocation() { - return this.template.getLinkLocation(this) - } - - /** - * @returns {NodeElement} - */ - getNodeElement() { - return this.closest("ueb-node") - } - - getLinks() { - return this.entity.LinkedTo ?? [] - } - - sanitizeLinks() { - this.entity.LinkedTo = this.getLinks().filter(pinReference => { - let pin = this.blueprint.getPin(pinReference); - if (pin) { - let link = this.blueprint.getLink(this, pin, true); - if (!link) { - this.blueprint.addGraphElement(new LinkElement(this, pin)); - } - } - return pin - }); - } - - /** - * @param {PinElement} targetPinElement - */ - linkTo(targetPinElement) { - this.entity.linkTo(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity); - this.template.applyConnected(this); - } - - /** - * @param {PinElement} targetPinElement - */ - unlinkFrom(targetPinElement) { - this.entity.unlinkFrom(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity); - this.template.applyConnected(this); - } - - /** - * - * @param {PinElement} originalPinElement - * @param {PinReferenceEntity} newReference - */ - redirectLink(originalPinElement, newReference) { - const index = this.entity.LinkedTo.findIndex(pinReference => - pinReference.objectName.toString() == originalPinElement.getPinName() - && pinReference.pinGuid == originalPinElement.entity.PinId - ); - if (index >= 0) { - this.entity.LinkedTo[index] = newReference; - return true - } - return false - } -} - customElements.define("ueb-pin", PinElement); // @ts-check @@ -3190,12 +3190,12 @@ class NodeTemplate extends SelectableDraggableTemplate {
- +
${sanitizeText(node.getNodeName())} - +
@@ -3254,93 +3254,93 @@ class NodeTemplate extends SelectableDraggableTemplate { } } -// @ts-check - -/** - * @extends {ISelectableDraggableElement} - */ -class NodeElement extends ISelectableDraggableElement { - - /** - * @param {ObjectEntity} entity - */ - constructor(entity) { - super(entity, new NodeTemplate()); - this.dragLinkObjects = []; - super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]); - } - - static fromSerializedObject(str) { - let entity = SerializerFactory.getSerializer(ObjectEntity).read(str); - return new NodeElement(entity) - } - - connectedCallback() { - this.getAttribute("type")?.trim(); - super.connectedCallback(); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.dispatchDeleteEvent(); - } - - getNodeName() { - return this.entity.getFullName() - } - - sanitizeLinks() { - this.getPinElements().forEach(pin => pin.sanitizeLinks()); - } - - /** - * @param {String} name - */ - rename(name) { - if (this.entity.Name == name) { - return false - } - for (let sourcePinElement of this.getPinElements()) { - for (let targetPinReference of sourcePinElement.getLinks()) { - this.blueprint.getPin(targetPinReference).redirectLink(sourcePinElement, new PinReferenceEntity({ - objectName: name, - pinGuid: sourcePinElement.entity.PinId, - })); - } - } - this.entity.Name = name; - this.template.applyRename(this); - } - - getPinElements() { - return this.template.getPinElements(this) - } - - /** - * @returns {PinEntity[]} - */ - getPinEntities() { - return this.entity.CustomProperties.filter(v => v instanceof PinEntity) - } - - setLocation(value = [0, 0]) { - let nodeType = this.entity.NodePosX.constructor; - // @ts-expect-error - this.entity.NodePosX = new nodeType(value[0]); - // @ts-expect-error - this.entity.NodePosY = new nodeType(value[1]); - super.setLocation(value); - } - - dispatchDeleteEvent(value) { - let deleteEvent = new CustomEvent(Configuration.nodeDeleteEventName, { - bubbles: true, - cancelable: true, - }); - this.dispatchEvent(deleteEvent); - } -} - +// @ts-check + +/** + * @extends {ISelectableDraggableElement} + */ +class NodeElement extends ISelectableDraggableElement { + + /** + * @param {ObjectEntity} entity + */ + constructor(entity) { + super(entity, new NodeTemplate()); + this.dragLinkObjects = []; + super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]); + } + + static fromSerializedObject(str) { + let entity = SerializerFactory.getSerializer(ObjectEntity).read(str); + return new NodeElement(entity) + } + + connectedCallback() { + this.getAttribute("type")?.trim(); + super.connectedCallback(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.dispatchDeleteEvent(); + } + + getNodeName() { + return this.entity.getFullName() + } + + sanitizeLinks() { + this.getPinElements().forEach(pin => pin.sanitizeLinks()); + } + + /** + * @param {String} name + */ + rename(name) { + if (this.entity.Name == name) { + return false + } + for (let sourcePinElement of this.getPinElements()) { + for (let targetPinReference of sourcePinElement.getLinks()) { + this.blueprint.getPin(targetPinReference).redirectLink(sourcePinElement, new PinReferenceEntity({ + objectName: name, + pinGuid: sourcePinElement.entity.PinId, + })); + } + } + this.entity.Name = name; + this.template.applyRename(this); + } + + getPinElements() { + return this.template.getPinElements(this) + } + + /** + * @returns {PinEntity[]} + */ + getPinEntities() { + return this.entity.CustomProperties.filter(v => v instanceof PinEntity) + } + + setLocation(value = [0, 0]) { + let nodeType = this.entity.NodePosX.constructor; + // @ts-expect-error + this.entity.NodePosX = new nodeType(value[0]); + // @ts-expect-error + this.entity.NodePosY = new nodeType(value[1]); + super.setLocation(value); + } + + dispatchDeleteEvent(value) { + let deleteEvent = new CustomEvent(Configuration.nodeDeleteEventName, { + bubbles: true, + cancelable: true, + }); + this.dispatchEvent(deleteEvent); + } +} + customElements.define("ueb-node", NodeElement); // @ts-check @@ -3784,40 +3784,40 @@ class SelectorTemplate extends ITemplate { } } -// @ts-check - -/** - * @extends {IElement} - */ -class SelectorElement extends IElement { - - constructor() { - super({}, new SelectorTemplate()); - this.selectionModel = null; - } - - /** - * @param {Number[]} initialPosition - */ - startSelecting(initialPosition) { - this.template.applyStartSelecting(this, initialPosition); - this.selectionModel = new FastSelectionModel(initialPosition, this.blueprint.getNodes(), this.blueprint.nodeBoundariesSupplier, this.blueprint.nodeSelectToggleFunction); - } - - /** - * @param {Number[]} finalPosition - */ - doSelecting(finalPosition) { - this.template.applyDoSelecting(this, finalPosition); - this.selectionModel.selectTo(finalPosition); - } - - finishSelecting() { - this.template.applyFinishSelecting(this); - this.selectionModel = null; - } -} - +// @ts-check + +/** + * @extends {IElement} + */ +class SelectorElement extends IElement { + + constructor() { + super({}, new SelectorTemplate()); + this.selectionModel = null; + } + + /** + * @param {Number[]} initialPosition + */ + startSelecting(initialPosition) { + this.template.applyStartSelecting(this, initialPosition); + this.selectionModel = new FastSelectionModel(initialPosition, this.blueprint.getNodes(), this.blueprint.nodeBoundariesSupplier, this.blueprint.nodeSelectToggleFunction); + } + + /** + * @param {Number[]} finalPosition + */ + doSelecting(finalPosition) { + this.template.applyDoSelecting(this, finalPosition); + this.selectionModel.selectTo(finalPosition); + } + + finishSelecting() { + this.template.applyFinishSelecting(this); + this.selectionModel = null; + } +} + customElements.define("ueb-selector", SelectorElement); // @ts-check diff --git a/js/Configuration.js b/js/Configuration.js index 6aa9b7f..774349e 100755 --- a/js/Configuration.js +++ b/js/Configuration.js @@ -12,7 +12,7 @@ export default class Configuration { begin: "blueprint-focus", end: "blueprint-unfocus", } - static fontSize = "12px" + static fontSize = "12.5px" static gridAxisLineColor = "black" static gridExpandThreshold = 0.25 // remaining size factor threshold to cause an expansion event static gridLineColor = "#353535" diff --git a/js/template/NodeTemplate.js b/js/template/NodeTemplate.js index a3e514d..3079f27 100755 --- a/js/template/NodeTemplate.js +++ b/js/template/NodeTemplate.js @@ -21,12 +21,12 @@ export default class NodeTemplate extends SelectableDraggableTemplate {
- +
${sanitizeText(node.getNodeName())} - +
diff --git a/scss/ueb-node.scss b/scss/ueb-node.scss index f24797b..f094772 100644 --- a/scss/ueb-node.scss +++ b/scss/ueb-node.scss @@ -41,18 +41,18 @@ ueb-blueprint[data-drag-scrolling="false"][data-selecting="false"] ueb-node { .ueb-node-header { padding: 0.3em 0.7em; - box-shadow: inset 5px 1px 5px -3px #92c381, inset 0 1px 2px 0 #313631, inset 0 2px 0 0 #92c381; + box-shadow: inset 5px 1px 5px -3px #83b37b, + inset 0 1px 0 0 #111311, + inset 0 2px 0 0 #83b37b; border-radius: var(--ueb-node-radius) var(--ueb-node-radius) 0 0; background: linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%); color: #c0c0c0; - font-weight: 600; + font-weight: 900; white-space: nowrap; } .ueb-node-name { - display: inline-block; - min-width: 80%; - background: radial-gradient(ellipse 95% 60% at 20% 50%, rgba(0, 0, 0, 0.5) 0%, transparent 90%); + background: radial-gradient(ellipse 100% 100% at 30% 50%, rgba(0, 0, 0, 0.45) 20%, transparent 50%); margin: -0.1em -1.6em; padding: 0.1em 1.6em; } @@ -66,11 +66,12 @@ ueb-blueprint[data-drag-scrolling="false"][data-selecting="false"] ueb-node { } .ueb-node-inputs { - margin-right: auto; + margin-right: 20px; padding-left: 8px; } .ueb-node-outputs { + margin-left: auto; padding-right: 8px; } diff --git a/scss/ueb-pin.scss b/scss/ueb-pin.scss index 797fcff..4fb7ae7 100644 --- a/scss/ueb-pin.scss +++ b/scss/ueb-pin.scss @@ -30,10 +30,10 @@ ueb-blueprint[data-drag-scrolling="false"][data-selecting="false"] ueb-pin:hover .ueb-pin-icon-value { display: inline-block; position: relative; - width: 1em; - height: 1em; + width: calc(1em - 1px); + height: calc(1em - 1px); vertical-align: baseline; - margin: 0 0.4em -1px 0.1em; + margin: 0 0.5em -1px 0.1em; } .ueb-pin-icon-value::before { @@ -80,7 +80,7 @@ ueb-pin.ueb-pin-fill .ueb-pin-icon-value::before { margin-left: 3px; border: 1px solid #a0a0a0; border-radius: 3px; - padding: 1px 3px 1px 3px; + padding: 0 3px 0 3px; color: #c0c0c0; &:hover,