From 0714432ee111dfa77e58334cc14d3b9fe7013a6c Mon Sep 17 00:00:00 2001 From: shylinux Date: Thu, 6 Jul 2023 18:47:33 +0800 Subject: [PATCH] opt feel --- frame.js | 12 +++-- index.css | 44 +++++++-------- lib/base.js | 2 +- lib/page.js | 2 +- lib/user.js | 12 +++-- panel/action.js | 14 +++-- panel/search.js | 2 +- plugin/local/wiki/feel.css | 12 +++-- plugin/local/wiki/feel.js | 108 ++++++++++++++++++++++++------------- plugin/local/wiki/word.css | 6 +-- plugin/local/wiki/word.js | 2 +- 11 files changed, 128 insertions(+), 88 deletions(-) diff --git a/frame.js b/frame.js index c254390c..cc221076 100644 --- a/frame.js +++ b/frame.js @@ -121,10 +121,12 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { var sub = Volcanos(meta.name, {_root: can._root||can, _follow: can.core.Keys(can._follow, meta.name), _target: field, _legend: legend, _option: option, _action: action, _output: output, _status: status, _history: [], Status: function(key, value) { if (can.base.isObject(key)) { return can.core.Item(key, sub.Status), key } + try { can.page.Select(can, status, [[[html.SPAN, key]]], function(target) { if (can.base.beginWith(value, nfs.PS, ice.HTTP)) { value = can.page.Format(html.A, value) } - return can.base.isUndefined(value)? (value = target.innerHTML): (target.innerHTML = value.trim? value.trim(): value||"") + return can.base.isUndefined(value)? (value = target.innerHTML): (target.innerHTML = value.trim? value.trim(): value+"") }); return value + } catch(e) {} }, Action: function(key, value) { return can.page.SelectArgs(can, action, key, value)[0] }, Option: function(key, value) { return can.page.SelectArgs(can, option, key, value)[0] }, @@ -151,7 +153,7 @@ Volcanos(chat.ONAPPEND, {_init: function(can, meta, list, cb, target, field) { sub.isCmdMode() && can.onappend.style(sub, can.misc.Search(can, ctx.STYLE)), sub.isCmdMode() && sub.Conf(can.misc.Search(can)) can.base.isFunc(cb) && cb(sub) if (can.user.isMobile && !can.user.isLandscape()) { return } if (can.page.ClassList.has(can, sub._target, html.OUTPUT)) { return } - // sub.isCmdMode() && !can.base.isIn(meta.index, web.CODE_VIMER, web.CODE_INNER, web.CHAT_MACOS_DESKTOP) && can.page.insertBefore(can, can.user.header(can), sub._output, sub._fields) + sub.isCmdMode() && !can.base.isIn(meta.index, web.CODE_VIMER, web.CODE_INNER, web.CHAT_MACOS_DESKTOP) && can.page.insertBefore(can, can.user.header(can), sub._output, sub._fields) }); return sub }, _option: function(can, meta, option, skip) { var index = -1, args = can.base.Obj(meta.args||meta.arg, []), opts = can.base.Obj(meta.opts, {}) @@ -560,7 +562,11 @@ Volcanos(chat.ONLAYOUT, {_init: function(can, target) { target = target||can._ro } else { layout.left = left+width-target.offsetWidth-event.target.offsetWidth } - } else if (layout.left+target.offsetWidth > left+width) { layout.left = left+width-target.offsetWidth } + } else if (layout.left > left+width-10) { + layout.left = left+width-target.offsetWidth-1-event.target.offsetWidth + } else if (layout.left+target.offsetWidth > left+width) { + layout.left = left+width-target.offsetWidth-1 + } }); return can.onmotion.move(can, target, layout), layout }, }) diff --git a/index.css b/index.css index b06d5556..241b726a 100644 --- a/index.css +++ b/index.css @@ -17,7 +17,7 @@ table.content td { padding:2px 5px; } table.content.action th:last-child { position:sticky; right:2px; } table.content.action td:last-child { position:sticky; right:2px; } h1 { text-align:center; margin:20px 0; } h2 { margin:20px 0; } h3 { margin:20px 0; } ul { padding-left:40px; margin:20px 0; } -hr, td.hr { border-bottom:gray dashed 1px; margin:5px; } +hr, td.hr { border-bottom:var(--plugin-border-color) dashed 1px; margin:5px; } img { margin-bottom:-8px; } /* fieldset */ fieldset>legend { margin-right:10px; } @@ -30,6 +30,7 @@ fieldset.input.key div.status { display:block; position:sticky; bottom:0; } fieldset.input.key div.output table.content { width:100%; } fieldset.input.key.simple th { display:none; } fieldset.input.key.simple td { min-width:40px; } +fieldset.input.date { display:block; } fieldset.input.date table.content { text-align:center; width:350px; } fieldset.input.date div.output td { padding:2px 10px; } fieldset.input.date div.output td.prev { color:gray; } @@ -75,7 +76,7 @@ select, input { font-size:1rem; height:32px; } textarea::placeholder, input::pl textarea { font-size:1rem; tab-size:2; padding:5px; height:96px; width:100%; resize:vertical; } table.content, div.item, div.code, div.story[data-type=spark] { font-family:monospace; } table.content, div.item, div.code, div.story[data-type=spark] { white-space:pre; text-align:left; } -div.story[data-type=spark] { padding:5px 10px; border-left:blue solid 5px; } +div.story[data-type=spark] { padding:5px 10px; border-left:var(--code-border-color) solid 5px; } table.content div.story[data-type=spark] { margin:0; } fieldset>div.output>div.code { font-size:14px; } fieldset>div.action>div.tabs { font-style:italic; line-height:22px; padding:5px; height:32px; } @@ -102,12 +103,9 @@ form.option>div.icon.refresh { line-height:26px; } form.option>div.icon.goback { line-height:26px; } form.option>div.icon.next { font-size:18px; } form.option>div.icon.prev { font-size:18px; } -form.option>div.item.text>span.icon { margin-left:-15px; margin-right:3px; } -form.option>div.item.select>span.icon { margin-left:-15px; margin-right:3px; visibility:hidden; } -form.option>div.item.select:hover>span.icon { visibility:visible; } -div.action>div.item.text>span.icon { margin-left:-15px; margin-right:3px; } -div.action>div.item.select>span.icon { margin-left:-15px; margin-right:3px; visibility:hidden; } -div.action>div.item.select:hover>span.icon { visibility:visible; } +div.item.text>span.icon { margin-left:-15px; margin-right:3px; } +div.item.select>span.icon { margin-left:-15px; margin-right:3px; visibility:hidden; } +div.item.select:hover>span.icon { visibility:visible; } div.item.text>span.icon.delete { font-size:20px; visibility:hidden; } div.item.text:hover>span.icon.delete { visibility:visible; } div.tabs span.icon { margin-left:5px; visibility:hidden; } @@ -162,10 +160,9 @@ div.project div.zone>div.item>div.icon { margin-left:3px; float:right; } div.project div.zone>div.list>div.zone>div.item { text-align:left; padding-left:20px; } div.project div.zone>div.list>div.zone>div.item:hover { margin-left:10px; transition:all 0.3s; } fieldset>div.output>div.project>div.item.filter { padding:0; } -fieldset>div.output>div.project { border-right:gray solid 1px; min-width:120px; max-width:240px; } -fieldset>div.output div.profile { border-left:gray solid 1px; max-width:320px; } -fieldset>div.output div.display { border-top:gray solid 1px; } -fieldset>div.output { width:100%; } fieldset>div.status { width:100%; } +fieldset>div.output>div.project { border-right:var(--plugin-border-color) solid 1px; min-width:120px; max-width:230px; } +fieldset>div.output div.profile { border-left:var(--plugin-border-color) solid 1px; max-width:320px; } +fieldset>div.output div.display { border-top:var(--plugin-border-color) solid 1px; } /* table card */ div.output.card>div.item.stop { color:var(--disable-fg-color); } div.output.card>div.item { padding:10px; border:#e7e7e7 solid 1px; margin:10px; width:320px; float:left; } @@ -195,11 +192,12 @@ fieldset.full { position:fixed; left:0; top:0; } fieldset>div.output>div.code { position:sticky; left:0; } fieldset>div.status>legend { margin-left:2px; margin-right:0; height:31px; float:right; clear:none; } fieldset>div.status>legend:not(:hover):not(.select) { background-color:unset; } -form.option>div.cmd, form.option>div.textarea { width:100%; } -fieldset.plug div.output table.content { width:100%; } div.carte.select.float>div.item { text-align:center; } legend, select, input[type=button], th, table.content td, h1, h2, h3, div.item, div.tabs { cursor:pointer; } div.story[data-type=spark] { cursor:copy; } +fieldset { display:flex; flex-wrap:wrap; } fieldset>div.output { width:100%; } fieldset>div.status { width:100%; } +form.option>div.cmd, form.option>div.textarea { width:100%; } +fieldset.plug div.output table.content { width:100%; } /* hover */ input:hover[type=button][name=create] { background-color:var(--create-bg-color); color:var(--create-fg-color); } input:hover[type=button][name=insert] { background-color:var(--create-bg-color); color:var(--create-fg-color); } @@ -218,16 +216,10 @@ body { --create-bg-color:blue; --create-fg-color:white; --disable-fg-color:gray; - --code-bg-color:black; - --code-fg-color:silver; - --code-comment:darkgray; - --code-keyword:darkblue; - --code-package:blue; - --code-datatype:cornflowerblue; - --code-function:darkcyan; - --code-constant:gray; - --code-string:brown; - --code-object:purple; + --code-bg-color:black; --code-fg-color:silver; --code-border-color:blue; + --code-comment:darkgray; --code-keyword:darkblue; --code-package:blue; + --code-datatype:cornflowerblue; --code-function:darkcyan; + --code-constant:gray; --code-string:brown; --code-object:purple; } body { background-color:var(--body-bg-color); color:var(--body-fg-color); } legend { background-color:var(--legend-bg-color); border-radius:var(--input-radius); } @@ -318,8 +310,8 @@ fieldset.inner.float>div.status { display:none; } fieldset.qrcode>div.output div.code { padding:0; } fieldset.xterm>div.action>div.tabs:only-child { display:none; } fieldset.xterm>div.layout { clear:both; } -fieldset.xterm div.layout div.output { border-left:gray solid 1px; border-top:gray solid 1px; } -fieldset.xterm div.layout div.output.select { border:blue solid 1px; } +fieldset.xterm div.layout div.output { border-left:var(--plugin-border-color) solid 1px; border-top:var(--plugin-border-color) solid 1px; } +fieldset.xterm div.layout div.output.select { border:var(--code-border-border) solid 1px; } fieldset.plan div.output div.content>table.content { height:100%; width:100%; } fieldset.draw>form.option>div.item.pid>input { width:60px; } fieldset.draw div.output svg { margin-bottom:-4px; height:100%; width:100%; } diff --git a/lib/base.js b/lib/base.js index fbaa8751..4835c19e 100644 --- a/lib/base.js +++ b/lib/base.js @@ -112,7 +112,7 @@ Volcanos("base", { } else if (typeof v == code.STRING) { if (v == "") { continue } else { return v } } else if (v == undefined) { continue } else { return v } } }, - replaceAll: function(str) { var arg = arguments; for (var i = 1; i < arg.length; i += 2) { if (!arg[i]) { continue } + replaceAll: function(str) { if (!str) { return str } var arg = arguments; for (var i = 1; i < arg.length; i += 2) { if (!arg[i]) { continue } if (str.replaceAll) { str = str.replaceAll(arg[i], arg[i+1]); continue } if (arg[i] && str.replace) { while (str.indexOf(arg[i]) > -1) { str = str.replace(arg[i], arg[i+1]) } } } return str }, diff --git a/lib/page.js b/lib/page.js index 36ce2fff..73ccc9b7 100644 --- a/lib/page.js +++ b/lib/page.js @@ -2,7 +2,7 @@ Volcanos("page", { ClassList: { has: function(can, target, key) { var list = target.className && target.className.split? target.className.split(lex.SP): []; return list.indexOf(key) > -1 }, add: function(can, target, key) { Array.isArray(key) && (key = key.join(lex.SP)) - var list = target.className? target.className.split(lex.SP): []; can.core.List(can.core.Split(key), function(key) { can.base.AddUniq(list, key) }) + var list = target.className? target.className.split(lex.SP): []; can.core.List(can.core.Split(key, " .,"), function(key) { can.base.AddUniq(list, key) }) var value = list.join(lex.SP).trim(); return value != target.className && (target.className = value), value }, del: function(can, target, key) { var list = target.className? target.className.split(lex.SP): [] diff --git a/lib/user.js b/lib/user.js index 47b72a9c..225a1d4b 100644 --- a/lib/user.js +++ b/lib/user.js @@ -83,11 +83,11 @@ Volcanos("user", { var carte = can.user.toast(can, {content: content, title: title, action: action||[cli.CLOSE], duration: -1}) can.page.style(can, carte._target, html.TOP, 200, html.BOTTOM, ""); return carte }, - toastProcess: function(can, content, title) { return can.user.toast(can, {content: content||ice.PROCESS, title: title||can._name, duration: -1, caller: 2}) }, - toastSuccess: function(can, content, title) { return can.user.toast(can, {content: "\u2705 "+(content||ice.SUCCESS), title: title||can._name, caller: 2}) }, - toastFailure: function(can, content, title) { return can.user.toast(can, {content: "\u274C "+(content||ice.FAILURE), title: title||can._name, duration: 10000, caller: 2}) }, + toastProcess: function(can, content, title) { return can.user.toast(can, {content: content||ice.PROCESS, title: title, duration: -1, caller: 2}) }, + toastSuccess: function(can, content, title) { return can.user.toast(can, {content: "\u2705 "+(content||ice.SUCCESS), title: title, caller: 2}) }, + toastFailure: function(can, content, title) { return can.user.toast(can, {content: "\u274C "+(content||ice.FAILURE), title: title, duration: 10000, caller: 2}) }, toast: function(can, content, title, duration, progress, caller) { - var meta = can.base.isObject(content)? content: {content: content, title: title||can._name.split(nfs.PS).slice(-2).join(nfs.PS), duration: duration, progress: progress, caller: caller} + var meta = can.base.isObject(content)? content: {content: content, title: title||can.Conf(ctx.INDEX)||can._name.split(nfs.PS).slice(-2).join(nfs.PS), duration: duration, progress: progress, caller: caller} var width = meta.width||400; if (width < 0) { width = window.innerWidth + width } meta.action = meta.action||[""] var ui = can.page.Append(can, document.body, [{view: [[chat.TOAST, chat.FLOAT]], style: {left: (window.innerWidth-width)/2, width: width, top: can.page.height()/2}, list: [ {text: [meta.title||"", html.DIV, html.TITLE], title: "点击复制", onclick: function(event) { can.user.copy(event, can, meta.title) }}, @@ -265,6 +265,8 @@ Volcanos("user", { header: function(can) { if (!can._root) { return } var header = can._root.Header var meta = { + space: {view: [[html.ITEM, html.SPACE]], style: {"flex-grow": "1"}, _init: function(target) { + }}, time: {view: [[html.ITEM, mdb.TIME]], _init: function(target) { can.core.Timer({interval: 100}, function() { can.page.Modify(can, target, can.user.time(can, null, "%H:%M:%S %w")) }) can.onappend.figure(can, {action: "date", _hold: true}, target, function(sub, value) {}) @@ -275,6 +277,6 @@ Volcanos("user", { usernick: {view: [[html.ITEM, aaa.USERNICK], "", can.user.info.usernick], onclick: function(event) { header && header.onaction.usernick(event, header) }}, - }; return can.core.List(can.base.getValid(can.core.List(arguments).slice(1), [mdb.TIME, aaa.AVATAR, aaa.USERNICK]), function(item) { return meta[item] }) + }; return can.core.List(can.base.getValid(can.core.List(arguments).slice(1), [html.SPACE, mdb.TIME, aaa.AVATAR, aaa.USERNICK]), function(item) { return meta[item] }) } }) diff --git a/panel/action.js b/panel/action.js index a37ae7a4..abf1ec1f 100644 --- a/panel/action.js +++ b/panel/action.js @@ -70,23 +70,27 @@ Volcanos(chat.ONACTION, {_init: function(can, target) { if (arg[0] == mdb.PLUGIN) { can.onexport.plugin(can, msg, arg, fields) } if (arg[0] == ctx.COMMAND) { can.onexport.command(can, msg, arg, fields) } }, - onkeydown: function(can, msg, model) { if (can.isCmdMode() && !msg._event.metaKey) { - var sub = can.core.Value(can._plugins[0], chat._OUTPUTS_CURRENT); sub && can.core.CallFunc([sub, "onaction.onkeydown"], {event: msg._event, can: sub}); return - } + onkeydown: function(can, msg, model) { + if (can.isCmdMode() && !msg._event.metaKey) { + var sub = can.core.Value(can._plugins[0], chat._OUTPUTS_CURRENT); sub && can.core.CallFunc([sub, "onaction.onkeydown"], {event: msg._event, can: sub}); return + } if (can.onkeymap.selectCtrlN(msg._event, can, can._action, html.DIV_ITEM)) { return } can._keylist = can.onkeymap._parse(msg._event, can, model, can._keylist||[], can._output) }, onresize: function(can) { can.onaction.layout(can), window.setsize && window.setsize(can.page.width(), can.page.height()) }, ontitle: function(can, msg) { can.onlayout._storage(can, "") }, + portal: function(can) { + can.user.opens("/wiki/portal/") + }, layout: function(can, button, skip) { can.page.ClassList.del(can, can._target, can._layout||can.onlayout._storage(can)), can._header_tabs && can.onmotion.hidden(can, can._header_tabs) button = (can.onlayout._storage(can, can._layout = button == ice.AUTO? "": button))||can.misc.SearchOrConf(can, html.LAYOUT), can.page.ClassList.add(can, can._target, button) can.onengine.signal(can, chat.ONLAYOUT, can.request({}, {layout: button})), can._root.River && can._river_show === false && can.onmotion.hidden(can, can._root.River._target), skip || can.onlayout._init(can) can.isCmdMode() || can.core.List(can._plugins, function(sub) { sub._delay_refresh = false, can.page.ClassList.set(can, sub._target, html.OUTPUT, [TABVIEW, HORIZON, VERTICAL].indexOf(button) > -1) }) var cb = can.onlayout[button]; can.base.isFunc(cb) && cb(can) || can.onlayout._plugin(can, button) }, - _menus: [[html.LAYOUT, ice.AUTO, TABS, TABVIEW, HORIZON, VERTICAL, GRID, FREE, FLOW, PAGE]], - _trans: kit.Dict(html.LAYOUT, "布局", ice.AUTO, "默认布局", TABS, "标签布局", TABVIEW, "标签分屏", HORIZON, "左右分屏", VERTICAL, "上下分屏", GRID, "网格布局", FREE, "自由布局", FLOW, "流动布局", PAGE, "网页布局"), + _menus: [[html.LAYOUT, ice.AUTO, TABS, TABVIEW, HORIZON, VERTICAL, GRID, FREE, FLOW, PAGE], "portal"], + _trans: kit.Dict("portal", "首页", html.LAYOUT, "布局", ice.AUTO, "默认布局", TABS, "标签布局", TABVIEW, "标签分屏", HORIZON, "左右分屏", VERTICAL, "上下分屏", GRID, "网格布局", FREE, "自由布局", FLOW, "流动布局", PAGE, "网页布局"), }) Volcanos(chat.ONLAYOUT, { tabs: function(can) { can.getActionSize(function(height, width) { can.ConfHeight(height-can.Conf(html.MARGIN_Y)+html.ACTION_MARGIN), can.ConfWidth(width-can.Conf(html.MARGIN_X)) }) diff --git a/panel/search.js b/panel/search.js index 9b49a06a..0e84bed9 100644 --- a/panel/search.js +++ b/panel/search.js @@ -8,7 +8,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg) { can.onmotion.clear(can, can _size: function(can) { can.ui && can.getActionSize(function(left, top, width, height) { can.page.style(can, can._target, {left: left||0, top: top||0, width: width}), can.page.style(can, can._output, html.MAX_HEIGHT, height -= 2*html.PLUGIN_MARGIN+html.ACTION_HEIGHT+can.onexport.statusHeight(can)) can.core.List([can.ui.content, can.ui.display], function(target) { can.page.style(can, target, html.MAX_WIDTH, can.ConfWidth(width-2*html.PLUGIN_MARGIN)) }) - can.ConfHeight(can.base.Min(height-can.ui.content.offsetHeight-can.ui.display.offsetHeight-html.ACTION_HEIGHT, height/2)) + can.ConfHeight(can.base.Min(height-can.ui.content.offsetHeight-can.ui.display.offsetHeight-1, height/2)) }) }, _input: function(can, msg, arg, fields) { if (can.base.contains(arg[1], ";")) { arg = can.core.Split(arg[1], "\t ;", "\t ;") } can.run(can.request({}, {fields: fields.join(mdb.FS)}, msg), arg, function(res) { can.db.type = arg[0] diff --git a/plugin/local/wiki/feel.css b/plugin/local/wiki/feel.css index da50cdc0..87911d90 100644 --- a/plugin/local/wiki/feel.css +++ b/plugin/local/wiki/feel.css @@ -1,5 +1,7 @@ -fieldset.feel div.output img { display:block; float:left; } -fieldset.feel div.output video { display:block; float:left; } -fieldset.feel.play.float div.output img { display:block; float:none; margin:auto; } -fieldset.feel.play.float div.output video { display:block; float:none; margin:auto; } -fieldset.feel.play.float div.status { display:block; } +fieldset.feel>div.output { display:flex; justify-content:center; } +fieldset.feel>div.output div.project { flex:0 0 230px; } +fieldset.feel>div.output div.project div.item.filter input { width:100%; } +fieldset.feel>div.output div.content.float { padding:0; position:fixed; left:0; top:0; } +fieldset.feel>div.output div.content:not(.hide) { display:flex; justify-content:center; } +fieldset.feel>div.output div.display:not(.hide) { display:flex; justify-content:center; flex-wrap:wrap; max-height:100%; } +fieldset.feel>div.output img { margin-bottom:0; } diff --git a/plugin/local/wiki/feel.js b/plugin/local/wiki/feel.js index b8e2dd39..7598fad0 100644 --- a/plugin/local/wiki/feel.js +++ b/plugin/local/wiki/feel.js @@ -1,65 +1,95 @@ -Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.clear(can), can.dir_root = msg.Option(nfs.DIR_ROOT) - can._path = can.request(), can.list = [], msg.Table(function(value) { can.base.endWith(value.path, nfs.PS)? can._path.Push(value): can.list.push(value) }) - can.ui = can.onappend.layout(can, [html.PROJECT, html.DISPLAY]) - can._path.Table(function(item) { item.name = item.path - can.onimport.item(can, item, function() { can.Option(nfs.PATH, item.path), can.Update() }, function() {}, can.ui.project) - }), cb(msg), can.onimport.page(can, can.list, can.begin = parseInt(msg.Option(cli.BEGIN)||"0")) - can.isCmdMode() || can.onmotion.hidden(can, can._action), can.onmotion.delay(can, function() { can.onimport.layout(can) }) - can.user.isMobile && can.onmotion.hidden(can, can.ui.project) +Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb) { can.onmotion.clear(can) + can.ui = can.onappend.layout(can, [html.PROJECT, [html.CONTENT, html.DISPLAY]]) + can.dir_root = msg.Option(nfs.DIR_ROOT), can.list = [], can._path = can.request(), cb && cb(msg) + msg.Table(function(item) { item.name = can.base.trimPrefix(item.path, can.Option(nfs.PATH)) + can.base.endWith(item.path, nfs.PS)? can.onimport.item(can, item, function(event) { can.Option(nfs.PATH, item.path) && can.Update(event) }): can.list.push(item) + }) + can.core.List(can.list, function(item, index) { item.nick = (can.misc.localStorage(can, can.onexport.key(can, "p", can.onimport._file(can, item.path)))||"")+" "+item.name; var target = can.onimport.item(can, item, function(_event) { + can.cb = function(event) { var target = _event.target, next = _event.target.nextSibling + can.misc.localStorage(can, can.onexport.key(can, "last"), item.path) + can.video = event.target, can.Status(item), target.innerHTML = parseInt(event.target.currentTime*100/event.target.duration)+"% "+item.name + if (event.type == "ended" && next) { can.onmotion.delay(can, function() { next.click() }, 3000), can.user.toast(can, "3s 后即将播放下一个", "", 3000) } + } + can.onmotion.clear(can, can.ui.content) + can.onimport.file(can, item.path, item, index, can.ui.content, can.ConfHeight()-can.onexport.height(can)-1, true).focus() + }, function() {}, can.ui.project); item.path == can.misc.localStorage(can, can.onexport.key(can, "last")) && target.click() }) + can.onimport.page(can, can.list, can.begin = parseInt(msg.Option(cli.BEGIN)||"0")) }, - _file: function(can, path, index) { var p = location.href.indexOf(ice.HTTP) == 0? "": "http://localhost:9020" + _file: function(can, path) { var p = location.href.indexOf(ice.HTTP) == 0? "": "http://localhost:9020" return path.indexOf(ice.HTTP) == 0? path: p+can.base.Path(web.SHARE_LOCAL, can.dir_root||"", path) }, - file: function(can, path, index) { path = can.onimport._file(can, path, index) + file: function(can, path, item, index, target, height, auto) { path = can.onimport._file(can, path) var cb = can.onfigure[can.base.Ext(path)]||can.onfigure[wiki.IMAGE]; can.Status(nfs.FILE, path) - can.base.isFunc(cb) && can.page.Append(can, can.ui.display, [cb(can, path, index)]) + return cb && can.page.Append(can, target||can.ui.display, [cb(can, path, item, index, height, auto)])._target }, page: function(can, list, begin, limit) { can.onmotion.clear(can, can.ui.display) begin = parseInt(begin||can.begin), limit = parseInt(limit||can.Action(mdb.LIMIT)) - for (var i = begin; i < begin+limit; i++) { list && list[i] && can.onimport.file(can, list[i].path, i) } + for (var i = begin; i < begin+limit; i++) { list && list[i] && can.onimport.file(can, list[i].path, list[i], i) } can.Status({begin: begin, limit: limit, total: list.length}) }, - layout: function(can) { - can.page.style(can, can.ui.display, html.WIDTH, can.ConfWidth()-can.ui.project.offsetWidth-1) - can.page.style(can, can.ui.project, html.HEIGHT, can.ui.display.offsetHeight) - // can.page.style(can, can.ui.display, html.WIDTH, "") + layout: function(can, height, width) { + can.page.style(can, can.ui.content, html.WIDTH, can.ConfWidth()-can.ui.project.offsetWidth) + can.page.style(can, can.ui.display, html.WIDTH, can.ConfWidth()-can.ui.project.offsetWidth) + can.list.length > 0 && can.page.style(can, can.ui.project, html.HEIGHT, can.base.Min(can.ui.display.offsetHeight, can.Action(html.HEIGHT), can.ConfHeight())) + can.isCmdMode() && can.page.style(can, can.ui.project, html.HEIGHT, can.ConfHeight()) }, }, [""]) Volcanos(chat.ONFIGURE, { - png: function(can, path, index) { return can.onfigure.image(can, path, index) }, - jpg: function(can, path, index) { return can.onfigure.image(can, path, index) }, - jpeg: function(can, path, index) { return can.onfigure.image(can, path, index) }, - image: function(can, path, index) { return {img: path, height: can.onexport.height(can), - onmouseover: function(event) { can.Status(nfs.FILE, path) }, + png: function(can, path, item, index, height) { return can.onfigure.image(can, path, item, index, height) }, + jpg: function(can, path, item, index, height) { return can.onfigure.image(can, path, item, index, height) }, + jpeg: function(can, path, item, index, height) { return can.onfigure.image(can, path, item, index, height) }, + image: function(can, path, item, index, height) { return {img: path, height: height||can.onexport.height(can), + onmouseover: function(event) { can.Status(nfs.FILE, path), can.Status(item) }, onclick: function(event) { can.ondetail._init(can, index) }, } }, - video: function(can, path) { var auto = can.user.isMobile&&can.Action(mdb.LIMIT)!="1"? false: true, loop = true, total = 0; function cb(event) { } - return {type: html.VIDEO, style: {height: can.onexport.height(can)}, className: "preview", - data: {src: path, controls: "controls", autoplay: false&&auto, loop: loop, playbackRate: parseFloat(can.Action(html.SPEED))}, - oncontextmenu: cb, onplay: cb, onpause: cb, onended: cb, - onmouseover: function(event) { can.Status(nfs.FILE, path) }, + video: function(can, path, item, index, height, auto) { var total = 0, cb = can.cb||function cb(event) { } + var init, last = can.misc.localStorage(can, can.onexport.key(can, path))||0 + return {type: html.VIDEO, style: {height: height||can.onexport.height(can)}, + data: {src: path, controls: "controls", autoplay: auto, playbackRate: parseFloat(can.Action(html.SPEED))}, + oncanplay: cb, onplay: cb, onpause: cb, oncontextmenu: cb, onratechange: cb, onseeked: cb, + onmouseover: function(event) { can.Status(nfs.FILE, path), can.Status(item) }, onloadedmetadata: function(event) { total = event.timeStamp event.target.currentTime = can._msg.currentTime || 0 - }, onloadeddata: cb, ontimeupdate: function(event) { - can.Status(nfs.FILE) == path && can.Status("position", can.onexport.position(can, (can._msg.currentTime=event.target.currentTime)-1, event.target.duration)) + }, onloadeddata: cb, ontimeupdate: function(event) { cb(event) + can.misc.localStorage(can, can.onexport.key(can, path), event.target.currentTime) + can.misc.localStorage(can, can.onexport.key(can, "p", path), parseInt(event.target.currentTime*100/event.target.duration)+"%") + if (!init) { init = true, event.target.currentTime = last } + can.Status("position", can.onexport.position(can, (can._msg.currentTime=event.target.currentTime)-1, event.target.duration)) + }, onended: function(event) { cb(event) + can.misc.localStorage(can, can.onexport.key(can, path), "") }, } }, - mp4: function(can, path) { return can.onfigure.video(can, path) }, - m4v: function(can, path) { return can.onfigure.video(can, path) }, - mov: function(can, path) { return can.onfigure.video(can, path) }, - webm: function(can, path) { return can.onfigure.video(can, path) }, + mp4: function(can, path, item, index, height, auto) { return can.onfigure.video(can, path, item, index, height, auto) }, + m4v: function(can, path, item, index, height, auto) { return can.onfigure.video(can, path, item, index, height, auto) }, + mov: function(can, path, item, index, height, auto) { return can.onfigure.video(can, path, item, index, height, auto) }, + webm: function(can, path, item, index, height, auto) { return can.onfigure.video(can, path, item, index, height, auto) }, }) -Volcanos(chat.ONACTION, {list: [ - [html.HEIGHT, ice.AUTO, 100, 200, 400, 600, 800, ice.AUTO], +Volcanos(chat.ONACTION, {list: ["full", + [html.HEIGHT, 100, 200, 400, 600, 800, "max", "hide", ice.AUTO], [mdb.LIMIT, 6, 1, 3, 6, 9, 12, 15, 20, 30, 50], - [html.SPEED, 0.1, 0.2, 0.5, 1, 2, 3, 5, 10], + [html.SPEED, 1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 5, 10], ], height: function(event, can, key, value) { can.Action(key, value), can.onimport.page(can, can.list) }, limit: function(event, can, key, value) { can.Action(key, value), can.onimport.page(can, can.list) }, speed: function(event, can, key, value) { can.Action(key, value), can.onimport.page(can, can.list) }, prev: function(event, can) { if (can.begin > 0) { can.begin -= parseInt(can.Action(mdb.LIMIT)), can.onimport.page(can, can.list) } else { can.user.toast(can, "已经是第一页了") } }, next: function(event, can) { if (can.begin + parseInt(can.Action(mdb.LIMIT)) < can.list.length) { can.begin += parseInt(can.Action(mdb.LIMIT)), can.onimport.page(can, can.list) } else { can.user.toast(can, "已经是最后一页了") } }, + full: function(event, can) { + var show = can.onmotion.toggle(can, can.ui.project); can.onmotion.toggle(can, can.ui.display), can.onimport.layout(can, can.ConfHeight(), can.ConfWidth()) + can.page.ClassList.set(can, can.ui.content, "float", !show), can.page.Select(can, can.ui.content, "*", function(target) { target.focus() + can.page.style(can, target, html.HEIGHT, can.ConfHeight()+(!show? 2*html.ACTION_HEIGHT: 0)-can.ui.display.offsetHeight) + }) + }, + onkeydown: function(event, can) { try { + if (event.target != can.video) { + if (event.key == "ArrowLeft") { can.video.currentTime -= 15 } + if (event.key == "ArrowRight") { can.video.currentTime += 15 } + } + if (event.key == "Escape") { can.onaction.full(event, can) } + if (event.key == "ArrowUp") { can.user.toast(can, parseInt((can.video.volume += 0.1)*100)) } + if (event.key == "ArrowDown") { can.user.toast(can, parseInt((can.video.volume -= 0.1)*100)) } + } catch (e) {} }, record0: function(event, can, name, cb) { can.user.input(event, can, [{name: nfs.FILE, value: name}], function(list) { var height = window.innerHeight navigator.mediaDevices.getDisplayMedia({video: {height: height}}).then(function(stream) { can.core.Next([3, 2, 1], function(item, next) { can.user.toast(can, item + "s 后开始截图"), can.onmotion.delay(can, next, 1000) }, function() { can.user.toast(can, "现在开始截图") @@ -101,7 +131,11 @@ Volcanos(chat.ONDETAIL, {list: ["关闭", "上一个", "下一个", "设置头 "下载": function(event, can) { can.user.download(can, path = can.onimport._file(can, can.list[can.order].path)) }, "删除": function(event, can) { can.runAction(event, nfs.TRASH, [can.list[can.order].path], function(msg) { can.user.toastSuccess(can, "删除成功") }, true) }, }) -Volcanos(chat.ONEXPORT, {list: [cli.BEGIN, mdb.LIMIT, mdb.TOTAL, nfs.FILE, "position"], - height: function(can) { var height = can.Action(html.HEIGHT); return parseInt(height == ice.AUTO? can.base.Min(can.ConfHeight()/4, 200): height)||200 }, +Volcanos(chat.ONEXPORT, {list: [cli.BEGIN, mdb.LIMIT, mdb.TOTAL, nfs.FILE, nfs.SIZE, "position"], + height: function(can) { var height = can.Action(html.HEIGHT); return parseInt( + height == "hide"? 0: height == "max"? can.ConfHeight(): height == ice.AUTO? can.base.Min(can.ConfHeight()/4, 200): height) }, position: function(can, index, total) { total = total || can.max; return parseInt((index+1)*100/total)+"%"+" = "+(parseInt(index)+1)+nfs.PS+parseInt(total) }, + key: function(can) { + return [can.Conf(ctx.INDEX)].concat(can.core.List(arguments).slice(1)).join(":") + }, }) diff --git a/plugin/local/wiki/word.css b/plugin/local/wiki/word.css index f5dc0751..8dbdbcb8 100644 --- a/plugin/local/wiki/word.css +++ b/plugin/local/wiki/word.css @@ -9,13 +9,13 @@ fieldset.word>div.output div.story.flex>* { padding:20px; } fieldset.word>div.output h2.story[data-type=spark][data-name=title] { text-align:center; } fieldset.word>div.output h2 { margin-top:40px; } fieldset.word>div.output h3 { margin-top:20px; } -fieldset.word>div.output table { width:100%; text-align:center; } +fieldset.word>div.output table { width:100%; } fieldset.word>div.output img { max-height:100%; max-width:100%; } fieldset.word>div.output video { max-height:100%; width:100%; } fieldset.word>div.output iframe { height:480px; width:100%; } fieldset.word>div.output svg.story[data-index] text { cursor:pointer; } fieldset.word>div.output input.story[type=button] { font-family:system-ui; font-weight:bold; padding:20px 40px; margin:10px; height:64px; } -fieldset.word>div.output fieldset.web.code.inner.output div.output { border-left:blue solid 5px; } +fieldset.word>div.output fieldset.web.code.inner.output div.output td.line { border-right:gray solid 1px; } fieldset.word>div.navmenu { background-color:inherit; overflow:auto; min-width:120px; clear:both; float:left; } fieldset.word>div.navmenu div.list { margin-left:20px; } @@ -25,7 +25,7 @@ fieldset.word>div.navmenu>div.item { font-size:1.6em; } div.story[data-type=spark] label { user-select:none; } div.story[data-type=spark_tabs] { margin-top:20px; } div.story[data-type=spark_tabs]>div.tabs>div.item { font-style:italic; padding:5px 20px; height:32px; float:left; } -div.story[data-type=spark_tabs]>div.tabs>div.item.select { border-bottom:blue solid 2px; } +div.story[data-type=spark_tabs]>div.tabs>div.item.select { border-bottom:var(--code-border-color) solid 2px; } div.story[data-type=spark_tabs]>div.story:not(.select) { display:none; } fieldset.word.play.float { top:0; } diff --git a/plugin/local/wiki/word.js b/plugin/local/wiki/word.js index 22d38681..bf478266 100644 --- a/plugin/local/wiki/word.js +++ b/plugin/local/wiki/word.js @@ -1,7 +1,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, target) { can.Conf(html.PADDING, 10) can.onmotion.clear(can), can.page.Modify(can, target, msg.Result()), can.onimport._display(can, target) }, - _display: function(can, target, cb) { can.onappend.style(can, "word") + _display: function(can, target, cb) { can.onappend.style(can, web.WIKI_WORD) can.page.Select(can, target, wiki.STORY_ITEM, function(target) { var meta = target.dataset||{}; cb && cb(target, meta) can.core.CallFunc([can.onimport, can.onimport[meta.name]? meta.name: meta.type||target.tagName.toLowerCase()], [can, meta, target]) var _meta = can.base.Obj(meta.meta); _meta && _meta.style && can.page.style(can, target, can.base.Obj(_meta.style))