From 5b9f0bdb66d2d517649a5eb7a506e21bb137ab84 Mon Sep 17 00:00:00 2001 From: shy Date: Sun, 30 Jun 2024 19:52:29 +0800 Subject: [PATCH] add some --- frame.js | 19 +++-- index.css | 23 +++--- lib/base.js | 3 + lib/user.js | 17 ++-- plugin/local/wiki/feel.css | 28 ++++--- plugin/local/wiki/feel.js | 161 +++++++++++++++++++++++++------------ plugin/state.js | 8 +- plugin/table.js | 2 +- 8 files changed, 164 insertions(+), 97 deletions(-) diff --git a/frame.js b/frame.js index 3ca5c296..d5b9897e 100644 --- a/frame.js +++ b/frame.js @@ -266,7 +266,8 @@ Volcanos(chat.ONAPPEND, { }}) } can.core.List(list, function(item) { - item.value = can.sup && can.sup.onexport.session && can.sup.onexport.session(can.sup, "action:"+item.name||item[0]) || item.value + var value = can.sup && can.sup.onexport.session && can.sup.onexport.session(can.sup, "action:"+item.name||item[0]) || item.value + if (value) { item.value = value } 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) @@ -330,7 +331,7 @@ Volcanos(chat.ONAPPEND, { sub.db.hash = can.base.getValid(can.isCmdMode()? can.misc.SearchHash(can): [], can.onexport.storage(can, "hash"))||[] var last = can.sub; last && can.core.CallFunc([last, "onaction.hidden"], {can: last}) sub.run = function(event, cmds, cb, silent) { var msg = sub.request(event)._caller() - msg.RunAction(event, sub, cmds) || can.Update(event, can.Input(cmds, !silent), cb, silent) + msg.RunAction(event, sub, cmds) || can.Update(event, cmds||can.Input(cmds, !silent), cb, silent) }, can._outputs = can._outputs||[], can._outputs.push(sub), sub.sup = can, can.sub = sub sub._index = can._index, can._msg = sub._msg = msg, sub.Conf(sub._args = can.base.ParseURL(display)) sub._trans = can.base.Copy(can.base.Copy(sub._trans||{}, can._trans), can.core.Value(sub, [chat.ONACTION, chat._TRANS])) @@ -1052,7 +1053,7 @@ Volcanos(chat.ONMOTION, { can.core.Timer({interval: 10, length: offset/step}, function() { parent.scrollTop += step }, function() { parent.scrollTop = (target.offsetTop-margin), delete(parent._scroll) }) }, clearFloat: function(can) { - var list = ["fieldset.input.float", "div.input.float", "div.carte.float"]; for (var i = 0; i < list.length; i++) { + var list = ["fieldset.input.float", "div.input.float", "div.carte.float", "div.toast.float"]; for (var i = 0; i < list.length; i++) { if (can.page.Select(can, document.body, list[i], function(target) { return target._close? target._close(): can.page.Remove(can, target) }).length > 0) { return true } } }, @@ -1151,13 +1152,11 @@ Volcanos(chat.ONMOTION, { can.user.toast(can, "filter out "+count+" lines") }, 300) }, - cacheClear: function(can, key) { - if (!key) { - delete(can._cache_data), delete(can._output._cache) - return - } - delete(can._cache_data[key]) - can.core.List(arguments, function(target, index) { index > 1 && target && target._cache && delete(target._cache[key]) }) + cacheClear: function(can, key, target) { + if (key) { delete(can._cache_data[key]) } else { delete(can._cache_data) } + can.core.List(arguments, function(target, index) { if (index > 1 && target && target._cache) { + if (key) { delete(target._cache[key]) } else { delete(target._cache), delete(target._cache_key) } + } }) }, cache: function(can, next) { var list = can.base.getValid(can.base.Obj(can.core.List(arguments).slice(2)), [can._output]) var data = can._cache_data = can._cache_data||{}, old = list[0]._cache_key diff --git a/index.css b/index.css index 4e8e279c..c2cd4903 100644 --- a/index.css +++ b/index.css @@ -110,7 +110,10 @@ body.width1 { /* 320-640 手机竖屏 */ --table-button:2; --card-button:3; } body.en { --card-button:3; } -body.mobile { --footer-height:60px; --svg-font-size:13px; } +body.mobile { + --footer-height:60px; --svg-font-size:13px; + --project-width:240px; +} body.cmd.web.code.vimer { --code-line-height:24px; } /* element */ * { box-sizing:border-box; padding:0; border:0; margin:0; tab-size:4; } @@ -209,6 +212,7 @@ fieldset.studio>div.output>div.layout>div.layout>div.content>fieldset.story>form fieldset.studio>div.output>div.layout>div.layout>div.content>fieldset.story>div.action>div.item.state.button.full.icons { display:none; } div.output>div.layout>div.layout { position:relative; } /* project */ +div.project { background-color:var(--plugin-bg-color); } div.project div.action:not(.hide) { width:100%; display:flex; overflow:hidden; } div.project div.action div.item input { border-right:var(--box-border); } div.project div.action div.item input:hover { border-right:var(--box-notice); } @@ -223,8 +227,9 @@ div.project div.item { position:relative; } div.project div.item.select { border-right:var(--item-notice); } div.project>div.item.select { position:sticky; top:32px; bottom:0; } div.project div.item:not(.hide) { white-space:pre; line-height:24px; cursor:pointer; padding:0 var(--input-padding); display:flex; align-items:center; } +body.mobile div.project div.item:not(.album):not(.hide) { padding:20px var(--input-padding); } div.project div.item:not(.hide)>i:first-child { margin-right:var(--input-margin); } -div.project div.item:not(:hover) input:not([type=button]) { border-right:0; } +div.project>div.item:not(:hover) input:not([type=button]) { border-right:0; } div.project>div.item:not(:hover) input:not([type=button]) { border-left:0; } div.project>div.zone>div.action div.item:not(:hover) input:not([type=button]) { border-left:0; } div.project div.item.filter { background-color:var(--plugin-bg-color); padding:0; width:100%; position:sticky; top:0; z-index:1; } @@ -237,9 +242,10 @@ div.project div.item>div.name { padding:0 var(--input-padding); } div.project div.item>div.icon { position:absolute; right:var(--input-padding); } div.project div.item>div.icon:hover { background-color:var(--hover-bg-color); } div.project div.item:not(:hover)>div.icon { display:none; } -div.project div.item>i:last-child { position:absolute; right:var(--input-padding); } -div.project div.item>i:last-child:hover { background-color:var(--hover-bg-color); } -div.project div.item:not(:hover)>i:last-child { display:none; } +div.project div.item:not(.button)>i:last-child { position:absolute; right:var(--input-padding); } +div.project div.item:not(.button)>i:last-child:hover { background-color:var(--hover-bg-color); } +body:not(.mobile) div.project div.item:not(.button):not(:hover)>i:last-child { display:none; } +body.mobile div.project div.item>i:last-child { display:none; } div.project div.zone>div.item { text-align:center; padding:var(--input-padding); display:flex; align-items:center; } div.project div.zone>div.item span:hover { background-color:var(--hover-bg-color); } div.project>div.zone>div.item span:first-child { font-style:italic; font-weight:bold; line-height:var(--action-height); } @@ -503,7 +509,7 @@ span.keyword { color:var(--code-keyword); } span.function { color:var(--code-fun span.item.select { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } span.item:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } span.icon:hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } -div.item:not(.text):hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } +body:not(.mobile) div.item:not(.text):hover { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } div.item.select:not(.button) { background-color:var(--hover-bg-color); color:var(--hover-fg-color); } div.item.button.danger input:hover[type=button] { background-color:var(--danger-bg-color); color:var(--danger-fg-color); } div.item.button.notice input:hover[type=button] { background-color:var(--notice-bg-color); color:var(--notice-fg-color); } @@ -698,7 +704,6 @@ div.item.text.url>input { width:var(--river-width); } div.item.text.port>input { width:80px; } div.item.text.line>input { width:80px; } body:not(.mobile) div.item.text.hash>input { width:320px; } -fieldset.plugin>form.option>div.item.text.path>input { width:var(--project-width); } div.item.text.limit>input { width:var(--button-width); } div.item.text.offend>input { width:var(--button-width); } body:not(.width2):not(.mobile) fieldset.plugin>form.option>div.item.text.path>input { width:var(--project-width); } @@ -807,8 +812,8 @@ body.mobile fieldset.plugin>legend { box-shadow:none; } body.mobile:not(.landscape) fieldset.plugin.cmd:not(.output)>div.header { display:none !important; } body.mobile div.output.card { overflow-x:hidden; } body.mobile div.output>div.project { position:absolute; left:0; top:0; z-index:2; } -body.mobile div.output>div.project { flex:0 0 240px; width:240px; } -body.mobile div.output>div.project div.item { height:var(--action-height); } +// body.mobile div.output>div.project { flex:0 0 240px; width:240px; } +body.mobile div.output>div.project div.item:not(.album) { height:var(--action-height); } body.mobile div.output>div.project { background-color:var(--plugin-bg-color); } body.mobile fieldset>div.output>div.code>img { max-width:390px; } body.mobile fieldset>div.output>div.code>div.form input[type=button] { width:100%; } diff --git a/lib/base.js b/lib/base.js index 009eb2bb..bbf173d3 100644 --- a/lib/base.js +++ b/lib/base.js @@ -99,6 +99,9 @@ Volcanos("base", { } } } + if (value.indexOf(year) == -1) { + return value.split(" ")[0] + } return prefix+this.trimPrefix(value.split(":").slice(0, 2).join(":"), pre, year) }, Time: function(time, fmt) { var now = this.Date(time) diff --git a/lib/user.js b/lib/user.js index dd4face6..985ec636 100644 --- a/lib/user.js +++ b/lib/user.js @@ -91,6 +91,7 @@ Volcanos("user", { meta.title = meta.title||can.core.Keys(can.ConfSpace(), can.ConfIndex())||can._name.split(nfs.PS).slice(-2).join(nfs.PS) meta.hash && can.misc.isDebug(can) && (meta.title += " "+meta.hash.slice(0, 6)), meta.action = meta.action||[""] var width = meta.width||(html.QRCODE_WIDTH+2*html.PLUGIN_PADDING+10); if (width < 0) { width = can.page.width() + width } + meta.title = can.base.replaceAll(meta.title||"", "%2F", "/") var ui = can.page.Append(can, meta.action.list || meta.action.length > 1 || !can._root || !can._root.Action || !can._root.Action._toast ? document.body: can._root.Action._toast, [{view: [[chat.TOAST, can.Conf(ctx.INDEX)||can.ConfIndex(), meta.style, chat.FLOAT]], style: {width: width}, list: [ {view: [wiki.TITLE, "", meta.title||""], title: "点击复制", onclick: function(event) { can.user.copy(event, can, meta.title) }}, {view: [cli.CLOSE, "", can.page.unicode.close], title: "点击关闭", onclick: function() { action.close() }}, @@ -102,13 +103,9 @@ Volcanos("user", { ] }]); can.onengine.signal(can, chat.ONTOAST, can.request({}, {time: can.misc._time(), title: meta.title, content: meta.content})) meta.action.meta && can.core.Item(meta.action.meta, function(key, cb) { cb.help && can.core.Value(meta.action.meta, ["_trans", key], cb.help) }) var action = can.onappend._action(can, meta.action.list? meta.action.list.reverse(): meta.action, ui.action, {_trans: meta.action.meta? meta.action.meta._trans: {}, - _engine: function(event, button) { - can.core.CallFunc(meta.action.meta? meta.action.meta[button]: meta.action, [event, button]) - action.close(event) - }, + _engine: function(event, button) { can.core.CallFunc(meta.action.meta? meta.action.meta[button]: meta.action, [event, button]), action.close(event) }, open: function(event) { meta.content.indexOf(ice.HTTP) == 0 && can.user.open(meta.content), meta.title.indexOf(ice.HTTP) == 0 && can.user.open(meta.title) }, - close: function(event) { - event && event.isTrusted && can.onengine.signal(can, "onevent", can.request(event, {_type: "close"})) + close: function(event) { event && event.isTrusted && can.onengine.signal(can, "onevent", can.request(event, {_type: "close"})) action.timer.stop = true, can.page.Remove(can, ui._target) }, cancel: function(event) { action.timer.stop = true, can.page.Remove(can, ui._target) }, timer: can.core.Timer({interval: 100, length: (meta.duration||1000)/100}, function(event, interval, index) { @@ -117,11 +114,9 @@ Volcanos("user", { can.onmotion.delay(can, function() { can.page.Remove(can, ui._target) }, 1000) }), _target: ui._target, }); can.onmotion.story.auto(can, ui._target) - if (action._target.parentNode == document.body) { - can.onmotion.delay(can, function() { - can.page.style(can, action._target, html.TOP, (can.page.height() - action._target.offsetHeight)/4, html.LEFT, (can.page.width()-action._target.offsetWidth)/2) - }) - } + if (action._target.parentNode == document.body) { can.onmotion.delay(can, function() { + can.page.style(can, action._target, html.TOP, (can.page.height() - action._target.offsetHeight)/4, html.LEFT, (can.page.width()-action._target.offsetWidth)/2) + }) } if (meta.action && meta.action.length == 1 && meta.action[0] === "") { can.page.Select(can, action._target, html.DIV_ACTION, function(target) { can.onmotion.hidden(can, target) }) } can._toast && (typeof can._toast.close == code.FUNCTION && can._toast.close(), delete(can._toast)) diff --git a/plugin/local/wiki/feel.css b/plugin/local/wiki/feel.css index 019eeaaa..16034b77 100644 --- a/plugin/local/wiki/feel.css +++ b/plugin/local/wiki/feel.css @@ -1,22 +1,32 @@ -fieldset.feel:not(.cmd)>form.option>div.item.file { display:none; } +fieldset.feel>form.option>div.item.file { display:none; } body.mobile fieldset.feel>form.option>div.item.file { display:none; } +fieldset.feel.fullscreen>div.action>div.item:not(.fullscreen) { display:none; } +fieldset.feel>div.output>div.project>div.albums { display:flex; flex-wrap:wrap; } +fieldset.feel>div.output>div.project>div.albums>div.item.album { border-bottom:var(--box-notice3); border-color:transparent; width:33.3%; display:flex; flex-direction:column; } +fieldset.feel>div.output>div.project>div.albums>div.item.album.select { border-bottom:var(--box-notice3); border-right:none; } +fieldset.feel>div.output>div.project>div.albums>div.item.album.create { height:calc(var(--project-width)/3 - 10px); font-size:42px; display:flex; justify-content:center; align-items:center; } +fieldset.feel>div.output>div.project>div.albums>div.item.album img { height:calc(var(--project-width)/3 - 10px); width:100%; object-fit:cover; } fieldset.feel>div.output>div.project>div.item.select { border-width:3px; } fieldset.feel>div.output>div.project>div.item>img { padding:5px; } fieldset.feel>div.output>div.project>div.item>span.name { flex-grow:1; overflow:hidden; } fieldset.feel>div.output>div.project>div.item>span.progress { color:var(--notice-bg-color); margin-left:10px; } fieldset.feel>div.output>div.project>div.item>span.size { color:var(--disable-fg-color); font-size:var(--status-font-size); margin-left:10px; } +fieldset.feel>div.output>div.project>div.item>span.time { color:var(--disable-fg-color); font-size:var(--status-font-size); margin-left:10px; } fieldset.feel>div.output>div.layout>div.display { overflow:hidden; position:relative; } fieldset.feel>div.output>div.layout>div.display:not(.hide) { height:100px; display:flex; justify-content:center; align-items:center; gap:10px; } fieldset.feel>div.output>div.layout>div.display>.select { border:var(--box-notice); border-width:3px; } -fieldset.feel>div.output>div.layout>div.display>img { height:100px; width:100px; object-fit:cover; } -fieldset.feel>div.output>div.layout>div.display>video { height:100px; width:100px; object-fit:cover; } -fieldset.feel>div.output>div.layout>div.display>div.audio { word-break:break-all; height:100px; width:100px; display:flex; align-items:center; } +fieldset.feel>div.output>div.layout>div.display>img { height:100px; width:100px; object-fit:contain; } +fieldset.feel>div.output>div.layout>div.display>video { height:100px; width:100px; object-fit:contain; } +fieldset.feel>div.output>div.layout>div.display>div.audio { word-break:break-all; height:100px; width:100px; display:flex; align-items:end; } fieldset.feel>div.output>div.layout>div.display>div.audio:not(.select) { border:var(--box-border); } -fieldset.feel>div.output>div.layout>div.display>div.audio img.cover { height:94px; width:94px; position:absolute; } -fieldset.feel>div.output>div.layout>div.display>div.audio span.name { z-index:5; } -fieldset.feel>div.output>div.layout>div.display>img:hover { cursor:pointer; } -fieldset.feel>div.output>div.layout>div.display>video:hover { cursor:pointer; } -fieldset.feel>div.output>div.layout>div.display>div.audio:hover { cursor:pointer; } +fieldset.feel>div.output>div.layout>div.display>div.audio img.cover { height:98px; width:98px; position:absolute; } +fieldset.feel>div.output>div.layout>div.display>div.audio.select img.cover { height:94px; width:94px; position:absolute; } +fieldset.feel>div.output>div.layout>div.display>div.audio span.name { background-color:var(--hover-bg-color); color:white; z-index:5; } +fieldset.feel>div.output>div.layout>div.display>*.select { background-color:var(--hover-bg-color); } +fieldset.feel>div.output>div.layout>div.display>*:hover { background-color:var(--hover-bg-color); cursor:pointer; } +fieldset.feel>div.output>div.layout>div.display>img:hover { background-color:var(--hover-bg-color); cursor:pointer; } +fieldset.feel>div.output>div.layout>div.display>video:hover { background-color:var(--hover-bg-color); cursor:pointer; } +fieldset.feel>div.output>div.layout>div.display>div.audio:hover { background-color:var(--hover-bg-color); cursor:pointer; } fieldset.feel>div.output>div.layout>div.display>div.toggle { font-size:32px; padding:5px; padding-top:32px; height:100px; position:absolute; } fieldset.feel>div.output>div.layout>div.display>div.toggle.prev { left:0; } fieldset.feel>div.output>div.layout>div.display>div.toggle.next { right:0; } diff --git a/plugin/local/wiki/feel.js b/plugin/local/wiki/feel.js index 3f920c2d..608c3246 100644 --- a/plugin/local/wiki/feel.js +++ b/plugin/local/wiki/feel.js @@ -1,45 +1,65 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg, cb) { can.onappend.style(can, wiki.FEEL) - can.user.isMobile && (can.onaction.list = ["upload"]) - can.ui = can.onappend.layout(can), cb && cb(msg) - if (can.Action("sort") != mdb.TIME) { - can.onaction.sort({}, can, "sort", can.Action("sort")) - } else { - can.onimport._project(can, msg) - } - can.onimport.page(can, can.db.list, can.db.begin = 0) - can.onmotion.toggle(can, can.ui.display, true), can.onimport.layout(can) + can.user.isMobile && (can.onaction.list = [web.UPLOAD]) + can.run({}, [], function(_msg) { can.db.albums = _msg + can.ui = can.onappend.layout(can), cb && cb(msg) + if (can.base.isIn(can.Action("sort")||"", mdb.TIME, "")) { + can.onimport._project(can, msg) + } else { + can.onaction.sort({}, can, "sort", can.Action("sort")) + } can.onimport.page(can, can.db.list, can.db.begin = 0) + can.onmotion.toggle(can, can.ui.display, can.user.isMobile || can.page.isDisplay(can.ui.project)), can.onimport.layout(can) + }) }, _project: function(can, msg) { can.db.list = [], can.db.dir_root = msg.Option(nfs.DIR_ROOT) + can.ui.albums = can.page.Appends(can, can.ui.project, ["albums"])._target + can.db.albums.Table(function(value) { + can.page.Append(can, can.ui.albums, [{view: "item album "+(can.base.beginWith(can.Option(nfs.PATH), value.path)? "select": ""), background: value.cover, list: [ + {img: can.misc.Resource(can, value.cover||"usr/icons/background.jpg")}, {text: value.name}, + ], onclick: function(event) { + can.Option(nfs.PATH, value.path), can.Update() + }, oncontextmenu: function(event) { + can.user.carteItem(event, can, value) + }}]) + }) + can.page.Append(can, can.ui.albums, [{view: ["item album create", "", "+"], onclick: function(event) { + can.Update(event, [ctx.ACTION, mdb.CREATE]) + }}]) + can.ui.filter = can.onappend.filter(can, can.ui.project) + // var action = can.page.Append(can, can.ui.project, ["action"])._target + // can.onappend._action(can, can.onaction.list, action) msg.Table(function(item) { item.name = can.base.trimPrefix(item.path, can.Option(nfs.PATH)) can.base.endWith(item.path, "/") && (item.nick = [{img: can.misc.Resource(can, "usr/icons/dir.png")}, {text: [item.name, "", mdb.NAME]}]) can.base.endWith(item.path, nfs.PS)? can.onimport.item(can, item, function(event) { can.Option(nfs.PATH, item.path) && can.Update(event) }): can.db.list.push(item) }) - can.core.List(can.db.list, function(item, index) { var last = can.onexport.progress(can, "p."+item.path) + can.onmotion.cacheClear(can, "", can.ui.content) + can.db.hash[0] && msg.path.indexOf(can.db.hash[0]) == -1 && (can.db.hash[0] = "") + can.core.List(can.db.list, function(item, index) { var last = can.onexport.progress(can, "p."+item.path); + (!can.db.hash[0] || can.db.hash[0] == can.Option(nfs.PATH) || can.db.hash[0].indexOf(can.Option(nfs.PATH)) == -1) && (can.db.hash[0] = item.path) item.nick = [item.cover? {img: can.misc.Resource(can, item.cover)}: can.misc.isImage(can, item.path)? {img: can.misc.Resource(can, item.path)}: can.misc.isVideo(can, item.path)? {img: can.misc.Resource(can, "usr/icons/QuickTime Player.png")}: can.misc.isAudio(can, item.path)? {img: can.misc.Resource(can, "usr/icons/Music.png")}: null, - {text: [item.name, "", mdb.NAME]}, last && {text: [last, "", "progress"]}, {text: [item.size, "", nfs.SIZE]}, + {text: [item.name, "", mdb.NAME]}, {text: [last||"", "", "progress"]}, + can.Option(nfs.PATH) != "usr/icons/" && can.base.isIn(can.Action("sort")||"", mdb.TIME, "")? {text: [can.base.TimeTrim(item.time), "", mdb.TIME]}: {text: [item.size, "", nfs.SIZE]}, ] + item.title = [item.time, item.path, item.size].join("\n") item._hash = item.path, item._title = item.path.split("/").pop() item._target = can.onimport.item(can, item, function(event, item, show, target) { can.onimport._content(can, item, index, target) }) + item.title = "" }) }, - _content: function(can, item, index, target) { can.Option(nfs.FILE, item.name), can.Status(item) + _content: function(can, item, index, target) { can.Option(nfs.FILE, item.name), can.Status(item), can.ui.video = item._video, can.ui.current = item if (can.onexport.progress(can, "p."+item.path) == "100%") { can.onexport.progress(can, "p."+item.path, ""), can.onexport.progress(can, item.path, "") } + if (can.misc.isImage(can, item.path)) { can.onmotion.delay(can, function() { can.onaction.playnext(can) }, 5000) } if (!can.onmotion.cache(can, function() { return item.path }, can.ui.content)) { var progress - item._cb = function(event) { can.ui.video = event.target - var p = parseInt(event.target.currentTime*100/event.target.duration) + item._cb = function(event, video) { can.ui.video = item._video = video + var p = parseInt(video.currentTime*100/video.duration) can.page.Select(can, target, "span.progress", function(target) { target.innerText = p+"%" }) if (!progress) { progress = can.page.Append(can, can.ui.content, ["progress"])._target } can.page.style(can, progress, html.WIDTH, can.ui.content.offsetWidth*p/100) } var _target = can.onimport.file(can, item.path, item, index, can.ui.content, true); _target.focus() - can.onappend._toggle(can, can.ui.content, function() { - target.previousSibling? target.previousSibling.click(): can.user.toast(can, "已经是第一页了") - }, function() { - target.nextSibling? target.nextSibling.click(): can.user.toast(can, "已经是最后一页了") - }) + can.onappend._toggle(can, can.ui.content, function() { can.onaction.prev({}, can) }, function() { can.onaction.next({}, can) }) } if (index < can.db.begin || index >= can.db.begin+can.db.limit) { can.onimport.page(can, can.db.list, can.db.begin = index-index%can.db.limit) @@ -55,7 +75,7 @@ Volcanos(chat.ONIMPORT, { page: function(can, list, begin) { can.onmotion.clear(can, can.ui.display) begin = parseInt(begin||can.db.begin||0), can.db.limit = can.base.Min((parseInt(can.ui.display.offsetWidth/110)||5)-1, 3) for (var i = begin; i < begin+can.db.limit; i++) { if (list && list[i]) { list[i]._display = can.onimport.file(can, list[i].path, list[i], i) } } - can.onappend._toggle(can, can.ui.display, function(event) { can.onaction.prev(event, can) }, function(event) { can.onaction.next(event, can) }) + can.onappend._toggle(can, can.ui.display, function(event) { can.onaction.prevpage(event, can) }, function(event) { can.onaction.nextpage(event, can) }) can.Status({begin: begin, limit: can.db.limit, total: list.length}) }, }, [""]) @@ -63,29 +83,31 @@ Volcanos(chat.ONFIGURE, { png: function(can, item) { return can.onfigure.image(can, item) }, jpg: function(can, item) { return can.onfigure.image(can, item) }, jpeg: function(can, item) { return can.onfigure.image(can, item) }, - image: function(can, item) { return {img: item._path, onclick: function(event) { item._target.click() }} }, + image: function(can, item) { return {img: item._path, title: item.title, onclick: function(event) { item._target.click() }} }, video: function(can, item, auto) { var init, last = can.onexport.progress(can, item.path)||0 - return {type: html.VIDEO, data: {src: item._path, controls: auto, autoplay: auto}, - onclick: function(event) { item._target.click(), can.onkeymap.prevent(event) }, + var meta = {type: html.VIDEO, title: item.title, data: {src: item._path, controls: auto, autoplay: auto}, + onclick: function(event) { item._target.click() }, onratechange: function(event) { can.onexport.storage(can, "rate", event.target.playbackRate) }, onvolumechange: function(event) { can.onexport.storage(can, "volume", event.target.volume) }, - onloadedmetadata: function(event) { + onloadedmetadata: function(event) { item._cb && item._cb(event, event.target) event.target.volume = can.onexport.storage(can, "volume")||0.5 event.target.playbackRate = can.onexport.storage(can, "rate")||1 }, - ontimeupdate: function(event) { if (event.target.currentTime == 0) { return } item._cb && item._cb(event) + ontimeupdate: function(event) { if (event.target.currentTime == 0) { return } item._cb && item._cb(event, event.target) can.Status("position", can.onexport.position(can, event.target.currentTime-1, event.target.duration)) can.onexport.progress(can, "p."+item.path, parseInt(event.target.currentTime*100/event.target.duration)+"%") can.onexport.progress(can, item.path, event.target.currentTime) if (!init) { init = true, event.target.currentTime = last } }, - onended: function(event) { var next = item._target.nextSibling - next && can.onmotion.delay(can, function() { next.click() }, 300) - }, + onended: function(event) { can.onaction.playnext(can) }, } + if (!auto && can.misc.isVideo(can, item.path) && !can.user.isChrome) { + return {view: html.AUDIO, list: [{img: can.misc.Resource(can, item.cover||"usr/icons/QuickTime Player.png", can.ConfSpace()), className: "cover"}, {text: [item.name, "", mdb.NAME]}], onclick: meta.onclick} + } + return meta }, audio: function(can, item, auto) { var meta = can.onfigure.video(can, item, auto); meta.type = html.AUDIO - return {view: html.AUDIO, list: [{img: can.misc.Resource(can, item.cover, can.ConfSpace()), className: "cover"}, {text: [item.name, "", mdb.NAME]}, meta], onclick: meta.onclick} + return {view: html.AUDIO, list: [{img: can.misc.Resource(can, item.cover||"usr/icons/Music.png", can.ConfSpace()), className: "cover"}, {text: [item.name, "", mdb.NAME]}, meta], onclick: meta.onclick} }, webm: function(can, item, auto) { return can.onfigure.video(can, item, auto) }, mov: function(can, item, auto) { return can.onfigure.video(can, item, auto) }, @@ -100,41 +122,75 @@ Volcanos(chat.ONACTION, { "fullscreen": "bi bi-fullscreen", }, }, - list: ["upload", "record1", "record2", "fullscreen", ["sort", "time", "path", "size"]], - 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, "现在开始截图") - cb(stream, function(blobs, ext) { var msg = can.request(event); msg._upload = new File(blobs, list[0]+nfs.PT+ext) - can.runAction(msg, html.UPLOAD, [], function() { can.user.toast(can, "上传成功"), can.Update() }) - can.core.List(stream.getTracks(), function(item) { item.stop() }) - }) + list: [ + // "fullscreen", + "mkdir", "upload", "record1", "record2", + ["sort", mdb.TIME, nfs.PATH, nfs.SIZE], + ["order", "loop", "range", "random"], + ], + record0: function(event, can, name, cb) { can.user.input(event, can, [{name: nfs.FILE, value: name}], function(list) { + var height = window.innerHeight, width = window.innerWidth + navigator.mediaDevices.getDisplayMedia({video: {height: height*8, width: width*8}}).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.onmotion.clearFloat(can) + can.onmotion.delay(can, function() { + cb(stream, function(blobs, ext) { var msg = can.request(event); msg._upload = new File(blobs, list[0]+nfs.PT+ext) + can.runAction(msg, html.UPLOAD, [], function(msg) { can.user.toast(can, "上传成功") + can.db.hash = can.onexport.hash(can, encodeURIComponent(msg.Result())), can.Update() + }), can.core.List(stream.getTracks(), function(item) { item.stop() }) + }) + }, 300) }) }).catch(function(err) { can.user.toast(can, err.name + ": " + err.message) }) }) }, - record1: function(event, can) { can.onaction.record0(event, can, "shot", function(stream, cb) { var height = window.innerHeight - var video = can.page.Append(can, document.body, [{type: html.VIDEO, height: height}])._target; video.srcObject = stream, video.onloadedmetadata = function() { video.play(), width = video.offsetWidth + record1: function(event, can) { can.onaction.record0(event, can, "Screenshot "+can.base.Time(null), function(stream, cb) { var height = window.innerHeight + var video = can.page.Append(can, document.body, [{type: html.VIDEO, height: height}])._target; video.srcObject = stream, video.onloadedmetadata = function() { + video.play(), height = video.offsetHeight, width = video.offsetWidth var canvas = can.page.Append(can, document.body, [{type: html.CANVAS, height: height, width: width}])._target; canvas.getContext("2d").drawImage(video, 0, 0, width, height) canvas.toBlob(function(blob) { cb([blob], nfs.PNG) }) } }) }, - record2: function(event, can) { can.onaction.record0(event, can, "shot", function(stream, cb) { - var recorder = new MediaRecorder(stream, {mimeType: 'video/webm'}), blobs = []; recorder.ondataavailable = function(res) { blobs.push(res.data) } - recorder.onstop = function() { cb(blobs, nfs.WEBM) }, recorder.start(1) - }) }, - fullscreen: function(event, can) { - var show = can.onmotion.toggle(can, can.ui.project); can.onmotion.toggle(can, can.ui.display, show), can.onimport.layout(can) - can.page.ClassList.set(can, can.ui.content, html.FLOAT, !show) + record2: function(event, can) { if (can.ui.recorder) { return can.ui.recorder.stop() } + can.onaction.record0(event, can, "Screenshot "+can.base.Time(null), function(stream, cb) { + if (can.user.isChrome) { + var recorder = new MediaRecorder(stream, {mimeType: "video/webm;codecs=vp8"}) + recorder.onstop = function() { delete(can.ui.recorder), cb(blobs, "webm") } + // var recorder = new MediaRecorder(stream, {mimeType: 'video/mp4; codecs="avc1.4d002a"'}) + // recorder.onstop = function() { delete(can.ui.recorder), cb(blobs, "mp4") } + } else { + var recorder = new MediaRecorder(stream, {mimeType: "video/mp4"}) + recorder.onstop = function() { delete(can.ui.recorder), cb(blobs, "mp4") } + } + var blobs = []; recorder.ondataavailable = function(res) { blobs.push(res.data) } + can.ui.recorder = recorder, recorder.start(1) + }) + }, + fullscreen: function(event, can, button) { var show = can.onmotion.toggle(can, can.ui.project) + can.onmotion.toggle(can, can.ui.display, show), can.onmotion.toggle(can, can._status, show) + can.page.ClassList.set(can, can._fields, button, !show), can.page.ClassList.set(can, can.ui.content, html.FLOAT, !show) + can.sup.onimport.size(can.sup, can.sup.ConfHeight(), can.sup.ConfWidth()) }, sort: function(event, can, button, value) { switch (value) { case mdb.TIME: can._msg.Sort(value, "str_r"); break case nfs.PATH: can._msg.Sort(value, "str"); break case nfs.SIZE: can._msg.Sort(value, "int_r"); break - } - can.onmotion.clear(can, can.ui.project), can.ui.filter = can.onappend.filter(can, can.ui.project), can.onimport._project(can, can._msg) + } can.onimport._project(can, can._msg) }, - prev: function(event, can) { if (can.db.begin > 0) { can.db.begin -= can.db.limit, can.onimport.page(can, can.db.list) } else { can.user.toast(can, "已经是第一页了") } }, - next: function(event, can) { if (can.db.begin + can.db.limit < can.db.list.length) { can.db.begin += can.db.limit, can.onimport.page(can, can.db.list) } else { can.user.toast(can, "已经是最后一页了") } }, + playnext: function(can) { + if (can.Action("order") == "loop") { + if (can.ui.video) { can.ui.video.currentTime = 0, can.ui.video.play() } + } + if (can.Action("order") == "range") { var next = can.ui.current._target.nextSibling + next && can.onmotion.delay(can, function() { next.click() }, 300) + } + if (can.Action("order") == "random") { + can.db.list[parseInt(Math.random()*can.db.list.length)]._target.click() + } + }, + prev: function(event, can) { var target = can.ui.current._target; target.previousSibling? target.previousSibling.click(): can.user.toast(can, "已经是第一页了") }, + next: function(event, can) { var target = can.ui.current._target; target.nextSibling? target.nextSibling.click(): can.user.toast(can, "已经是最后一页了") }, + prevpage: function(event, can) { if (can.db.begin > 0) { can.db.begin -= can.db.limit, can.onimport.page(can, can.db.list) } else { can.user.toast(can, "已经是第一页了") } }, + nextpage: function(event, can) { if (can.db.begin + can.db.limit < can.db.list.length) { can.db.begin += can.db.limit, can.onimport.page(can, can.db.list) } else { can.user.toast(can, "已经是最后一页了") } }, }) Volcanos(chat.ONEXPORT, {list: [cli.BEGIN, mdb.LIMIT, mdb.TOTAL, mdb.NAME, nfs.SIZE, mdb.TIME, "position"], progress: function(can, path, time) { return can.onexport.storage(can, path.split("?")[0], time) }, @@ -144,10 +200,11 @@ Volcanos(chat.ONKEYMAP, { _mode: { plugin: { Escape: function(event, can) { can.onaction.fullscreen(event, can) }, - ArrowLeft: function(event, can) { can.ui.video.currentTime -= 15 }, - ArrowRight: function(event, can) { can.ui.video.currentTime += 15 }, + ArrowLeft: function(event, can) { if (can.ui.video) { can.ui.video.currentTime -= 15 } else { can.onaction.prev(event, can) } }, + ArrowRight: function(event, can) { if (can.ui.video) { can.ui.video.currentTime += 15 } else { can.onaction.next(event, can) } }, ArrowDown: function(event, can) { try { can.user.toast(can, "volume: "+parseInt((can.ui.video.volume -= 0.1)*100)) } catch (e) {} }, ArrowUp: function(event, can) { try { can.user.toast(can, "volume: "+parseInt((can.ui.video.volume += 0.1)*100)) } catch (e) {} }, + " ": function(event, can) { if (can.ui.video) { can.ui.video.paused? can.ui.video.play(): can.ui.video.pause() } }, }, }, }) diff --git a/plugin/state.js b/plugin/state.js index 11d90390..afd87adf 100644 --- a/plugin/state.js +++ b/plugin/state.js @@ -352,7 +352,7 @@ Volcanos(chat.ONEXPORT, { }, title: function(can, title) { if (!can.isCmdMode()) { return } var list = []; function push(p) { p && list.indexOf(p) == -1 && list.push(p) } - if (!can.base.isIn(can.ConfIndex(), web.PORTAL)) { push(can.user.trans(can, can.ConfIndex(), can.Conf("help"))) } + if (!can.base.isIn(can.ConfIndex(), web.PORTAL, code.VIMER, wiki.FEEL)) { push(can.user.trans(can, can.ConfIndex(), can.Conf("help"))) } can.core.List(arguments, function(title, index) { index > 0 && push(title) }), push(can.ConfSpace()||can.misc.Search(can, ice.POD)) can.user.title(list.join(" ")) }, @@ -361,10 +361,8 @@ Volcanos(chat.ONEXPORT, { // if (can.sub && can.sub.onexport.link) { return can.sub.onexport.link(can.sub) } var args = can.Option(); args.pod = can.ConfSpace()||can.misc.Search(can, ice.POD), args.cmd = can.ConfIndex() can.core.Item(args, function(key, value) { key != ice.POD && !value && delete(args[key]) }) - var hash = can.onexport.storage(can, "hash")||"" - can.base.isArray(hash) && (hash = hash.join(":")) - hash && (hash = "#"+hash) - return can.misc.MergePodCmd(can, args, true)+hash + var hash = can.onexport.storage(can, "hash")||""; can.base.isArray(hash) && (hash = hash.join(":")), hash && (hash = "#"+hash) + return can.base.replaceAll(can.misc.MergePodCmd(can, args, true), "%2F", "/")+hash }, close: function(can, msg) {}, }) diff --git a/plugin/table.js b/plugin/table.js index 26ead735..9d970f3c 100644 --- a/plugin/table.js +++ b/plugin/table.js @@ -123,7 +123,7 @@ Volcanos(chat.ONIMPORT, { }, _item: function(can, item, cb, cbs) { item._hash = item._hash||item.hash||item.zone||item.path||item.name - item._title = item._title||item.name||item.path||item.path||item.hash + item._title = item._title||item.name||item.path||item.zone||item.hash item._select == undefined && can.db.hash[0] && (item._select = can.db.hash[0] == item._hash) return {view: [[html.ITEM, item.type, item.role, item.status]], title: item.title||item.nick, list: [ can.onimport._icons(can, item),