diff --git a/const.js b/const.js index 31643af9..0687490c 100644 --- a/const.js +++ b/const.js @@ -285,9 +285,13 @@ var http = { GET: "GET", PUT: "PUT", POST: "POST", DELETE: "DELETE", Accept: "Accept", ContentType: "Content-Type", ApplicationJSON: "application/json", ApplicationFORM: "application/x-www-form-urlencoded", } -var html = {RIVER_WIDTH: 230, PROJECT_WIDTH: 230, - PLUG_WIDTH: 800, PLUG_HEIHGT: 320, STORY_HEIHGT: 480, FLOAT_HEIHGT: 480, FLOAT_WIDTH: 1200, DESKTOP_WIDTH: 1200, DESKTOP_HEIGHT: 684, - RIVER_MARGIN: 80, PLUGIN_MARGIN: 10, PLUGIN_PADDING: 10, ACTION_MARGIN: 200, ACTION_HEIGHT: 32, STATUS_HEIGHT: 32, +var html = {value: { + RIVER_WIDTH: 230, PROJECT_WIDTH: 230, + ACTION_HEIGHT: 32, STATUS_HEIGHT: 32, + PLUG_WIDTH: 800, PLUG_HEIHGT: 320, STORY_HEIHGT: 480, FLOAT_HEIGHT: 480, FLOAT_WIDTH: 1200, DESKTOP_WIDTH: 1200, DESKTOP_HEIGHT: 684, + RIVER_MARGIN: 80, ACTION_MARGIN: 200, + PLUGIN_PADDING: 0, PLUGIN_MARGIN: 0, + ACTION_BUTTON: 3, TABLE_BUTTON: 5}, FIELDSET: "fieldset", LEGEND: "legend", OPTION: "option", ACTION: "action", OUTPUT: "output", STATUS: "status", OPTION_ARGS: "select.args,input.args,textarea.args", INPUT_ARGS: "input.args,textarea.args", INPUT_BUTTON: "input[type=button]", INPUT_FILE: "input[type=file]", FORM_OPTION: "form.option", DIV_ACTION: "div.action", DIV_OUTPUT: "div.output", DIV_STATUS: "div.status", diff --git a/frame.js b/frame.js index 1a7c25a6..874453cf 100644 --- a/frame.js +++ b/frame.js @@ -196,7 +196,13 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { var cb = meta[button]||meta[chat._ENGINE]; cb? can.core.CallFunc(cb, {event: event, can: can, button: button}): can.run(event, button == mdb.LIST? []: [ctx.ACTION, button].concat(_can.Input())) }) } - return can.core.List(can.page.inputs(can, can.base.getValid(can.base.Obj(list), can.core.Value(can, [chat.ONACTION, mdb.LIST]), meta != can.onaction? can.core.Item(meta): [])||[]), function(item) { + var list = can.page.inputs(can, can.base.getValid(can.base.Obj(list), can.core.Value(can, [chat.ONACTION, mdb.LIST]), meta != can.onaction? can.core.Item(meta): [])||[]) + var limit = html.ACTION_BUTTON; if (list.length >= limit) { var rest = list.slice(limit-1); list = list.slice(0, limit-1), list.push({type: html.BUTTON, name: "more", onclick: function(event) { + can.user.carte(event, can, {_trans: meta._trans||can._trans}, can.core.List(rest, function(item) { return item.name }), function(event, button) { + run(event, button) + }) + }}) } + return can.core.List(list, function(item) { can.base.isUndefined(item) || can.onappend.input(can, item == ""? /* 1.空白 */ {type: html.BR}: can.base.isString(item)? /* 2.按键 */ {type: html.BUTTON, name: item, value: can.user.trans(can, item, meta._trans), onclick: function(event) { run(event, item) @@ -289,6 +295,7 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { var icon = [], _item = can.base.Copy({className: "", type: "", name: ""}, item), input = can.page.input(can, _item, value) if (item.type == html.SELECT) { can.core.List(input.list, function(item) { item.inner = can.user.trans(can, item.inner, null, html.INPUT) }) } if (item.type == html.BUTTON && !input.value) { input.value = can.user.trans(can, item.name) } + input.onclick = item.onclick if (item.type == html.TEXT) { input.placeholder = can.user.trans(can, input.placeholder||input.name, null, html.INPUT) input.title = can.user.trans(can, input.title||input.placeholder||input.name, null, html.INPUT) @@ -356,15 +363,20 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { }) }, _init: function(target) { can.page.style(can, target, html.WIDTH, (select.offsetWidth||80)+30), can.onappend.style(can, html.HIDE, select) }}, {icon: mdb.SELECT}]) }, - checkbox: function(can, table, msg) { can.page.Select(can, table, "tr>th:first-child,tr>td:first-child", function(target) { - can.page.insertBefore(can, [{type: target.tagName, list: [{type: html.INPUT, data: {type: html.CHECKBOX}, onchange: function(event) { - can.page.tagis(target, html.TH) && can.page.Select(can, table, "tr>td:first-child>input[type=checkbox]", function(target) { target.checked = event.target.checked }) - var list = {}, key = can.page.SelectArgs(can, can._option, "", function(target) { if (target.value == "") { return target.name } }) - can.page.Select(can, table, "tr>td:first-child>input[type=checkbox]", function(target) { can.page.ClassList.set(can, can.page.parentNode(can, target, html.TR), html.SELECT, target.checked) - target.checked && can.core.List(key, function(key) { if (!msg[key]) { return } list[key] = (list[key]||[]).concat([msg[key][can.page.parentNode(can, target, html.TR).dataset.index]]) }) - }), can.db._checkbox = {}, can.core.Item(list, function(k, v) { can.db._checkbox[k] = v.join(",") }) - }}] }], target) - }) }, + checkbox: function(can, table, msg) { + can.page.Select(can, table, "tr>th:first-child,tr>td:first-child", function(target) { + can.page.insertBefore(can, [{type: target.tagName, list: [{type: html.INPUT, data: {type: html.CHECKBOX}, onchange: function(event) { + can.page.tagis(target, html.TH) && can.page.Select(can, table, "tr>td:first-child>input[type=checkbox]", function(target) { target.checked = event.target.checked }) + var list = {}, key = can.page.SelectArgs(can, can._option, "", function(target) { if (target.value == "") { return target.name } }) + can.page.Select(can, table, "tr>td:first-child>input[type=checkbox]", function(target) { can.page.ClassList.set(can, can.page.parentNode(can, target, html.TR), html.SELECT, target.checked) + target.checked && can.core.List(key, function(key) { if (!msg[key]) { return } list[key] = (list[key]||[]).concat([msg[key][can.page.parentNode(can, target, html.TR).dataset.index]]) }) + }), can.db._checkbox = {}, can.core.Item(list, function(k, v) { can.db._checkbox[k] = v.join(",") }) + }}] }], target) + }) + can.page.Select(can, table, "colgroup>col:first-child", function(target) { + can.page.insertBefore(can, [{type: target.tagName, className: "checkbox"}], target) + }) + }, table: function(can, msg, cb, target, keys) { if (!msg || msg.Length() == 0) { return } var meta = can.base.Obj(msg.Option(mdb.META)) if (can.user.isMobile) { can.base.toLast(msg.append, mdb.TIME) } can.base.toLast(msg.append, web.LINK), can.base.toLast(msg.append, ctx.ACTION) if (msg.append && msg.append[msg.append.length-1] == ctx.ACTION && can.core.List(msg[ctx.ACTION], function(item) { if (item) { return item } }).length == 0) { msg.append.pop() } @@ -397,7 +409,7 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { can.page.ClassList.set(can, target, "will", can.page.ClassList.has(can, target, key)) }) }, title: can.user.trans(can, can.Option(key) == undefined? key: "click to detail", null, html.INPUT), _init: function(target) { - key == ctx.ACTION && can.onappend.mores(can, target, data, can.user.isMobile? can.user.isLandscape() || msg.IsDetail()? 5: 3: can.isCmdMode() || msg.IsDetail()? 10: 5) + key == ctx.ACTION && can.onappend.mores(can, target, data, msg.IsDetail()? 10: html.TABLE_BUTTON) can.page.SelectOne(can, target, html.SPAN, function(span) { can.core.List(span.style, function(key) { target.style[key] = span.style[key] }) }) can.page.style(can, target, "cursor", can.base.isIn(key, mdb.KEY, mdb.TIME)? "default": can.Option(key) != undefined? "pointer": "text") }} diff --git a/index.css b/index.css index 64689049..ca85158a 100644 --- a/index.css +++ b/index.css @@ -33,41 +33,49 @@ body { --code-font-size:14px; --code-line-height:24px; --code-tabs-height:48px; --svg-font-size:24px; --svg-stroke-width:1; --status-font-size:12px; - --legend-padding:20px; --title-margin:var(--legend-padding); --river-margin:80px; - --textarea-height:96px; --qrcode-height:320px; --iframe-height:420px; + --river-width:var(--project-width); --project-width:230px; --input-width:120px; --button-width:60px; --action-height:32px; --status-height:var(--action-height); --footer-height:var(--action-height); --header-height:48px; - --project-width:230px; --river-width:var(--project-width); --input-width:120px; --button-width:60px; - --plug-width:800px; --plug-height:320px; --story-height:480px; --float-height:480px; --float-width:1000px; --desktop-width:1200px; --desktop-height:684px; - --plugin-margin:var(--plugin-padding); --button-margin:var(--button-padding); --input-margin:var(--input-padding); --action-margin:200px; --desktop-icon-size:80px; - --plugin-padding:10px; --button-padding:var(--plugin-padding); --input-padding:5px; --table-padding:var(--button-padding); + --plug-width:800px; --plug-height:320px; --story-height:480px; --float-height:480px; --float-width:1000px; --desktop-width:1200px; --desktop-height:684px; + --textarea-height:96px; --qrcode-height:320px; --iframe-height:420px; --desktop-icon-size:80px; + --river-margin:80px; --action-margin:200px; + --plugin-padding:10px; --plugin-margin:var(--plugin-padding); + --legend-padding:20px; --title-margin:var(--legend-padding); + --button-padding:var(--plugin-padding); --button-margin:var(--button-padding); + --input-padding:5px; --input-margin:var(--input-padding); + --table-padding:var(--button-padding); --plugin-radius:var(--plugin-padding); --button-radius:var(--input-padding); + --action-button:10; --table-button:5; } input { font-family:var(--input-font-family); } body { font-family:var(--body-font-family); } body { background-color:var(--body-bg-color); color:var(--body-fg-color); } body.windows { --code-font-family:"Courier New"; } body.cmd:not(.portal) { background-color:var(--plugin-bg-color); color:var(--plugin-fg-color); } -body.cmd { - --plug-width:1200px; --plug-height:480px; -} +body.cmd { --plug-width:1200px; --plug-height:480px; } body.width1 { /* 320-640 手机竖屏 */ - --footer-height:60px; --input-width:80px; - --river-margin:0; --plugin-margin:0; --button-margin:5px; - --project-width:120px; --river-width:280px;; --svg-font-size:13px; + --river-width:280px;; --project-width:120px; --input-width:80px; + --river-margin:0; + --plugin-margin:0; --button-margin:5px; + --footer-height:60px; + --action-button:2; --table-button:2; } body.width2 { /* 640-960 手机横屏 平板竖屏 笔记本调试 */ + --action-button:4; --table-button:3; } body.width3 { /* 960-1280 平板横屏 */ - + --action-button:5; --table-button:3; } body.width4 { /* 1280-1600 笔记本 显示器调试 */ - + --plugin-padding:10px; + --action-button:6; --table-button:4; } body.width5 { /* 1600-1920 */ - + --plugin-padding:10px; + --action-button:6; --table-button:4; } body.width6 { /* 1920-2240 显示器 */ + --plugin-padding:10px; --river-width:280px; --input-width:180px; } @@ -79,6 +87,7 @@ input:not([type=file]) { padding:0 var(--button-padding); } input:not([type=button]) { padding:0 var(--input-padding); border-radius:0; outline:none; } input[type=checkbox] { height:22px; width:22px; margin:5px; } table.content.full { width:100%; } +body.mobile table.content.detail { word-break:break-all; white-space:unset; } table.content thead { position:sticky; top:2px; } table.content tr.disable { color:var(--disable-fg-color); } table.content tr.offline { color:var(--disable-fg-color); } @@ -296,7 +305,7 @@ fieldset.plug>div.action>div.button.icons>input { display:none; } fieldset.plug>form.option>div.icon:first-child { margin-left:var(--input-margin); } fieldset>form.option>div.text>span.value { line-height:calc(var(--action-height) - 2 * var(--input-padding)); -white-space:pre; padding:var(--input-padding) var(--button-padding); max-width:200px; height:var(--action-height); overflow:auto; } +white-space:pre; padding:var(--input-padding) var(--button-padding); max-width:320px; height:var(--action-height); overflow:auto; } fieldset.plug>form.option>div.text>span.value { display:none; } fieldset:not(.float)>form.option>div.text>span.value { display:none; } fieldset.float:not(.plug)>form.option>div.text>input { display:none; } @@ -369,7 +378,7 @@ div.output.card>div.item>div.title { font-size:var(--legend-font-size); font-wei div.output.card>div.item>div.title>img { margin-right:var(--button-margin); margin-left:0; height:var(--header-height); width:var(--header-height); float:left; } div.output.card>div.item>div.content { font-size:var(--status-font-size); padding:var(--input-padding); height:var(--header-height); } div.output.card>div.item>div.action { text-align:right; width:100%; display:flex; } -div.output.card>div.item>div.action>input { margin-right:var(--button-margin); box-shadow:var(--box-shadow); } +div.output.card>div.item>div.action>input { padding:0 var(--button-padding); margin-right:var(--input-margin); box-shadow:var(--box-shadow); } div.output.stats { flex-wrap:wrap; } div.output.stats>div.item { text-align:center; padding:var(--plugin-padding); margin:var(--plugin-padding); float:left; flex-direction:column; flex-grow:1; } div.output.stats>div.item>div.value span:first-child { font-size:32px; } @@ -427,8 +436,9 @@ table.content th { background-color:var(--th-bg-color); color:var(--th-fg-color) table.content td:hover { background-color:var(--td-hover-bg-color); } table.content td.select { background-color:var(--td-hover-bg-color); } table.content.action tr:hover td:last-child { background-color:var(--th-bg-color); box-shadow:var(--box-shadow); } -table.content.detail td:first-child { text-align:center; } +table.content.detail td:first-child { text-align:center; min-width:80px; } table.content input { box-shadow:var(--box-shadow); } +body.mobile table.content input { border:var(--box-border); box-shadow:var(--box-shadow); } h1:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } h2:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } h3:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } diff --git a/lib/page.js b/lib/page.js index ad96cbf3..d05e1782 100644 --- a/lib/page.js +++ b/lib/page.js @@ -388,7 +388,7 @@ Volcanos("page", { }, buttonStyle: function(can, name) { return can.base.isIn(name, mdb.CREATE, mdb.INSERT, mdb.IMPORT, nfs.CLONE, cli.BUILD, cli.START, ctx.RUN, web.OPEN, web.UPLOAD, web.CONFIRM, aaa.LOGIN, code.AUTOGEN, code.COMPILE, "more", "sso", "add", "pull", "push", "commit", "startall", "preview", "auto-preview", ice.APP)? html.NOTICE: - can.base.isIn(name, mdb.REMOVE, mdb.DELETE, mdb.PRUNES, mdb.PRUNE, nfs.TRASH, cli.RESTART, cli.STOP, cli.REBOOT, web.CANCEL, code.UPGRADE, "drop", "stopall", "prockill")? html.DANGER: "" + can.base.isIn(name, mdb.REMOVE, mdb.DELETE, mdb.PRUNES, mdb.PRUNE, nfs.TRASH, cli.RESTART, cli.STOP, cli.CLOSE, cli.REBOOT, web.CANCEL, code.UPGRADE, "drop", "stopall", "prockill")? html.DANGER: "" }, exportValue: function(can, msg, target) { target = target||can._output msg.OptionDefault(ice.MSG_THEME, can.getHeaderTheme()) diff --git a/panel/header.js b/panel/header.js index ceece72a..53be86ea 100644 --- a/panel/header.js +++ b/panel/header.js @@ -33,21 +33,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, target) { can.onimport.menu(can, mdb.SEARCH, function() { can.onengine.signal(can, chat.ONOPENSEARCH, can.request(event, {type: mdb.FOREACH, word: can._search.value||""})) }) }, _const: function(can) { - html.RIVER_WIDTH = can.page.styleValueInt(can, "--river-width") - html.RIVER_MARGIN = can.page.styleValueInt(can, "--river-margin") - html.PROJECT_WIDTH = can.page.styleValueInt(can, "--project-width") - html.PLUG_WIDTH = can.page.styleValueInt(can, "--plug-width") - html.PLUG_HEIGHT = can.page.styleValueInt(can, "--plug-height") - html.STORY_HEIGHT = can.page.styleValueInt(can, "--story-height") - html.FLOAT_HEIGHT = can.page.styleValueInt(can, "--float-height") - html.FLOAT_WIDTH = can.page.styleValueInt(can, "--float-width") - html.DESKTOP_WIDTH = can.page.styleValueInt(can, "--desktop-width") - html.DESKTOP_HEIGHT = can.page.styleValueInt(can, "--desktop-height") - html.PLUGIN_PADDING = can.page.styleValueInt(can, "--plugin-padding") - html.PLUGIN_MARGIN = can.page.styleValueInt(can, "--plugin-margin") - html.ACTION_MARGIN = can.page.styleValueInt(can, "--action-margin") - html.ACTION_HEIGHT = can.page.styleValueInt(can, "--action-height") - html.STATUS_HEIGHT = can.page.styleValueInt(can, "--status-height") + can.core.Item(html.value, function(key, value) { html[key] = can.page.styleValueInt(can, "--"+key.toLowerCase().replaceAll("_", "-"))||value }) }, _time: function(can, target) { can.core.Timer({interval: 100}, function() { can.onimport.time(can, target) }), can.onappend.figure(can, {action: "date"}, target) }, time: function(can, target) { can.onimport.theme(can), target.innerHTML = can.user.time(can, null, can.Conf(mdb.TIME)||"%H:%M:%S %w") }, diff --git a/plugin/table.js b/plugin/table.js index 476a14ca..1f2d6e90 100644 --- a/plugin/table.js +++ b/plugin/table.js @@ -11,7 +11,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, target) { can.onmotion.clear( return {view: [[html.ITEM, value.status]], list: [ {view: [wiki.TITLE, html.DIV], list: [value.icon && {img: can.misc.Resource(can, value.icon, value.name)}, {text: value.name}]}, {view: [wiki.CONTENT, html.DIV, value.text]}, - {view: html.ACTION, inner: value.action, _init: function(target) { can.onappend.mores(can, target, value, 5) }}, + {view: html.ACTION, inner: value.action, _init: function(target) { can.onappend.mores(can, target, value, html.TABLE_BUTTON) }}, ]} })), can.onimport.layout = function() { can.onlayout.expand(can, can._output, 320) }, can.onappend.scroll(can, can._output) },