Add project files.
This commit is contained in:
253
Http/SkinEditor/app.css
Normal file
253
Http/SkinEditor/app.css
Normal file
@@ -0,0 +1,253 @@
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#toolbar {
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tgbtn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tgbtn-active {
|
||||
background-color: lightblue;
|
||||
}
|
||||
|
||||
.tgbtn:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
#toolbar .tgbtn {
|
||||
min-width: 64px;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
border-right: solid 1px gray;
|
||||
}
|
||||
|
||||
#treeview {
|
||||
height: calc(100% - 32px);
|
||||
}
|
||||
|
||||
#tree {
|
||||
overflow: auto;
|
||||
height: calc(100% - 10px);
|
||||
}
|
||||
|
||||
.t-list {
|
||||
position: absolute;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
overflow: auto;
|
||||
background-color: floralwhite;
|
||||
border: solid 1px gray;
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.t-li {
|
||||
list-style: none;
|
||||
padding: 0 4px;
|
||||
margin: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.t-li:hover {
|
||||
background-color: lightblue;
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
font-family: sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.t-node {
|
||||
padding: 1px 4px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.t-node, .t-node-sup {
|
||||
transition: 0.25s;
|
||||
}
|
||||
|
||||
.t-node.t-inline {
|
||||
padding: 0 2px;
|
||||
margin: 4px 2px;
|
||||
}
|
||||
|
||||
.t-internal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.t-literal {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 16px;
|
||||
height: 0px;
|
||||
font-size: small;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: 0.25s;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btn.t-inline {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.btn:only-child {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.btn.t-inline:only-child {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.t-statement > .btn {
|
||||
}
|
||||
|
||||
.t-node:hover > .btn {
|
||||
transition: 0.25s;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.t-node:hover > .btn.t-inline {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.btn-add {
|
||||
border: solid 1px green;
|
||||
}
|
||||
|
||||
.mode-hide-add .btn-add {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
border: solid 1px red;
|
||||
}
|
||||
|
||||
.mode-hide-delete .btn-delete {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.t-block {
|
||||
border-left: solid 1px darkcyan;
|
||||
}
|
||||
|
||||
.t-exp {
|
||||
border-top: solid 1px gray;
|
||||
}
|
||||
|
||||
.t-exp.t-inline {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.t-exp:hover {
|
||||
border-top: solid 3px gray;
|
||||
}
|
||||
|
||||
.t-input {
|
||||
display: inline-block;
|
||||
border: solid 1px magenta;
|
||||
}
|
||||
|
||||
.t-statement {
|
||||
border-left: solid 1px orange;
|
||||
}
|
||||
|
||||
.t-statement.t-inline {
|
||||
border: solid 1px orange;
|
||||
}
|
||||
|
||||
.t-node:hover {
|
||||
transition: 0.25s;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.t-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Debug Mode */
|
||||
.mode-debug .t-internal {
|
||||
display: block;
|
||||
background-color: lightgray;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Sort Mode */
|
||||
.mode-sort .t-internal {
|
||||
display: block;
|
||||
background-color: lightgray;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mode-sort input {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.mode-sort .t-node {
|
||||
border-color: lightgray;
|
||||
}
|
||||
|
||||
.mode-sort .t-statement {
|
||||
cursor: grab;
|
||||
padding-left: 10px;
|
||||
border-color: orange;
|
||||
border-left-width: 2px;
|
||||
}
|
||||
|
||||
.mode-sort .t-statement:hover {
|
||||
border-color: yellow;
|
||||
border-left-width: 5px;
|
||||
}
|
||||
|
||||
.mode-sort .t-statement.t-inline {
|
||||
border-color: lightgray;
|
||||
}
|
||||
|
||||
.mode-sort .btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mode-sort.state-grabbing .t-node {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.mode-sort.state-grabbing input {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.mode-sort.state-grabbing .t-grabbing {
|
||||
background-color: lightgreen;
|
||||
border-left-color: green;
|
||||
}
|
||||
|
||||
.grab-ptr {
|
||||
margin: 0;
|
||||
border: solid 1px green;
|
||||
}
|
456
Http/SkinEditor/app.js
Normal file
456
Http/SkinEditor/app.js
Normal file
@@ -0,0 +1,456 @@
|
||||
var messages = {};
|
||||
var lang;
|
||||
|
||||
var literal = true;
|
||||
|
||||
var app;
|
||||
var tv;
|
||||
var tree;
|
||||
|
||||
var cel;
|
||||
var clist;
|
||||
|
||||
var blocklists = {
|
||||
"block.element": ["statement.obj", "statement.comp", "statement.filter", "statement.prop"],
|
||||
"block.filter": ["statement.filter.type", "statement.filter.flag", "statement.filter.flag.n", "statement.filter.prop", "statement.filter.prop.n"],
|
||||
"block.root": ["statement.select", "statement.define"],
|
||||
"block.select": ["statement.select.type", "statement.select.flag", "statement.select.flag.n", "statement.select.prop", "statement.select.prop.n"],
|
||||
};
|
||||
|
||||
var ilid = 0;
|
||||
var inputlists = {
|
||||
"input.comp": ["image", "scale3", "rect", "polysec"],
|
||||
"input.type": ["chart", "group", "track", "note"],
|
||||
};
|
||||
|
||||
var statementlists = {
|
||||
"statement.comp": ["input.comp"],
|
||||
"statement.define": ["input.ident", "exp"],
|
||||
"statement.filter": ["block.filter", "block.element"],
|
||||
"statement.filter.flag": ["input.flag"],
|
||||
"statement.filter.flag.n": ["input.flag"],
|
||||
"statement.filter.prop": ["input.prop", "exp"],
|
||||
"statement.filter.prop.n": ["input.prop", "exp"],
|
||||
"statement.filter.type": ["input.type"],
|
||||
"statement.obj": ["block.element"],
|
||||
"statement.prop": ["input.prop", "exp"],
|
||||
"statement.select": ["block.select", "block.element"],
|
||||
"statement.select.flag": ["input.flag"],
|
||||
"statement.select.flag.n": ["input.flag"],
|
||||
"statement.select.prop": ["input.prop", "exp"],
|
||||
"statement.select.prop.n": ["input.prop", "exp"],
|
||||
"statement.select.type": ["input.type"],
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
lang = navigator.language.replace("-", "_");
|
||||
if (!messages[lang])
|
||||
lang = "en_US";
|
||||
|
||||
app = $("#app");
|
||||
tv = $("#treeview");
|
||||
tree = $("#tree");
|
||||
app.find("tbr").replaceWith(function() {
|
||||
return msg($(this).text());
|
||||
});
|
||||
addAddButton(tree).on("click", function(event) {
|
||||
if (clist)
|
||||
clist.remove();
|
||||
});
|
||||
tv.on("mousemove", null, null, onMouseMove);
|
||||
|
||||
$(".tgbtn").on("click", function(event) {
|
||||
var btn = $(this);
|
||||
btn.toggleClass("tgbtn-active");
|
||||
onToggleButtonClick(btn.attr("id"), btn.hasClass("tgbtn-active"));
|
||||
});
|
||||
}
|
||||
;
|
||||
|
||||
function addAddButton(el) {
|
||||
return el.append($("<span></span>").addClass("btn btn-add").text("+").on("click", null, el, onAddButtonClick));
|
||||
}
|
||||
|
||||
function addAddExpButton(el) {
|
||||
return el.append($("<span></span>").addClass("btn btn-add").text("+").on("click", null, el, onAddExpButtonClick));
|
||||
}
|
||||
|
||||
function addAddButtonLiteral(el) {
|
||||
return el.append($("<span></span>").addClass("btn btn-add t-inline").text("+").on("click", null, el, onAddButtonLiteralClick));
|
||||
}
|
||||
|
||||
function addDeleteButton(el) {
|
||||
return el.append($("<span></span>").addClass("btn btn-delete").text("x").on("click", null, el, onDeleteButtonClick));
|
||||
}
|
||||
|
||||
function addDeleteButtonLiteral(el) {
|
||||
return el.append($("<span></span>").addClass("btn btn-delete t-inline").text("x").on("click", null, el, onDeleteButtonLiteralClick));
|
||||
}
|
||||
|
||||
function onAddButtonClick(event) {
|
||||
cel = el = event.data;
|
||||
generateAddList(event, blocklists[el.attr("key")]);
|
||||
}
|
||||
|
||||
function onAddExpButtonClick(event) {
|
||||
cel = el = event.data;
|
||||
generateAddExpList(event);
|
||||
}
|
||||
|
||||
function onAddButtonLiteralClick(event) {
|
||||
var el = event.data.children(".t-internal");
|
||||
if (!el.hasClass("t-node"))
|
||||
el = el.children(".t-node");
|
||||
event.data = el;
|
||||
onAddButtonClick(event);
|
||||
}
|
||||
|
||||
function onDeleteButtonClick(event) {
|
||||
event.data.remove();
|
||||
}
|
||||
|
||||
function onDeleteButtonLiteralClick(event) {
|
||||
var el = event.data.parents(".t-literal").first();
|
||||
fetchInternalStatements(el).eq(parseInt(event.data.attr("target"))).remove();
|
||||
updateLiteral(el);
|
||||
}
|
||||
|
||||
var tblist = {
|
||||
"tb-debug": "mode-debug",
|
||||
"tb-hide-add": "mode-hide-add",
|
||||
"tb-hide-delete": "mode-hide-delete",
|
||||
"tb-sort": "mode-sort",
|
||||
}
|
||||
function onToggleButtonClick(id, state) {
|
||||
var cls = tblist[id];
|
||||
if (state)
|
||||
tv.addClass(cls);
|
||||
else
|
||||
tv.removeClass(cls);
|
||||
if (cls == "mode-sort") {
|
||||
var il = tv.find(".t-input");
|
||||
var sl = tv.find(".t-statement").not(".t-inline");
|
||||
if (state) {
|
||||
il.each(function(i) {
|
||||
$(il[i]).children("input").attr("disabled", "");
|
||||
});
|
||||
sl.each(function(i) {
|
||||
$(sl[i]).on("click", null, $(sl[i]), onStatementSort);
|
||||
});
|
||||
} else {
|
||||
il.each(function(i) {
|
||||
var el = $(il[i]);
|
||||
if (!el.parents(".t-internal").length)
|
||||
el.children("input").attr("disabled", null);
|
||||
});
|
||||
sl.each(function(i) {
|
||||
$(sl[i]).off("click", null, onStatementSort);
|
||||
});
|
||||
tv.removeClass("state-grabbing");
|
||||
if (grabbing) {
|
||||
grabbing.removeClass("t-grabbing");
|
||||
grabbing = null;
|
||||
grabPointer.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var grabbing;
|
||||
var grabPointer;
|
||||
function onStatementSort(event) {
|
||||
event.stopPropagation();
|
||||
if (grabbing) {
|
||||
var l = grabbing.parent().children(".t-statement");
|
||||
var i = getGrabPtrIndex(event.pageY);
|
||||
if (i == l.length)
|
||||
grabbing.insertAfter(l.last());
|
||||
else
|
||||
grabbing.insertBefore(l.eq(i));
|
||||
tv.removeClass("state-grabbing");
|
||||
grabbing.removeClass("t-grabbing");
|
||||
updateLiteral(grabbing.parents(".t-literal").first());
|
||||
grabbing = null;
|
||||
grabPointer.remove();
|
||||
} else {
|
||||
grabbing = event.data;
|
||||
grabbing.addClass("t-grabbing");
|
||||
tv.addClass("state-grabbing");
|
||||
grabPointer = $("<hr />").addClass("grab-ptr");
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMove(event) {
|
||||
if (grabbing) {
|
||||
var l = grabbing.parent().children(".t-statement");
|
||||
var i = getGrabPtrIndex(event.pageY);
|
||||
if (i == l.length)
|
||||
grabPointer.remove().insertAfter(l.last());
|
||||
else
|
||||
grabPointer.remove().insertBefore(l.eq(i));
|
||||
}
|
||||
}
|
||||
|
||||
function getGrabPtrIndex(y) {
|
||||
var l = grabbing.parent().children(".t-statement");
|
||||
var tl = l.map(function(i) {
|
||||
return l[i].offsetTop - tree.scrollTop() - y;
|
||||
}).toArray();
|
||||
tl.push(l.last()[0].offsetTop + l.last().height() - tree.scrollTop() - y);
|
||||
return ArrayUtil.binarySearch(tl, 0, function(a, b) {
|
||||
return a - b;
|
||||
}, true);
|
||||
}
|
||||
|
||||
function generateAddList(event, items) {
|
||||
event.stopPropagation();
|
||||
if (clist)
|
||||
clist.remove();
|
||||
var ul = $("<ul></ul>").addClass("t-list");
|
||||
for (var i in items) {
|
||||
var item = items[i];
|
||||
ul.append($("<li></li>").addClass("t-li").attr("key", item).text(msg("list." + item)).on("click", null, item, onAddItemClick));
|
||||
}
|
||||
popup(event, ul);
|
||||
}
|
||||
|
||||
function generateAddExpList(event, items) {
|
||||
event.stopPropagation();
|
||||
if (clist)
|
||||
clist.remove();
|
||||
var ul = $("<ul></ul>").addClass("t-list t-exp-list");
|
||||
for (var i in items) {
|
||||
var item = items[i];
|
||||
ul.append($("<li></li>").addClass("t-li").attr("key", item).text(msg("list." + item)).on("click", null, item, onAddItemClick));
|
||||
}
|
||||
popup(event, ul);
|
||||
}
|
||||
|
||||
function popup(event, ul) {
|
||||
clist = ul;
|
||||
app.append(ul);
|
||||
var left = event.pageX;
|
||||
if (left + ul.outerWidth() > window.innerWidth)
|
||||
left = Math.max(0, left - ul.outerWidth());
|
||||
var top = event.pageY;
|
||||
if (top + ul.outerHeight() > window.innerHeight)
|
||||
top = Math.max(0, top - ul.outerHeight());
|
||||
ul.css({
|
||||
"left": left,
|
||||
"top": top
|
||||
});
|
||||
}
|
||||
|
||||
function generateInputList(el, key) {
|
||||
var il = inputlists[key];
|
||||
if (!il)
|
||||
return;
|
||||
var id = "il-" + ilid.toString();
|
||||
var dl = $("<datalist></datalist>").attr("id", id);
|
||||
for (var i in il) {
|
||||
var li = il[i];
|
||||
dl.append($("<option />").attr({
|
||||
"label": msg(key + "." + li),
|
||||
"value": li,
|
||||
}));
|
||||
}
|
||||
dl.insertAfter(el);
|
||||
el.attr("list", id);
|
||||
ilid++;
|
||||
}
|
||||
|
||||
function onAddItemClick(event) {
|
||||
create(event.data).insertBefore(cel.children(":last"));
|
||||
if (cel.parents(".t-node").first().hasClass("t-literal"))
|
||||
updateLiteral(cel.parents(".t-node").first());
|
||||
var il = cel.parents(".t-node").first().find(".t-input");
|
||||
il.each(function(i) {
|
||||
var iel = $(il[i]);
|
||||
Stretchy.resize(iel.children("input")[0]);
|
||||
});
|
||||
cel = null;
|
||||
clist.remove();
|
||||
}
|
||||
|
||||
function onInputLiteralUpdate(event) {
|
||||
var ib = event.data.children("input");
|
||||
var el = event.data.parents(".t-literal").first();
|
||||
fetchInternalStatements(el).eq(parseInt(event.data.attr("target"))).children("[pid=\"" + event.data.attr("pid") + "\"]").children("input").val(ib.val());
|
||||
}
|
||||
|
||||
function syncLiteral(iel) {
|
||||
if (iel.attr("target") == -1)
|
||||
return;
|
||||
var ib = iel.children("input");
|
||||
var el = iel.parents(".t-literal").first();
|
||||
ib.val(fetchInternalStatements(el).eq(parseInt(iel.attr("target"))).children("[pid=\"" + iel.attr("pid") + "\"]").children("input").val());
|
||||
}
|
||||
|
||||
function fetchInternalStatements(el, key) {
|
||||
var l = el.children(".t-internal");
|
||||
if (!l.hasClass("t-node"))
|
||||
l = l.children(".t-node").first();
|
||||
if (key)
|
||||
return l.children("[key=\"" + key + "\"]");
|
||||
else
|
||||
return l.children();
|
||||
}
|
||||
|
||||
function create(key, target) {
|
||||
var k0 = key.split(".")[0];
|
||||
var flag = msg("literal." + key);
|
||||
if (k0 == "input")
|
||||
flag = true;
|
||||
if (target != null && literal && flag)
|
||||
switch (k0) {
|
||||
case "block":
|
||||
return createBlockLiteral(key, target);
|
||||
case "input":
|
||||
return createInput(key, target);
|
||||
case "statement":
|
||||
return createStatementLiteral(key, target);
|
||||
}
|
||||
else
|
||||
switch (k0) {
|
||||
case "block":
|
||||
return createBlock(key);
|
||||
case "statement":
|
||||
return createStatement(key);
|
||||
case "exp":
|
||||
return createExp(key);
|
||||
}
|
||||
}
|
||||
|
||||
function createBlock(key) {
|
||||
var m = msg(key);
|
||||
var b = addAddButton($("<div></div>").attr("key", key).addClass("t-node t-block"));
|
||||
if (!m)
|
||||
return b;
|
||||
else {
|
||||
var n = $("<div></div>").addClass("t-node-sup t-block-sup").html(m);
|
||||
n.children("tbr").replaceWith(b);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
function createBlockLiteral(key, target) {
|
||||
var o = createBlock(key).addClass("t-internal");
|
||||
var el = $("<div></div>").attr({
|
||||
"key": key,
|
||||
"target": target.index()
|
||||
}).addClass("t-node t-literal");
|
||||
el.append(o);
|
||||
updateLiteral(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
function createExp(key) {
|
||||
var m = msg(key);
|
||||
var el = addAddExpButton($("<div></div>").attr("key", key).addClass("t-node t-exp t-inline").html(m));
|
||||
return el;
|
||||
}
|
||||
|
||||
function createInput(key, target) {
|
||||
var el = $("<input />").attr({
|
||||
"type": "text",
|
||||
"placeholder": msg(key + ".default")
|
||||
});
|
||||
var r = $("<span></span>").attr({
|
||||
"key": key,
|
||||
"target": target.index()
|
||||
}).addClass("t-node t-input t-inline").append(el);
|
||||
generateInputList(el, key);
|
||||
applyResizeHandler(el);
|
||||
el.on("change input", null, r, onInputLiteralUpdate);
|
||||
return r;
|
||||
}
|
||||
|
||||
function createStatement(key) {
|
||||
var r = msg(key);
|
||||
var el = addDeleteButton($("<div></div>").attr("key", key).addClass("t-node t-statement").html(r));
|
||||
el.children("tbr").replaceWith(function() {
|
||||
var m = $(this).text();
|
||||
var id = parseInt(m);
|
||||
if (isNaN(id))
|
||||
return create(m, $(this).parent());
|
||||
else
|
||||
return create(statementlists[key][id], $(this).parent()).attr("pid", id);
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
function createStatementLiteral(key, target) {
|
||||
var r = msg("literal." + key);
|
||||
var el = addDeleteButtonLiteral($("<div></div>").attr({
|
||||
"key": key,
|
||||
"target": target.index()
|
||||
}).addClass("t-node t-statement t-inline").html(r));
|
||||
el.children("tbr").replaceWith(function() {
|
||||
var m = $(this).text();
|
||||
var id = parseInt(m);
|
||||
if (isNaN(id))
|
||||
return create(m, target);
|
||||
else
|
||||
return create(statementlists[key][id], target).attr("pid", id);
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
function applyResizeHandler(el) {
|
||||
el.on("change input", function() {
|
||||
Stretchy.resize(this);
|
||||
});
|
||||
}
|
||||
|
||||
function updateLiteral(el) {
|
||||
var key = el.attr("key");
|
||||
var m = msg("literal." + key);
|
||||
var o = el.children(".t-internal");
|
||||
addAddButtonLiteral(el.html(m));
|
||||
el.append(o);
|
||||
el.children("tbr").replaceWith(function() {
|
||||
var m = $(this).text().split("?");
|
||||
var def;
|
||||
if (m.length > 1) {
|
||||
def = m[1];
|
||||
m = m[0];
|
||||
} else
|
||||
m = m[0];
|
||||
var l = fetchInternalStatements(el, m);
|
||||
var s = l.map(function(si) {
|
||||
return create(m, l.eq(si));
|
||||
});
|
||||
return conjAnd(s, def);
|
||||
});
|
||||
var il = el.find(".t-input");
|
||||
il.each(function(i) {
|
||||
var iel = $(il[i]);
|
||||
if (iel.parents(".t-internal").length || tv.hasClass("mode-sort"))
|
||||
iel.children("input").attr("disabled", "");
|
||||
syncLiteral(iel);
|
||||
Stretchy.resize(iel.children("input")[0]);
|
||||
});
|
||||
var cl = el.contents();
|
||||
for (var t in cl) {
|
||||
var ci = cl[t];
|
||||
if (ci.nodeName == "#text" && ci.nodeValue == " ") {
|
||||
ci.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function conjAnd(list, def) {
|
||||
var el = $("<div></div>").addClass("t-conj t-inline");
|
||||
for (var i = 0; i < list.length; i++)
|
||||
el.append(list[i]);
|
||||
if (list.length == 0)
|
||||
el.text(def);
|
||||
return el;
|
||||
}
|
||||
|
||||
function msg(key) {
|
||||
var m = messages[lang][key];
|
||||
if (!m)
|
||||
return null;
|
||||
return m.replace(/{(.*?)}/g, "<tbr>$1</tbr>");
|
||||
}
|
26
Http/SkinEditor/array_util.js
Normal file
26
Http/SkinEditor/array_util.js
Normal file
@@ -0,0 +1,26 @@
|
||||
var ArrayUtil = {
|
||||
binarySearch: function(a, i, c, f) {
|
||||
var s = 0
|
||||
, e = a.length - 1;
|
||||
while (e - s > 1) {
|
||||
var m = Math.floor((e + s) / 2);
|
||||
var r = c(i, a[m]);
|
||||
if (r < 0)
|
||||
e = m;
|
||||
else if (r > 0)
|
||||
s = m;
|
||||
else
|
||||
return m;
|
||||
}
|
||||
if (!f)
|
||||
return -e;
|
||||
else {
|
||||
var rs = Math.abs(c(i, a[s]));
|
||||
var re = Math.abs(c(i, a[e]));
|
||||
if (re < rs)
|
||||
return e;
|
||||
else
|
||||
return s;
|
||||
}
|
||||
}
|
||||
};
|
24
Http/SkinEditor/index.html
Normal file
24
Http/SkinEditor/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<title>Skin Editor - Cosmo Resona</title>
|
||||
<link type="text/css" rel="stylesheet" href="app.css"/>
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="stretchy.min.js"></script>
|
||||
<script type="text/javascript" src="array_util.js"></script>
|
||||
<script type="text/javascript" src="app.js"></script>
|
||||
<script type="text/javascript" src="messages/en_US.js"></script>
|
||||
<!--<script type="text/javascript" src="messages/zh_CN.js" charset="UTF-8"></script>-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div id="toolbar">
|
||||
<div class="tgbtn" id="tb-sort"><tbr>tool.sort</tbr></div>
|
||||
<div class="tgbtn" id="tb-hide-add"><tbr>tool.hideadd</tbr></div>
|
||||
<div class="tgbtn" id="tb-hide-delete"><tbr>tool.hidedelete</tbr></div>
|
||||
<div class="tgbtn" id="tb-debug"><tbr>tool.debug</tbr></div>
|
||||
</div>
|
||||
<div id="treeview">
|
||||
<div id="tree" class="t-node t-root" key="block.root"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
2
Http/SkinEditor/jquery-3.6.0.min.js
vendored
Normal file
2
Http/SkinEditor/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
65
Http/SkinEditor/messages/en_US.js
Normal file
65
Http/SkinEditor/messages/en_US.js
Normal file
@@ -0,0 +1,65 @@
|
||||
messages["en_US"] = {
|
||||
"block.filter": "If {}",
|
||||
"block.select": "Select {}",
|
||||
"input.comp.default": "component",
|
||||
"input.comp.image": "image sprite",
|
||||
"input.comp.polysec": "polygon sectional mesh",
|
||||
"input.comp.rect": "colored rectangle",
|
||||
"input.comp.scale3": "scale3 sprite",
|
||||
"input.ident.default": "variable",
|
||||
"input.flag.default": "flag",
|
||||
"input.prop.default": "property",
|
||||
"input.type.chart": "chart",
|
||||
"input.type.default": "element",
|
||||
"input.type.group": "track group",
|
||||
"input.type.note": "note",
|
||||
"input.type.track": "track",
|
||||
"list.statement.comp": "Attach a component",
|
||||
"list.statement.define": "Define a variable",
|
||||
"list.statement.filter": "Filter element",
|
||||
"list.statement.filter.flag": "Filter flag",
|
||||
"list.statement.filter.flag.n": "Filter flag (negative)",
|
||||
"list.statement.filter.prop": "Filter property",
|
||||
"list.statement.filter.prop.n": "Filter property (negative)",
|
||||
"list.statement.filter.type": "Filter element type",
|
||||
"list.statement.obj": "Create a container",
|
||||
"list.statement.prop": "Set property",
|
||||
"list.statement.select": "Select elements",
|
||||
"list.statement.select.flag": "Filter flag",
|
||||
"list.statement.select.flag.n": "Filter flag (negative)",
|
||||
"list.statement.select.prop": "Filter property",
|
||||
"list.statement.select.prop.n": "Filter property (negative)",
|
||||
"list.statement.select.type": "Filter element type",
|
||||
"literal.block.filter": "If {statement.filter.flag} {statement.filter.flag.n} {statement.filter.type} {statement.filter.prop} {statement.filter.prop.n}",
|
||||
"literal.block.select": "For each {statement.select.flag} {statement.select.flag.n} {statement.select.type?element} {statement.select.prop} {statement.select.prop.n}",
|
||||
"literal.statement.filter.flag": "it is {0}",
|
||||
"literal.statement.filter.flag.n": "it is not {0}",
|
||||
"literal.statement.filter.prop": "its {0} is {1}",
|
||||
"literal.statement.filter.prop.n": "its {0} is not {1}",
|
||||
"literal.statement.filter.type": "it is a {0}",
|
||||
"literal.statement.select.flag": "{0}",
|
||||
"literal.statement.select.flag.n": "non-{0}",
|
||||
"literal.statement.select.prop": "whose {0} is {1}",
|
||||
"literal.statement.select.prop.n": "whose {0} is not {1}",
|
||||
"literal.statement.select.type": "{0}",
|
||||
"statement.comp": "with a {0}",
|
||||
"statement.define": "Define {0} = {1}",
|
||||
"statement.filter": "{0} {1}",
|
||||
"statement.filter.flag": "it is {0}",
|
||||
"statement.filter.flag.n": "it is not {0}",
|
||||
"statement.filter.prop": "its {0} is {1}",
|
||||
"statement.filter.prop.n": "its {0} is not {1}",
|
||||
"statement.filter.type": "it is a {0}",
|
||||
"statement.obj": "Create a container {0}",
|
||||
"statement.prop": "Set its {0} to {1}",
|
||||
"statement.select": "{0} {1}",
|
||||
"statement.select.flag": "that is {0}",
|
||||
"statement.select.flag.n": "that is not {0}",
|
||||
"statement.select.prop": "whose {0} is {1}",
|
||||
"statement.select.prop.n": "whose {0} is not {1}",
|
||||
"statement.select.type": "{0}",
|
||||
"tool.debug": "Debug",
|
||||
"tool.hideadd": "Hide Add",
|
||||
"tool.hidedelete": "Hide Delete",
|
||||
"tool.sort": "Sort",
|
||||
};
|
65
Http/SkinEditor/messages/zh_CN.js
Normal file
65
Http/SkinEditor/messages/zh_CN.js
Normal file
@@ -0,0 +1,65 @@
|
||||
messages["zh_CN"] = {
|
||||
"block.filter": "如果 {}",
|
||||
"block.select": "选择 {}",
|
||||
"input.comp.default": "组件",
|
||||
"input.comp.image": "图片元件",
|
||||
"input.comp.polysec": "多边形截面网格",
|
||||
"input.comp.rect": "纯色矩形",
|
||||
"input.comp.scale3": "三段拉伸元件",
|
||||
"input.ident.default": "变量",
|
||||
"input.flag.default": "标记",
|
||||
"input.prop.default": "属性",
|
||||
"input.type.chart": "谱面",
|
||||
"input.type.default": "元素",
|
||||
"input.type.group": "轨道组",
|
||||
"input.type.note": "音符",
|
||||
"input.type.track": "轨道",
|
||||
"list.statement.comp": "附加组件",
|
||||
"list.statement.define": "定义变量",
|
||||
"list.statement.filter": "筛选元素",
|
||||
"list.statement.filter.flag": "筛选标记",
|
||||
"list.statement.filter.flag.n": "筛选标记(否定)",
|
||||
"list.statement.filter.prop": "筛选属性",
|
||||
"list.statement.filter.prop.n": "筛选属性(否定)",
|
||||
"list.statement.filter.type": "筛选元素类型",
|
||||
"list.statement.obj": "创建容器",
|
||||
"list.statement.prop": "设置属性",
|
||||
"list.statement.select": "选择元素",
|
||||
"list.statement.select.flag": "筛选标记",
|
||||
"list.statement.select.flag.n": "筛选标记(否定)",
|
||||
"list.statement.select.prop": "筛选属性",
|
||||
"list.statement.select.prop.n": "筛选属性(否定)",
|
||||
"list.statement.select.type": "筛选元素类型",
|
||||
"literal.block.filter": "如果 {statement.filter.flag} {statement.filter.flag.n} {statement.filter.type} {statement.filter.prop} {statement.filter.prop.n}",
|
||||
"literal.block.select": "对于每个 {statement.select.prop} {statement.select.prop.n} {statement.select.flag} {statement.select.flag.n} {statement.select.type?元素}",
|
||||
"literal.statement.filter.flag": "该元素带有标记 {0}",
|
||||
"literal.statement.filter.flag.n": "该元素不带有标记 {0}",
|
||||
"literal.statement.filter.prop": "该元素的 {0} {1}",
|
||||
"literal.statement.filter.prop.n": "该元素的 {0} 不 {1}",
|
||||
"literal.statement.filter.type": "该元素是 {0}",
|
||||
"literal.statement.select.flag": "{0}",
|
||||
"literal.statement.select.flag.n": "非{0}",
|
||||
"literal.statement.select.prop": "{0} {1} 的",
|
||||
"literal.statement.select.prop.n": "{0} 不 {1} 的",
|
||||
"literal.statement.select.type": "{0}",
|
||||
"statement.comp": "创建一个 {0} 组件",
|
||||
"statement.define": "定义变量 {0} = {1}",
|
||||
"statement.filter": "{0} {1}",
|
||||
"statement.filter.flag": "该元素带有标记 {0}",
|
||||
"statement.filter.flag.n": "该元素不带有标记 {0}",
|
||||
"statement.filter.prop": "该元素的 {0} {1}",
|
||||
"statement.filter.prop.n": "该元素的 {0} 不 {1}",
|
||||
"statement.filter.type": "该元素是 {0}",
|
||||
"statement.obj": "创建一个容器 {0}",
|
||||
"statement.prop": "设置属性 {0} 为 {1}",
|
||||
"statement.select": "{0} {1}",
|
||||
"statement.select.flag": "{0}",
|
||||
"statement.select.flag.n": "非{0}",
|
||||
"statement.select.prop": "{0} {1} 的",
|
||||
"statement.select.prop.n": "{0} 不 {1} 的",
|
||||
"statement.select.type": "{0}",
|
||||
"tool.debug": "调试",
|
||||
"tool.hideadd": "隐藏添加按钮",
|
||||
"tool.hidedelete": "隐藏删除按钮",
|
||||
"tool.sort": "排序",
|
||||
};
|
5
Http/SkinEditor/stretchy.min.js
vendored
Normal file
5
Http/SkinEditor/stretchy.min.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
!function(){if(self.Element&&(Element.prototype.matches||(Element.prototype.matches=Element.prototype.webkitMatchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||null),Element.prototype.matches)){var p=self.Stretchy={selectors:{base:'textarea, select:not([size]), input:not([type]), input[type="'+"text number url email tel".split(" ").join('"], input[type="')+'"]',filter:"*"},script:document.currentScript||t("script").pop(),resize:function(e){if(p.resizes(e)){var t,i=getComputedStyle(e),n=0;!e.value&&e.placeholder&&(t=!0,e.value=e.placeholder);var o=e.nodeName.toLowerCase();if("textarea"==o)e.style.height="0","border-box"==i.boxSizing?n=e.offsetHeight:"content-box"==i.boxSizing&&(n=-e.clientHeight+parseFloat(i.minHeight)),e.style.height=e.scrollHeight+n+"px";else if("input"==o)if(e.style.width="1000px",e.offsetWidth){e.style.width="0",
|
||||
"border-box"==i.boxSizing?n=e.offsetWidth:"padding-box"==i.boxSizing?n=e.clientWidth:"content-box"==i.boxSizing&&(n=parseFloat(i.minWidth));var r=Math.max(n,e.scrollWidth-e.clientWidth);e.style.width=r+"px";for(var l=0;l<10&&(e.scrollLeft=1e10,0!=e.scrollLeft);l++)r+=e.scrollLeft,e.style.width=r+"px"}else e.style.width=e.value.length+1+"ch";else if("select"==o){var s,c=0<e.selectedIndex?e.selectedIndex:0,a=document.createElement("_");for(var d in a.textContent=e.options[c].textContent,e.parentNode.insertBefore(a,e.nextSibling),i){var h=i[d];/^(width|webkitLogicalWidth|length)$/.test(d)||"string"!=typeof h||(a.style[d]=h,/appearance$/i.test(d)&&(s=d))}a.style.width="",0<a.offsetWidth&&(e.style.width=a.offsetWidth+"px",i[s]&&"none"===i[s]||(e.style.width="calc("+e.style.width+" + 2em)")),a.parentNode.removeChild(a),a=null}t&&(e.value="")}},resizeAll:function(e){t(e||p.selectors.base).forEach(function(e){p.resize(e)})},active:!0,resizes:function(e){
|
||||
return e&&e.parentNode&&e.matches&&e.matches(p.selectors.base)&&e.matches(p.selectors.filter)},init:function(){p.selectors.filter=p.script.getAttribute("data-filter")||(t("[data-stretchy-filter]").pop()||document.body).getAttribute("data-stretchy-filter")||p.selectors.filter,p.resizeAll(),self.MutationObserver&&!p.observer&&(p.observer=new MutationObserver(function(e){p.active&&e.forEach(function(e){"childList"==e.type&&p.resizeAll(e.addedNodes)})}),p.observer.observe(document.documentElement,{childList:!0,subtree:!0}))},$$:t};"loading"!==document.readyState?requestAnimationFrame(p.init):document.addEventListener("DOMContentLoaded",p.init),window.addEventListener("load",function(){p.resizeAll()});var e=function(e){p.active&&p.resize(e.target)};document.documentElement.addEventListener("input",e),document.documentElement.addEventListener("change",e)}function t(e,t){return e instanceof Node||e instanceof Window?[e]:[].slice.call("string"==typeof e?(t||document).querySelectorAll(e):e||[])
|
||||
}}();
|
||||
//# sourceMappingURL=stretchy.min.js.map
|
Reference in New Issue
Block a user