From 44ea7eeb88d103eb02087ad982f84036298d830c Mon Sep 17 00:00:00 2001 From: shaoying Date: Thu, 13 Feb 2020 11:36:53 +0800 Subject: [PATCH] opt app --- frame.js | 74 +++++----- index.html | 1 - lib/core.js | 19 ++- lib/misc.js | 12 +- lib/page.js | 3 +- lib/user.js | 2 + manifest.json | 17 +++ order.js | 9 +- page/chat.js | 3 + pane/Action.js | 128 +++++++++++++---- pane/Header.js | 2 + pane/Login.js | 42 +++--- pane/River.js | 32 ++--- plugin/chrome/chrome.html | 13 ++ plugin/chrome/chrome.js | 142 +++++++++++++++++++ plugin/chrome/config.js | 41 ++++++ plugin/chrome/popup.html | 13 ++ plugin/chrome/popup.js | 19 +++ plugin/input.js | 108 +++++++++++++- plugin/table.js | 6 +- plugin/team/plan.js | 149 ++++++++++++++++++++ plugin/wiki/feel.js | 51 +++++-- plugin/wiki/mind.js | 237 +++++++++++++++---------------- plugin/wiki/word.js | 286 +++++++++++++++++++++++++++++++++++--- proto.js | 128 ++++++++++------- style.css | 74 ++++++++-- 26 files changed, 1269 insertions(+), 342 deletions(-) create mode 100644 manifest.json create mode 100644 plugin/chrome/chrome.html create mode 100644 plugin/chrome/chrome.js create mode 100644 plugin/chrome/config.js create mode 100644 plugin/chrome/popup.html create mode 100644 plugin/chrome/popup.js create mode 100644 plugin/team/plan.js diff --git a/frame.js b/frame.js index 6135b851..8bdc7fd8 100644 --- a/frame.js +++ b/frame.js @@ -1,46 +1,49 @@ var can = Volcanos("chat", { Page: shy("构造网页", function(can, name, conf, cb, body) { - var page = Volcanos(name, {_type: "local", + var page = Volcanos(name, {_type: "local", _panes: {}, target: body, Plugin: can.Plugin, Inputs: can.Inputs, Output: can.Output, - Report: function(event, value, key) { - page.Import && page.Import(event, value, key) - can.core.Item(page.panes, function(index, item) { - item.Import && item.Import(event, value, key) - }) - }, Import: function(event, value, key) {var cb = page.onimport[key]; typeof cb == "function" && cb(event, page, value, key, body); }, + Report: function(event, value, key) { + page.Import && page.Import(event, value, key) + can.core.Item(page._panes, function(index, item) { + item.Import && item.Import(event, value, key) + }) + }, run: function(event, option, cmds, cb) {can.misc.Run(event, page, option, cmds, cb)}, - }, Config.libs.concat(["page/"+name]), function(page) {page.Conf(conf); - page.onimport._init && page.onimport._init(page, conf, body) - can.core.Next(conf.pane, function(item, cb) {page.panes = page.panes || {}; - page.panes[item.name] = page[item.pos] = page[item.name] = can.Pane(page, item.name, item, cb, + }, Config.libs.concat(["page/"+name]), function(page) { + page.onimport._init && page.onimport._init(page, page.Conf(conf), body) + + can.core.Next(conf.pane, function(item, cb) { + page._panes[item.name] = page[item.pos] = page[item.name] = can.Pane(page, item.name, item, cb, can.page.Select(can, body, "fieldset."+item.name)[0] || can.page.AppendField(can, body, item.name+" "+(item.pos||""), item)) }, function() {typeof cb == "function" && cb(page)}) }, conf) - return page.target = body, page + return page }), Pane: shy("构造面板", function(can, name, meta, cb, field) { var river = "", storm = ""; - var pane = Volcanos(name, {_type: "local", target: field, + var pane = Volcanos(name, {_type: "local", _plugins: [], target: field, option: field.querySelector("form.option"), action: field.querySelector("div.action"), output: field.querySelector("div.output"), Plugin: can.Plugin, Inputs: can.Inputs, Output: can.Output, - _plugins: [], Export: function(event, value, key) {can.Report(event, value, key)}, Import: function(event, value, key) {var cb = pane.onimport[key]; typeof cb == "function" && cb(event, pane, value, key, pane.output); can.core.List(pane._plugins, function(item) {item.Import(event, value, key)}) - pane.page.Select(pane, pane.action, "input."+key, function(item) { - item.value = value - }) + pane.page.Select(pane, pane.action, "input."+key, function(item) {item.value = value}) + }, + Action: function(key, value) { + return can.page.Select(can, pane.action, "input[name="+key+"],select."+key+",select[name="+key+"]", function(item) { + value != undefined && (item.value = value), value = item.value + }), value }, Size: function(event, width, height) {var cb = pane.onimport["size"]; @@ -95,14 +98,7 @@ var can = Volcanos("chat", { can.run(event, pane.option.dataset, cmds, cb) return msg }, - }, Config.libs.concat(["pane/"+name]), function(pane) { - can.Dream(document.head, "pane/"+name+".css") - function deal(event, value) { - typeof pane.onaction[value] == "function" && pane.onaction[value](event, pane, meta, value, pane.output) - } - can.page.Append(can, pane.action, can.core.List(pane.onaction.list, function(line) { - return typeof line == "string"? {button: [line, deal]}: line.length > 0? {select: [line, deal]}: line - })) + }, Config.libs.concat(["pane/"+name]), function(pane) {can.Dream(document.head, "pane/"+name+".css") pane.onimport._init && pane.onimport._init(pane, pane.Conf(meta), pane.output, pane.action, pane.option, field) typeof cb == "function" && cb(pane) }, meta) @@ -120,9 +116,7 @@ var can = Volcanos("chat", { var feature = JSON.parse(meta.feature||'{}'); var exports = JSON.parse(meta.exports||'""')||feature.exports||[]; var plugin = Volcanos(name, {_type: "local", target: field, - option: field.querySelector("form.option"), - action: field.querySelector("div.action"), - output: field.querySelector("div.output"), + option: option, action: action, output: output, Inputs: can.Inputs, Output: can.Output, Import: function(event, value, key) {var cb = plugin.onimport[key]; @@ -231,6 +225,7 @@ var can = Volcanos("chat", { typeof cb == "function" && cb(plugin) }) }, meta) + field.Check = plugin.Check return plugin }), Inputs: shy("构造控件", function(can, item, type, name, value, cb, option) { @@ -243,14 +238,14 @@ var can = Volcanos("chat", { }, Append: function(event, value) {can.Append(null, function(input) {can.Select(event, input.target, true)})}, Clone: function(event, value) {can.Clone(event, function(input) {input.Select(event, null, true)})}, - run: function(event, cmd, cb, silent) { + run: function(event, cmd, cb, silent) {var msg = can.Event(event); + msg.Option("_action", item.name); (input[item.cb] || can[item.cb] || can.Check)(event, event.target, cb); }, }, Config.libs.concat(["plugin/"+type]), function(input) { var target = input.onimport.init(input, item, name, value, option); input.target = target, target.Input = input; - typeof cb == "function" && cb(input); }) return input @@ -263,16 +258,14 @@ var can = Volcanos("chat", { typeof cb == "function" && cb(event, output, value, key, target); }, Option: function(key, value) { - can.page.Select(can, can.option, "input[name="+key+"],select[name="+key+"]", function(item) { + return can.page.Select(can, can.option, "input[name="+key+"],select[name="+key+"]", function(item) { value != undefined && (item.value = value), value = item.value - }) - return value + }), value }, Action: function(key, value) { - can.page.Select(can, can.action, "input[name="+key+"],select."+key+",select[name="+key+"]", function(item) { + return can.page.Select(can, can.action, "input[name="+key+"],select."+key+",select[name="+key+"]", function(item) { value != undefined && (item.value = value), value = item.value - }) - return value + }), value }, Status: function(event, value, key) {var cb = output.onstatus[key]; typeof cb == "function"? cb(event, output, value, key, can.page.Select(can, status, "div."+key)[0]): false && output.run(event, ["status", key, value], function(msg) { @@ -297,8 +290,11 @@ var can = Volcanos("chat", { }), }, Config.libs.concat(Config.list), function(can) { can[Config.main] = can.Page(can, Config.main, Config, function(chat) { - chat.Login.Export(event||{}, can.user.Search(can, "layout")||Config.layout.def, "layout") - chat.Login.Import(event||{}, "", "login") - can.user.Search(can, "you") && can.user.title(can.user.Search(can, "you")) + chat.Import(event||{}, can.user.Search(can, "layout")||Config.layout.def, "layout") + can.user.title(can.user.Search(can, "you")||Config.title) + can.user.login(function(user) { + chat.River.Import(event||{}, "update", "river") + chat.Header.Import(event||{}, user.name, "username") + }) }, document.body) }) diff --git a/index.html b/index.html index e7d68f22..07e645fc 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,6 @@ - diff --git a/lib/core.js b/lib/core.js index c12b6d3e..e1f18870 100644 --- a/lib/core.js +++ b/lib/core.js @@ -1,5 +1,22 @@ Volcanos("core", {help: "核心模块", - List: shy("迭代器", function(obj, cb, interval, cbs) {obj = typeof obj == "string"? [obj]: (obj || []) + List: shy("迭代器", function(obj, cb, interval, cbs) { + if (typeof obj == "number") { + var begin = 0, end = obj, step = 1; + if (typeof interval == "number") { + step = interval + } + if (typeof cb == "number") { + begin = obj, end = cb; + } + + var list = [] + for (var i = begin; i < end; i += step) { + list.push(i) + } + return list + } + + obj = typeof obj == "string"? [obj]: (obj || []) if (interval > 0) { function loop(i) {if (i >= obj.length) {return typeof cbs == "function" && cbs(obj)} typeof cb == "function" && cb(obj[i], i, obj), setTimeout(function() {loop(i+1)}, interval); diff --git a/lib/misc.js b/lib/misc.js index 7530d9d5..8b0aba70 100644 --- a/lib/misc.js +++ b/lib/misc.js @@ -36,7 +36,7 @@ Volcanos("misc", {help: "工具模块", Run: shy("请求后端", {order: 0}, function(event, can, dataset, cmd, cb) { var msg = can.Event(event) - var option = {"cmds": cmd} + var option = {"cmds": cmd||msg.cmd} msg.option && msg.option.forEach(function(item) { msg[item] && (option[item] = msg[item]) }) @@ -56,15 +56,13 @@ Volcanos("misc", {help: "工具模块", // kit.Log(msg.detail.concat([msg])) // kit.History("run", -1, option) - this.POST(can, msg, can.Conf("context")+dataset.names.toLowerCase(), option, function(msg) { + this.POST(can, msg, can.Conf("iceberg")+(dataset.names||msg.names).toLowerCase(), option, function(msg) { // kit.Log("run", what, "result", msg.result? msg.result[0]: "", msg) typeof cb == "function" && cb(msg) }), delete(event.msg) }), - WSS: shy("请求后端", {order: 0}, function(can, cb, onerror, onclose, onopen) {var meta = arguments.callee.meta - can._socket = new WebSocket(location.protocol.replace("http", "ws")+"//"+location.host+"/space/?"+can.base.Args({ - node: "active", name: can._share||"", user: can._username||"", share: can._share||"", - })) + WSS: shy("请求后端", {order: 0}, function(can, url, args, cb, onopen, onerror, onclose) {var meta = arguments.callee.meta + can._socket = new WebSocket(url+"?"+can.base.Args(args)) var timer = can.Timer(30000, function() { can._socket.send("{}") @@ -74,7 +72,7 @@ Volcanos("misc", {help: "工具模块", }, can._socket.onclose = onclose || function() { timer.stop = true, can.user.toast("wss redial") can.Log("wss", "close"), delete(can._socket), setTimeout(function() { - can.misc.WSS(can, cb, onerror, onclose, onopen) + can.misc.WSS(can, url, args, cb, onerror, onclose, onopen) }, 1000) }, can._socket.onopen = onopen can._socket.onmessage = function(event) {var order = ++meta.order diff --git a/lib/page.js b/lib/page.js index bfd55004..40bb7690 100644 --- a/lib/page.js +++ b/lib/page.js @@ -195,6 +195,7 @@ Volcanos("page", {help: "网页模块", {view: ["action"]}, {view: ["output"]}, {view: ["status"]}, // {view: ["border-bottom"]}, ]}]).first; + field.Meta = item return field; }), AppendTable: shy("添加表格", function(can, target, msg, list, cb, cbs) { @@ -260,7 +261,7 @@ Volcanos("page", {help: "网页模块", }, AppendAction: shy("添加控件", function(can, action, list, cb) { - can.page.Append(can, action, can.core.List(list, function(line) { + return can.page.Append(can, action, can.core.List(list, function(line) { return typeof line == "string"? {button: [line, cb]}: line.length > 0? {select: [line, cb]}: line })) }), diff --git a/lib/user.js b/lib/user.js index 3a030071..b4b61219 100644 --- a/lib/user.js +++ b/lib/user.js @@ -7,6 +7,8 @@ Volcanos("user", {help: "用户模块", toast: function(text) {}, carte: function(event, cb) {}, + login: function(cb) {}, + share: function(cb) {}, Share: shy("共享链接", function(can, objs, clear) {var obj = objs || {}; var path = location.pathname; obj.path && (path = obj.path, delete(obj.path)) diff --git a/manifest.json b/manifest.json new file mode 100644 index 00000000..6254ac19 --- /dev/null +++ b/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 2, + "name": "volcanos", + "version": "0.0.1", + "background": {"page": "plugin/chrome/chrome.html"}, + "browser_action": {"default_popup": "plugin/chrome/popup.html"}, + "content_scripts": [], + "permissions": [ + "tabs", + "history", + "cookies", + "bookmarks", + "notifications", + "*://localhost/*", + "*://localhost:9020/*" + ] +} diff --git a/order.js b/order.js index d02a77ac..58e4feaa 100644 --- a/order.js +++ b/order.js @@ -1,4 +1,5 @@ -var Config = {context: "/chat/", +var Config = {iceberg: "/chat/", volcano: "/static/volcanos/", + libs: ["lib/base", "lib/core", "lib/misc", "lib/page", "lib/user"], main: "chat", list: ["page/chat", "pane/Toast", "pane/Tutor", "pane/Debug", "pane/Carte", "pane/Favor", "pane/Login", @@ -9,9 +10,7 @@ var Config = {context: "/chat/", "pane/Footer", "plugin/state", "plugin/input", "plugin/table", "plugin/inner", "plugin/media", - ], - libs: ["lib/base", "lib/core", "lib/misc", "lib/page", "lib/user"], - pane: [ + ], pane: [ {group: "index", name: "Toast", pos: "dialog", duration: 3000}, {group: "index", name: "Tutor", pos: "dialog"}, {group: "index", name: "Debug", pos: "dialog"}, @@ -30,7 +29,7 @@ var Config = {context: "/chat/", {group: "index", name: "Action", pos: "bottom"}, {group: "index", name: "Footer", pos: "foot", state: ["ntxt", "ncmd"], title: 'shylinux@163.com'}, - ], layout: {def: "办公", list: ["工作", "办公", "聊天"], size: { + ], title: "volcanos", layout: {def: "办公", list: ["工作", "办公", "聊天"], size: { "最大": {head: 0, foot: 0, left: 0, right: 0, bottom: -1, center: 0, top: 0}, "工作": {head: 30, foot: 30, left: 0, right: 100, bottom: -1, center: 0, top: 0}, "办公": {head: 30, foot: 30, left: 100, right: 100, bottom: -1, center: 0, top: 0}, diff --git a/page/chat.js b/page/chat.js index 04a82280..ab3b9a69 100644 --- a/page/chat.js +++ b/page/chat.js @@ -21,6 +21,9 @@ Volcanos("onaction", {help: "组件交互", list: [], can.Action.escape && can.Action.escape(event) break case " ": + if (event.target.getAttribute("contenteditable")) { + break + } if (event.target.tagName == "INPUT" || event.target.tagName == "TEXTAREA") { break } diff --git a/pane/Action.js b/pane/Action.js index 45190b32..836bff02 100644 --- a/pane/Action.js +++ b/pane/Action.js @@ -4,76 +4,137 @@ Volcanos("onimport", {help: "导入数据", list: [], input.value = can.user.Search(can, input.name) || "" }) }, - init: function(event, can, msg, cmd, output) {output.innerHTML = ""; + init: function(event, can, msg, cmd, target) {can.output.innerHTML = ""; msg.Table(function(item, index) {if (!item.name) {return} can._plugins.push(can[item.name] = can.Plugin(can, item.name, item, function(event, cmds, cbs) { can.run(event, [item.river, item.storm, item.action].concat(cmds), cbs) - }, can.page.AppendField(can, output, "item "+item.group+" "+item.name, item))) + }, can.page.AppendField(can, can.output, "item "+item.group+" "+item.name, item))) }) - }, - size: function(event, can, value, cmd, output) { - }, - layout: function(event, can, value, cmd, output) {can.layout = value; + layout: function(event, can, value, cmd, target) {can.layout = value; can.page.Select(can, can.action, "select.layout", function(item) { item.value = value }) }, - scroll: function(event, can, value, cmd, output) {can.layout = value; - output.parentElement.scrollBy(value.x, value.y) + scroll: function(event, can, value, cmd, target) {can.layout = value; + can.output.parentElement.scrollBy(value.x, value.y) }, - river: function(event, can, value, cmd, output) { + river: function(event, can, value, cmd, target) { if (value == "update") {return} can.Conf("temp_river", value) }, - you: function(event, can, value, cmd, output) { + you: function(event, can, value, cmd, target) { can.user.title(value) }, - storm: function(event, can, value, cmd, output) { - can.Cache(can.Conf("river")+"."+can.Conf("storm"), output, "some"); + storm: function(event, can, value, cmd, target) { + can.Cache(can.Conf("river")+"."+can.Conf("storm"), can.output, "some"); can.Conf("river", can.Conf("temp_river")) can.Conf("storm", value) - if (!can.Cache(can.Conf("river")+"."+can.Conf("storm"), output)) { + if (!can.Cache(can.Conf("river")+"."+can.Conf("storm"), can.output)) { can.run(event, [can.Conf("river"), can.Conf("storm")], function(msg) { - can.onimport.init(event, can, msg, cmd, output) + can.onimport.init(event, can, msg, cmd, can.output) }) } }, - favor: function(event, can, msg, cmd, output) {var key = msg.detail[0]; + favor: function(event, can, msg, cmd, target) {var key = msg.detail[0]; if (msg._hand) {return} - var cb = can.onaction[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, output); return msg.Echo(can._name, " onaction ", key), msg._hand = true} - var cb = can.onchoice[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, output); return msg.Echo(can._name, " onchoice ", key), msg._hand = true} + var cb = can.onaction[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, can.output); return msg.Echo(can._name, " onaction ", key), msg._hand = true} + var cb = can.onchoice[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, can.output); return msg.Echo(can._name, " onchoice ", key), msg._hand = true} var sub = can[key]; if (sub && sub.Select) {sub.Select(event, null, true); return msg.Echo(can._name, " select ", sub._name), msg._hand = true} can._plugin && can._plugin.Import(event, msg, cmd) }, }) -Volcanos("onaction", {help: "组件交互", list: [["layout", "最大", "工作", "办公", "聊天"], "清屏", "刷新", "串行", "并行", +Volcanos("onaction", {help: "组件交互", list: [["layout", "最大", "工作", "办公", "聊天"], "刷新", "清屏", "并行","串行", + ["action", "正常", "编辑", "编排", "定位"], {input: "pod"}, {input: "you"}, {input: "hot"}, {input: "top"}, ], - onmousemove: function(event, can, msg, cmd, output) { + onmousemove: function(event, can, msg, cmd, target) { can.resize && can.resize(event) }, - layout: function(event, can, value, cmd, output) { + action: function(event, can, value, cmd, target) { + switch (value) { + case "正常": + can.page.Select(can, target, "fieldset.item", function(item) { + item.setAttribute("draggable", false) + }) + break + case "编排": + can.page.Select(can, target, "fieldset.item", function(item) { + item.setAttribute("draggable", true) + item.ondragstart = function(event) {can.drag = event.target} + item.ondragover = function(event) {event.preventDefault()} + item.ondrop = function(event) {event.preventDefault() + item.parentNode.insertBefore(can.drag, item) + } + }) + break + case "定位": + var max = 0; + var current, begin; + can.page.Select(can, target, "fieldset.item", function(item) { + item.style.left = item.offsetLeft + "px" + item.style.top = item.offsetTop + "px" + }) + can.page.Select(can, target, "fieldset.item", function(item) { + item.style.position = "absolute" + item.onmousedown = function(event) { + if (can.Action("action") != "定位") {return} + + if (current) { + current.style.left = event.clientX - begin.x + begin.left + "px" + current.style.top = event.clientY - begin.y + begin.top + "px" + current = null; + return + } + current = event.target; + current.style["z-index"] = max = max + 1 + begin = {x: event.clientX, y: event.clientY, left: item.offsetLeft, top: item.offsetTop} + }; + target.onmousemove = item.onmousemove = function(event) {if (!current) {return} + current.style.left = event.clientX - begin.x + begin.left + "px" + current.style.top = event.clientY - begin.y + begin.top + "px" + } + }) + break + } + }, + layout: function(event, can, value, cmd, target) { can.Export(event, value, cmd) }, - "清屏": function(event, can, msg, cmd, output) { - can.page.Select(can, output, "fieldset.item>div.output", function(item) { - item.innerHTML = ""; - }) - }, - "刷新": function(event, can, msg, cmd, output) { - can.page.Select(can, output, "fieldset.item>div.output", function(item) { + "刷新": function(event, can, msg, cmd, target) { + can.page.Select(can, can.output, "fieldset.item>div.output", function(item) { item.innerHTML = ""; }) can.run(event, [can.Conf("river"), can.Conf("storm")], function(msg) { - can.onimport.init(event, can, msg, cmd, output) + can.onimport.init(event, can, msg, cmd, can.output) + }) + }, + "清屏": function(event, can, msg, cmd, target) { + can.page.Select(can, can.output, "fieldset.item>div.output", function(item) { + item.innerHTML = ""; + }) + }, + "并行": function(event, can, msg, cmd, target) { + can.page.Select(can, target, "fieldset.item", function(field) { + can.page.Select(can, field, "input[type=button]", function(input, index) { + index == 0 && field.Check(event, input, function() {}) + }) + }) + }, + "串行": function(event, can, msg, cmd, target) { + can.core.Next(can.page.Select(can, target, "fieldset.item", function(field) { + return field + }), function(field, cb) { + can.page.Select(can, field, "input[type=button]", function(input, index) { + index == 0 && field.Check(event, input, cb) + }) }) }, }) -Volcanos("onchoice", {help: "组件菜单", list: [["layout", "工作", "办公", "聊天"]], +Volcanos("onchoice", {help: "组件菜单", list: [["layout", "工作", "办公", "聊天"], "保存"], "工作": function(event, can, msg, cmd, target) { can.Export(event, cmd, "layout") }, @@ -83,6 +144,15 @@ Volcanos("onchoice", {help: "组件菜单", list: [["layout", "工作", "办公" "聊天": function(event, can, msg, cmd, target) { can.Export(event, cmd, "layout") }, + "保存": function(event, can, msg, cmd, target) { + var list = [] + can.page.Select(can, target, "fieldset", function(item) {var meta = item.Meta + list.push(meta.node||"", meta.group, meta.index, meta.index) + }) + can.run(event, [can.Conf("river"), can.Conf("storm"), "save"].concat(list), function(msg) { + can.user.toast("保存成功") + }) + }, }) Volcanos("ondetail", {help: "组件详情", list: []}) Volcanos("onexport", {help: "导出数据", list: []}) diff --git a/pane/Header.js b/pane/Header.js index 6ae6e923..4a18de24 100644 --- a/pane/Header.js +++ b/pane/Header.js @@ -2,11 +2,13 @@ Volcanos("onimport", {help: "导入数据", list: [], _init: function(can, conf, output, action, option, field) {output.innerHTML = ""; conf.title && can.page.Append(can, output, [{view: "title", list: [{text: conf.title, className: "title"}], click: function(event) {can.onexport.title(event, can)}}]) + can.ui = can.page.Append(can, output, [{view: "state", list: can.core.List(conf.state, function(item) { return {text: conf[item]||"", className: item, click: function(event) {var cb = can.onexport[item]; typeof cb == "function" && cb(event, can, item, item, output) }}; })}]) + can.timer = can.Timer({interval: 1000, length: -1}, function() { can.ui.time.innerHTML = can.base.Time().split(" ")[1] }) diff --git a/pane/Login.js b/pane/Login.js index c33ed459..6293aa71 100644 --- a/pane/Login.js +++ b/pane/Login.js @@ -1,6 +1,19 @@ Volcanos("onimport", {help: "导入数据", list: [], _init: function(can, conf, output, action, option, field) { - var ui = can.page.Appends(can, option, [ + can.user.login = function(cb) { + can.user.Cookie("sessid")? can.onaction.check(event, can, cb, "check", output): + can.onaction.login(event, can, cb, "login", output) + } + }, +}) +Volcanos("onaction", {help: "组件交互", list: [], + check: function(event, can, cb, cmd, target) { + can.run(event||{}, ["check"], function(msg) {var user = msg.nickname && msg.nickname[0] || msg.Result() + user? typeof cb == "function" && cb({name: user}): can.onaction.login(event, can, cb, "login", target) + }) + }, + login: function(event, can, cb, cmd, target) { + var ui = can.page.Appends(can, target, [ {text: ["账号: ", "label"]}, {username: []}, {type: "br"}, {text: ["密码: ", "label"]}, {password: []}, {type: "br"}, {button: ["密码登录", function(event, cmd) { @@ -9,17 +22,14 @@ Volcanos("onimport", {help: "导入数据", list: [], can.run(event, ["login", ui.username.value, ui.password.value], function(msg) { if (msg.result && msg.result.length > 0) { - can.Hide(), can.Export(event, "", "login") - } else { - can.user.toast("用户或密码错误") + can.Hide(), can.onaction.check(event, can, cb, "check", target) + return } + can.user.toast("用户或密码错误") }) - event.stopPropagation() - event.preventDefault() - return true }]}, {button: ["扫码登录", function(event, cmd) { - can.onimport.username(event, can, "", function(event, msg) { + can.onaction.socket(event, can, "", function(event, msg) { switch (msg.detail[0]) { case "space": if (msg.detail[1] == "share") {can._share = msg.detail[2] @@ -31,19 +41,18 @@ Volcanos("onimport", {help: "导入数据", list: [], break case "sessid": can.user.Cookie(can, "sessid", msg.detail[1]) - can.Hide(), can.Export(event, "", "login") + can.Hide(), typeof cb == "function" && cb({name: user}) can.user.toast("") return true } }) - event.stopPropagation() - event.preventDefault() - return true }]}, {type: "br"}, ]) + can.Show(event, -1, -1) }, - username: function(event, can, value, cmd, output) {can._username = value + socket: function(event, can, value, cmd, output) {can._username = value +// location.protocol.replace("http", "ws")+"//"+location.host+"/space/?"+ return can._socket = can._socket || can.misc.WSS(can, function(event, msg) { if (msg.Option("_handle")) {return can.user.toast(msg.result.join(""))} if (typeof cmd == "function" && cmd(event, msg)) {return msg.Reply(msg)} @@ -55,14 +64,7 @@ Volcanos("onimport", {help: "导入数据", list: [], msg.Reply(msg) }) }, - login: function(event, can, value, cmd, output) { - if (!can.user.Cookie("sessid")) {can.Show(event, 400, 400); return} - can.run(event||{}, ["check"], function(msg) {var user = msg.nickname && msg.nickname[0] || msg.Result() - user? can.Export(event, user, "username"): can.Show(event, -1, -1) - }) - }, }) -Volcanos("onaction", {help: "组件交互", list: []}) Volcanos("onchoice", {help: "组件菜单", list: []}) Volcanos("ondetail", {help: "组件详情", list: []}) Volcanos("onexport", {help: "导出数据", list: []}) diff --git a/pane/River.js b/pane/River.js index 5d0a8698..b26ef47f 100644 --- a/pane/River.js +++ b/pane/River.js @@ -1,21 +1,16 @@ Volcanos("onimport", {help: "导入数据", list: [], + _init: function(can, conf, output, action, option, field) { + }, init: function(event, can, msg, key, output) {output.innerHTML = ""; can.page.AppendItem(can, output, msg.Table(), can.user.Search(can, "river"), function(event, line, item) { can.Export(event, line.key, "river") }) }, - username: function(event, can, value, key, output) { + river: function(event, can, value, key, output) {if (value == "update") { can.run(event, [], function(msg) { can.onimport.init(event, can, msg, key, output) }) - }, - river: function(event, can, value, key, output) { - if (value == "update") { - can.run(event, [], function(msg) { - can.onimport.init(event, can, msg, key, output) - }) - } - }, + }}, favor: function(event, can, msg, cmd, output) {var key = msg.detail[0]; if (msg._hand) {return} var cb = can.onaction[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, output); return msg.Echo(can._name, " onaction ", key), msg._hand = true} @@ -34,23 +29,18 @@ Volcanos("onaction", {help: "组件交互", list: ["创建", "刷新"], can.Export(event, "create", "ocean") }, "刷新": function(event, can, meta, key, output) { - can.run(event, [], function(msg) { - can.onimport.init(event, can, msg, key, output) - }) - }, -}) -Volcanos("onchoice", {help: "组件菜单", list: ["创建", "刷新"], - "创建": function(event, can, msg, key, target) { - can.Export(event, "create", "ocean") - }, - "刷新": function(event, can, msg, key, target) { - can.onaction[key](event, can, key, can.output) + can.Import(event, "update", "river") }, }) +Volcanos("onchoice", {help: "组件菜单", list: ["创建", "刷新"]}) Volcanos("ondetail", {help: "组件详情", list: ["共享"], "共享": function(event, can, line, key, target) { + can.Export(event, "river", "share") + }, +}) +Volcanos("onexport", {help: "导出数据", list: [], + share: function(event, can, line, key, target) { can.user.toast(can.user.Share(can, {river: line.key}), "共享链接", 10000) }, }) -Volcanos("onexport", {help: "导出数据", list: []}) diff --git a/plugin/chrome/chrome.html b/plugin/chrome/chrome.html new file mode 100644 index 00000000..f50dcf02 --- /dev/null +++ b/plugin/chrome/chrome.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/plugin/chrome/chrome.js b/plugin/chrome/chrome.js new file mode 100644 index 00000000..5f11aa0a --- /dev/null +++ b/plugin/chrome/chrome.js @@ -0,0 +1,142 @@ +var can = Volcanos("chrome", { + _send: function(msg, cb) {chrome.extension.sendRequest(msg, cb)}, + _open: function(url) {chrome.windows.create({url: url})}, + + run: function(can, msg, cb) { + can.misc.Run({names: "chrome", msg: msg}, can, {}, null, cb) + }, + + open: function(msg, cmd, cb) { + chrome.windows.create({url: cmd[0]}) + typeof cb == "function" && cb(msg) + }, + wins: function(msg, cmd, cb) { + if (cmd.length == 0) { + // 窗口列表 + chrome.windows.getAll(function(wins) { + can.core.List(wins, function(win) {win.wid = win.id + msg.Push(win, ["wid", "state", "left", "top", "width", "height"]) + }) + typeof cb == "function" && cb(msg) + }) + return + } + + if (cmd.length > 1) { + // 新建标签 + chrome.tabs.create({windowId: parseInt(cmd[0]), url: cmd[1], selected: false}, function() { + can.wins(msg, [cmd[0]], cb) + }) + return + } + + // 标签列表 + chrome.tabs.getAllInWindow(parseInt(cmd[0]), function(tabs) { + can.core.List(tabs, function(tab) {tab.tid = tab.id + msg.Push(tab, ["tid", "active", "width", "height", "index", "title", "url"]) + }) + typeof cb == "function" && cb(msg) + }) + }, + tabs: function(msg, cmd, cb) { + if (cmd.length == 0) { + chrome.tabs.getAllInWindow(function(tabs) { + can.core.List(tabs, function(tab) { + msg.Push("id", tab.id) + msg.Push("active", tab.active) + msg.Push("index", tab.index) + msg.Push("title", tab.title) + msg.Push("url", tab.url) + }) + typeof cb == "function" && cb(msg) + }) + return + } + + chrome.tabs[cmd[1]](parseInt(cmd[0]), cb) + }, + cookie: function(msg, cmd, cb) { + if (cmd[0] == "modify") {var data = {}; data[cmd[1]] = cmd[2] + chrome.bookmarks.update(cmd[4], data, function() { + typeof cb == "function" && cb(msg) + }) + return + } else if (cmd[0] == "delete") { + chrome.bookmarks.remove(cmd[2], function() { + typeof cb == "function" && cb(msg) + }) + return + } else if (cmd.length > 2) { + chrome.bookmarks.create({parentId: cmd[0], url: cmd[1], title: cmd[2], index: cmd[3]||0}, cb) + } + + chrome.cookies.getAll({name: ""}, function(cs) { + typeof cb == "function" && cb(msg) + }) + }, + history: function(msg, cmd, cb) { + chrome.tabs.getAllInWindow(function(tabs) { + can.core.List(tabs, function(tab) { + msg.Push("id", tab.id) + msg.Push("active", tab.active) + msg.Push("index", tab.index) + msg.Push("title", tab.title) + msg.Push("url", tab.url) + }) + typeof cb == "function" && cb(msg) + }) + }, + bookmark: function(msg, cmd, cb) { + if (cmd[0] == "modify") {var data = {}; data[cmd[1]] = cmd[2] + chrome.bookmarks.update(cmd[4], data, function() { + typeof cb == "function" && cb(msg) + }) + return + } else if (cmd[0] == "delete") { + chrome.bookmarks.remove(cmd[2], function() { + typeof cb == "function" && cb(msg) + }) + return + } else if (cmd.length > 2) { + chrome.bookmarks.create({parentId: cmd[0], url: cmd[1], title: cmd[2], index: cmd[3]||0}, cb) + } + + chrome.bookmarks.getSubTree(cmd[0]||"0", function(labs) { + for (var i = 0; i < labs.length; i++) {labs[i].pid = labs[i].parentId + msg.Push("time", can.base.Time(labs[i].dateAdded)) + msg.Push(labs[i], ["pid", "id", "index", "title", "url"]) + labs = labs.concat(labs[i].children||[]) + } + typeof cb == "function" && cb(msg) + }) + }, +}, Config.libs.concat(Config.list), function(can) {can.Conf(Config) + can.user.toast = function(message, title) {chrome.notifications.create(null, { + message: message, title: title||Config.title, iconUrl: "/favicon.ico", type: "basic", + })}, + + can.socket = can.socket || can.misc.WSS(can, "ws://localhost:9020/space/", {node: "chrome", name: chrome.runtime.id}, function(event, msg) { + if (msg.Option("_handle")) {return can.user.toast(msg.result.join(""))} + + can.user.toast(msg.detail.join(" ")) + switch (msg.detail[0]) { + case "space": can._share = msg.detail[2]; break + case "pwd": msg.Echo("hello world"); break + default: (can[msg.detail[0]]||can.chrome[msg.detail[0]])(msg, msg.detail.slice(1), function(msg) { + msg.Reply(msg) + }); return + } + msg.Reply(msg) + }, function() {can.user.toast("wss connect", "iceberg")}) + + chrome.history.onVisited.addListener(function(item) { + can.run(can, {names: "crx", cmd: ["history", item.id, item.url, item.title]}, function(msg) { + can.user.toast(item.url, item.title) + }) + }) + + chrome.extension.onRequest.addListener(function(msg, sender, cb) { + can.run(can, msg, cb) + }) +}) + diff --git a/plugin/chrome/config.js b/plugin/chrome/config.js new file mode 100644 index 00000000..ba3e6650 --- /dev/null +++ b/plugin/chrome/config.js @@ -0,0 +1,41 @@ +var Config = {iceberg: "http://localhost:9020/chat/", volcano: "/", + libs: ["lib/base", "lib/core", "lib/misc", "lib/page", "lib/user"], + main: "chat", list: ["page/chat", + "pane/Toast", "pane/Tutor", "pane/Debug", + "pane/Carte", "pane/Favor", "pane/Login", + + "pane/Header", + "pane/Ocean", "pane/River", "pane/Storm", "pane/Steam", + "pane/Target", "pane/Source", "pane/Action", + "pane/Footer", + + "plugin/state", "plugin/input", "plugin/table", "plugin/inner", "plugin/media", + ], pane: [ + {group: "index", name: "Toast", pos: "dialog", duration: 3000}, + {group: "index", name: "Tutor", pos: "dialog"}, + {group: "index", name: "Debug", pos: "dialog"}, + {group: "index", name: "Carte", pos: "dialog"}, + {group: "index", name: "Favor", pos: "dialog"}, + {group: "index", name: "Login", pos: "dialog"}, + + {group: "index", name: "Header", pos: "head", state: ["time", "user", "link"], title: "github.com/shylinux/context"}, + {group: "index", name: "Ocean", pos: "dialog", def_name: "meet"}, + {group: "index", name: "River", pos: "left"}, + {group: "index", name: "Storm", pos: "right"}, + {group: "index", name: "Steam", pos: "dialog", def_name: "miss"}, + + {group: "index", name: "Target", pos: "top"}, + {group: "index", name: "Source", pos: "center"}, + {group: "index", name: "Action", pos: "bottom"}, + {group: "index", name: "Footer", pos: "foot", state: ["ntxt", "ncmd"], title: 'shylinux@163.com'}, + + ], title: "范晓旭", layout: {def: "办公", list: ["工作", "办公", "聊天"], size: { + "最大": {head: 0, foot: 0, left: 0, right: 0, bottom: -1, center: 0, top: 0}, + "工作": {head: 30, foot: 30, left: 0, right: 100, bottom: -1, center: 0, top: 0}, + "办公": {head: 30, foot: 30, left: 100, right: 100, bottom: -1, center: 0, top: 0}, + "聊天": {head: 30, foot: 30, left: 100, right: 100, bottom: 300, center: 40, top: -2}, + "全屏": {head: 0, foot: 0, left: 0, right: 0, bottom: -1, center: 0, top: 0}, + }, border: 4, + }, +} + diff --git a/plugin/chrome/popup.html b/plugin/chrome/popup.html new file mode 100644 index 00000000..436c82dd --- /dev/null +++ b/plugin/chrome/popup.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/plugin/chrome/popup.js b/plugin/chrome/popup.js new file mode 100644 index 00000000..2c1ef1c9 --- /dev/null +++ b/plugin/chrome/popup.js @@ -0,0 +1,19 @@ +var can = Volcanos("popup", { + demo: function() { + can.chrome.notice("hi", "hello") + }, +}, Config.libs.concat(Config.list), function(can) {can.Conf(Config) + can.page.Append(can, document.body, [{button: ["baidu", function() { + can.chrome.open("https://www.baidu.com") + }]}]) + can.page.Append(can, document.body, [{button: ["volcanos", function() { + can.chrome.open("http://localhost:9020") + }]}]) + + can.page.Append(can, document.body, [{button: ["send", function() { + can.chrome.send({names: "crx", cmds: ["hi"]}, function(msg) { + can.chrome.notice("hi", "hello") + console.log(msg) + }) + }]}]) +}) diff --git a/plugin/input.js b/plugin/input.js index 3bf56a5c..2db3b37e 100644 --- a/plugin/input.js +++ b/plugin/input.js @@ -1,4 +1,6 @@ Volcanos("onimport", {help: "导入数据", list: [], + _begin: function(can) {}, + _start: function(can) {}, init: shy("添加控件", function(can, item, name, value, option) { var input = {type: "input", name: name, data: item}; item.type = item.type || item._type || item._input; @@ -41,8 +43,112 @@ Volcanos("onimport", {help: "导入数据", list: [], return target.value + (target.value == "" || target.value.endsWith("/")? "": "/") + value }, }) +Volcanos("onfigure", {help: "控件详情", list: [], + date: {click: function(event, can, value, cmd, target) {if (can.date) {return} + target.style.width = "120px" + function set(now) { + target.value = can.base.Time(now); + if (can.item.action == "auto") { + can.run({}); + } + } + + can.stick = false + can.now = target.value? new Date(target.value): new Date(); + can.date = can.page.Append(can, document.body, [{view: ["date input", "fieldset"], style: { + position: "absolute", left: event.clientX+"px", top: event.clientY+10+"px", + }, onmouseleave: function(event) { + if (can.stick) {can.stick = false; return} + can.page.Remove(can, can.date); delete(can.date); + }}]).last + + var action = can.page.Append(can, can.date, [{view: ["action"]}]).last + var control = can.page.AppendAction(can, action, ["今天", "随机", + ["hour"].concat(can.core.List(24)), ["minute"].concat(can.core.List(0, 60, 5)), ["second"].concat(can.core.List(0, 60, 5)), {view: ["", "br"]}, + "上一月", ["year"].concat(can.core.List(can.now.getFullYear() - 20, can.now.getFullYear() + 20)), + ["month"].concat(can.core.List(1, 13)), "下一月", {view: ["", "br"]}, + ], function(event, value, cmd) {can.stick = true; + switch (cmd) { + case "year": can.now.setFullYear(parseInt(value)); show(can.now); return; + case "month": can.now.setMonth(parseInt(value)-1); show(can.now); return; + case "hour": can.now.setHours(parseInt(value)); show(can.now); set(can.now); return; + case "minute": can.now.setMinutes(parseInt(value)); show(can.now); set(can.now); return; + case "second": can.now.setSeconds(parseInt(value)); show(can.now); set(can.now); return; + } + + switch (value) { + case "今天": can.now = new Date(); show(can.now); set(can.now); break; + case "随机": can.now.setDate((Math.random() * 100 - 50) + can.now.getDate()); show(can.now); set(can.now); break; + case "关闭":can.page.Remove(can, can.date); delete(can.date); + case "前一年": can.now.setFullYear(can.now.getFullYear()-1); show(can.now); break; + case "后一年": can.now.setFullYear(can.now.getFullYear()+1); show(can.now); break; + case "上一月": can.now.setMonth(can.now.getMonth()-1); show(can.now); break; + case "下一月": can.now.setMonth(can.now.getMonth()+1); show(can.now); break; + } + }) + + var table = can.page.Append(can, can.date, [{type: "table"}]).table + function click(event) { + var day = new Date(parseInt(event.target.dataset.date)) + can.now = day; + set(can.now); + } + function show(now) { + control.month.value = now.getMonth()+1; + control.year.value = now.getFullYear(); + control.hour.value = now.getHours(); + control.minute.value = parseInt(now.getMinutes()/5)*5; + control.second.value = parseInt(now.getSeconds()/5)*5; + var meta = ["日", "一", "二", "三", "四", "五", "六"] + can.page.Appends(can, table, [{type: "tr", list: can.core.List(meta, function(day) {return {text: [day, "th"]}})}]) + + var one = new Date(now); one.setDate(1); + var end = new Date(now); end.setMonth(now.getMonth()+1); end.setDate(1); + var head = new Date(one); head.setDate(one.getDate()-one.getDay()); + var tail = new Date(end); tail.setDate(end.getDate()+7-end.getDay()); + + var tr; + function add(day, type) { + if (day.getDay() == 0) {tr = can.page.Append(can, table, [{type: "tr"}]).tr} + can.page.Append(can, tr, [{className: can.base.Time(day).split(" ")[0] == can.base.Time(now).split(" ")[0]? "now": type, + text: [day.getDate(), "td"], dataset: {date: day.getTime()}, click: click, + }]) + } + for (var day = new Date(head); day < one; day.setDate(day.getDate()+1)) {add(day, "last")} + for (var day = new Date(one); day < end; day.setDate(day.getDate()+1)) {add(day, "main")} + for (var day = new Date(end); end.getDay() != 0 && day < tail; day.setDate(day.getDate()+1)) {add(day, "next")} + } + + show(can.now); + set(can.now); + }}, + province: {click: function(event, can, value, cmd, target) {if (can.figure) {return} + can.figure = can.page.Append(can, document.body, [{view: ["date input", "fieldset"], style: { + position: "absolute", left: "20px", top: event.clientY+10+"px", + }, onmouseleave: function(event) { + can.page.Remove(can, can.figure); delete(can.figure); + }}]).last + + can.page.Append(can, can.figure, [{include: ["/plugin/github.com/shylinux/echarts/echarts.js", function(event) { + can.page.Append(can, can.figure, [{include: ["/plugin/github.com/shylinux/echarts/china.js", function(event) { + var china_chart = echarts.init(can.page.Append(can, can.figure, [{type: "div", style: {width: "600px", height: "400px"}}]).last); + + var option = {geo: {map: 'china'}}; + china_chart.setOption(option); + + china_chart.on('click', function (params) { + target.value = params.name; + }); + }]}]); + }]}]); + }, + }, +}) Volcanos("onaction", {help: "控件交互", list: [], - onclick: function(event, can) {can.Select(event); can.item.type == "button" && can.run(event)}, + onclick: function(event, can) {can.Select(event); + var figure = can.onfigure[can.item.figure] + figure? figure.click(event, can, can.item, can.item.name, event.target): can.item.type == "button" && can.run(event) + }, onkeydown: function(event, can) { can.page.oninput(event, can, function(event) { switch (event.key) { diff --git a/plugin/table.js b/plugin/table.js index 55d1b70e..eeabcecf 100644 --- a/plugin/table.js +++ b/plugin/table.js @@ -27,7 +27,8 @@ Volcanos("onimport", {help: "导入数据", list: [], var sub = can.Event(event); msg.append.forEach(function(key) {sub.Option(key, msg[key][index].trim())}) typeof cb == "function"? cb(event, can, msg, index, key, cmd, target): - can.run(event, [id, typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + // can.run(event, [id, typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + can.run(event, ["action", typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { can.onimport.init(can, msg, cb, output, option) }, true) })) @@ -82,7 +83,8 @@ Volcanos("ondetail", {help: "组件详情", list: ["选择", "编辑", "删除", if (event.key == " ") {return event.stopPropagation()} if (event.key != "Enter") {return} if (key == "value" && msg.key) {key = msg.key[index]} - can.run(event, [msg.Ids(index), "modify", key, event.target.value, text], function(msg) { + // can.run(event, [msg.Ids(index), "modify", key, event.target.value, text], function(msg) { + can.run(event, ["action", "modify", key, event.target.value, text, msg.Ids(index)], function(msg) { td.innerHTML = event.target.value; can.user.toast("修改成功") }, true) diff --git a/plugin/team/plan.js b/plugin/team/plan.js new file mode 100644 index 00000000..3cf8c72a --- /dev/null +++ b/plugin/team/plan.js @@ -0,0 +1,149 @@ +Volcanos("onimport", {help: "导入数据", list: [], + init: function(can, msg, cb, output, action, option) {output.innerHTML = ""; + if (!msg.append || msg.append.length == 0) { + var code = can.page.Append(can, output, [{view: ["code", "div", msg.Result()]}]).code; + return typeof cb == "function" && cb(msg), code; + } + + var table = can.page.AppendTable(can, output, msg, msg.append); + table.onclick = function(event) {switch (event.target.tagName) { + case "TD": + can.onimport.which(event, table, msg.append, function(index, key) { + can.ondetail["复制"](event, can, msg, event.target.innerHTML, index, key, event.target); + can.Export(event, event.target.innerHTML.trim(), key, index) + }) + break + case "TH": + break + case "TR": + case "TABLE": + }} + table.oncontextmenu = function(event) {var target = event.target; + switch (event.target.tagName) { + case "TD": + can.onimport.which(event, table, msg.append, function(index, key) { + can.user.carte(event, shy("", can.ondetail, can.feature.detail || can.ondetail.list, function(event, cmd, meta) {var cb = meta[cmd]; + var id = msg.Ids(index); + var sub = can.Event(event); + msg.append.forEach(function(key) {sub.Option(key, msg[key][index].trim())}) + typeof cb == "function"? cb(event, can, msg, index, key, cmd, target): + // can.run(event, [id, typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + can.run(event, ["action", typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + can.onimport.init(can, msg, cb, output, option) + }, true) + })) + }) + event.stopPropagation() + event.preventDefault() + break + case "TH": + case "TR": + case "TABLE": + } + } + + can.page.Select(can, table, "div.miss", function(item) { + item.setAttribute("draggable", true) + item.ondragstart = function(event) {can.drag = event.target} + item.ondragover = function(event) {event.preventDefault()} + item.ondrop = function(event) {event.preventDefault() + can.preview.insertBefore(can.drag, item) + } + }) + + can.page.Select(can, table, "tr", function(tr) {tr.list = []; + can.page.Select(can, tr, "td", function(item, index) {tr.list.push(item); + // item.setAttribute("draggable", true) + // item.ondragstart = function(event) {can.drag = event.target} + item.ondragover = function(event) {event.preventDefault(), can.page.Select(can, table, "td.over", function(item) { + can.page.ClassList.del(can, item, "over") + }), can.page.ClassList.add(can, item, "over")} + item.ondrop = function(event) {event.preventDefault() + item.append(can.drag) + + var data = can.drag.dataset; + var begin_time = new Date(data.begin_time); + begin_time.setHours(parseInt(tr.list[0].innerText)); + begin_time.setMinutes(0); + begin_time.setSeconds(0); + if (can.Option("scale") == "week") { + begin_time.setDate(begin_time.getDate() - (begin_time.getDay() - index + 1)) + } + can.run(event, ["action", "modify", "begin_time", can.base.Time(begin_time), data.begin_time, data.id, data.name], function(msg) { + can.user.toast("修改成功") + }, true); + } + }) + }) + + return typeof cb == "function" && cb(msg), table; + }, + which: function(event, table, list, cb) {if (event.target == table) {return cb(-1, "")} + can.page.Select(can, table, "tr", function(tr, index) {if (event.target == tr) {return cb(index-1, "")} + can.page.Select(can, tr, "th,td", function(td, order) { + if (event.target == td) {return cb(index-1, list[order])} + }) + }) + }, + + favor: function(event, can, msg, cmd, output) {var key = msg.detail[0]; + var cb = can.onaction[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, output); return msg.Echo(can._name, " onaction ", key), msg._hand = true} + var cb = can.onchoice[key]; if (typeof cb == "function") {cb(event, can, msg, cmd, output); return msg.Echo(can._name, " onchoice ", key), msg._hand = true} + }, +}) +Volcanos("onaction", {help: "组件交互", list: [], +}) +Volcanos("onchoice", {help: "组件菜单", list: ["返回", "清空", "复制", "下载"], + "返回": function(event, can, msg, cmd, target) { + can.run(event, ["", "Last"]) + }, + "清空": function(event, can, msg, cmd, target) { + can.target.innerHTML = ""; + }, + "复制": function(event, can, msg, cmd, target) { + var list = can.onexport.Format(can, msg, "data"); + can.user.toast(can.page.CopyText(can, list[2]), "复制成功") + }, + "下载": function(event, can, msg, cmd, target) {msg = msg || can.msg; + var list = can.onexport.Format(can, msg, msg._plugin_name||"data"); + can.page.Download(can, list[0]+list[1], list[2]); + }, +}) +Volcanos("ondetail", {help: "组件详情", list: ["选择", "编辑", "删除", "复制", "下载"], + "选择": "select", + "删除": "delete", + "编辑": function(event, can, msg, index, key, cmd, td) { + var text = td.innerHTML; + var input = can.page.Appends(can, td, [{type: "input", value: text, style: {width: td.clientWidth+"px"}, data: {onkeydown: function(event) { + if (event.key == " ") {return event.stopPropagation()} + if (event.key != "Enter") {return} + if (key == "value" && msg.key) {key = msg.key[index]} + // can.run(event, [msg.Ids(index), "modify", key, event.target.value, text], function(msg) { + can.run(event, ["action", "modify", key, event.target.value, text, msg.Ids(index)], function(msg) { + td.innerHTML = event.target.value; + can.user.toast("修改成功") + }, true) + }}}]).first; + input.focus(); + input.setSelectionRange(0, input.value.length); + }, + "复制": function(event, can, msg, index, key, cmd, target) { + can.user.toast(can.page.CopyText(can, target.innerHTML), "复制成功") + }, + "下载": function(event, can, msg, index, key, cmd, target) { + can.page.Download(can, key, target.innerHTML); + }, +}) +Volcanos("onexport", {help: "导出数据", list: [], + Format: function(can, msg, name) { + var ext = ".csv", txt = can.page.Select(can, can.target, "tr", function(tr) { + return can.page.Select(can, tr, "td,th", function(td) {return td.innerText}).join(",") + }).join("\n"); + + !txt && (ext = ".txt", txt = msg.result && msg.result.join("") || ""); + return [name, ext, txt] + }, +}) + + + diff --git a/plugin/wiki/feel.js b/plugin/wiki/feel.js index 4e944594..65c42a4b 100644 --- a/plugin/wiki/feel.js +++ b/plugin/wiki/feel.js @@ -12,11 +12,12 @@ Volcanos("onimport", {help: "导入数据", list: [], var items = item.path.split("."); switch (items[items.length-1]) { + case "png": case "JPG": - return {img: "/share/local/web.wiki.feel/"+item.path, width: width, oncontextmenu: menu} + return {className: "preview", img: "/share/local/web.wiki.feel/"+item.path, width: width, oncontextmenu: menu} case "MOV": case "m4v": - return {type: "video", width: width, oncontextmenu: menu, + return {className: "preview", type: "video", width: width, oncontextmenu: menu, onplay: cb, onpause: cb, onloadedmetadata: cb, onloadeddata: cb, @@ -31,7 +32,7 @@ Volcanos("onimport", {help: "导入数据", list: [], var table = can.page.AppendTable(can, output, msg, msg.append); var begin = 0, limit = 3; - var rate = 1, width = 200; + var rate = 1, width = 600; var control = can.page.Append(can, output, [{view: ["control"], list: [ {select: [["width", 100, 200, 400, 600, 800], function(event, value) {width = parseInt(value), page(begin, limit)}]}, {select: [["rate", 0.1, 0.2, 0.5, 1, 2, 3, 5, 10], function(event, value) {rate = value}]}, @@ -63,23 +64,27 @@ Volcanos("onimport", {help: "导入数据", list: [], page(begin, limit); function show(index) {var item = list[can.page.Select(can, table, "tr")[index+1].dataset.index]; - var video; + var video = {}; var timer = can.user.toast({text: "", list: [{view: "control", list: [ {button: ["close", function(event) {video.pause(), timer.toast.Hide()}]}, - {select: [["width", 100, 200, 400, 600, 800], function(event, value) {timer.toast.Show(event, parseInt(value)+20), video.width = value}]}, + {select: [["width", 100, 200, 400, 600, 800], function(event, value) {timer.toast.Show(event, parseInt(value)+20), + width = value + timer.toast.preview.setAttribute("width", value) + // video.width = value + }]}, {select: [["rate", 0.1, 0.2, 0.5, 1, 2, 3, 5, 10], function(event, value) {rate = video.playbackRate = value}]}, {button: ["prev", function(event) {show(index-1)}]}, {text: index+"/"+list.length}, {button: ["next", function(event) {show(index+1)}]}, {type: "br"}, {text: item.path}, {type: "br"}, {text: item.label}, - ]}].concat([view(index, 400, true, function(event) {video = event.target; + ]}].concat([view(index, 600, true, function(event) {video = event.target; switch (event.type) { case "loadeddata": video.playbackRate = rate; break case "ended": show(index+1); break } - })]), width: 400+20, height: 620, duration: -1}) - timer.toast.width.value = 400; + })]), width: 600+20, height: 620, duration: -1}) + timer.toast.width.value = 600; timer.toast.rate.value = rate; } @@ -99,6 +104,29 @@ Volcanos("onimport", {help: "导入数据", list: [], case "TR": case "TABLE": }} + table.oncontextmenu = function(event) {var target = event.target; + switch (event.target.tagName) { + case "TD": + can.onimport.which(event, table, msg.append, function(index, key) { + can.user.carte(event, shy("", can.ondetail, can.feature.detail || can.ondetail.list, function(event, cmd, meta) {var cb = meta[cmd]; + var id = msg.Ids(index); + var sub = can.Event(event); + msg.append.forEach(function(key) {sub.Option(key, msg[key][index].trim())}) + typeof cb == "function"? cb(event, can, msg, index, key, cmd, target): + // can.run(event, [id, typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + can.run(event, ["action", typeof cb == "string"? cb: cmd, key, target.innerHTML], function(msg) { + can.onimport.init(can, msg, cb, output, option) + }, true) + })) + }) + event.stopPropagation() + event.preventDefault() + break + case "TH": + case "TR": + case "TABLE": + } + } return typeof cb == "function" && cb(msg), table; }, which: function(event, table, list, cb) {if (event.target == table) {return cb(-1, "")} @@ -123,17 +151,12 @@ Volcanos("onchoice", {help: "组件交互", list: ["保存", "清空", ["rect", console.log("choice", cmd) }, }) -Volcanos("ondetail", {help: "组件详情", list: ["标签", "删除"], +Volcanos("ondetail", {help: "组件详情", list: ["标签"], "标签": function(event, can, msg, index, key, cmd, target) { can.user.prompt("目标", function(kind) { can.run(event, ["action", "标签", msg.path, kind], function() { }, true) }) - var figure = can.onfigure[target.tagName] - figure.copy(event, can, target) - }, - "删除": function(event, can, msg, index, key, cmd, target) { - can.page.Remove(can, target) }, }) Volcanos("onstatus", {help: "组件状态", list: ["begin", "width", "point", "which"], diff --git a/plugin/wiki/mind.js b/plugin/wiki/mind.js index 4491cb27..ad487c1d 100644 --- a/plugin/wiki/mind.js +++ b/plugin/wiki/mind.js @@ -1,13 +1,19 @@ Volcanos("onimport", {help: "导入数据", list: [], + _begin: function(can) { + }, + _start: function(can) { + can.Action("stroke-width", 2) + can.Action("stroke", "yellow") + can.Action("fill", "purple") + can.Action("grid", "20") + }, init: function(can, msg, cb, output, action, option) {output.innerHTML = ""; - if (msg.append && msg.append.length > 0) { + if (msg.append && msg.append.length > 0) {action.innerHTML = ""; var table = can.page.AppendTable(can, output, msg, msg.append); table.onclick = function(event) {switch (event.target.tagName) { case "TD": can.onimport.which(event, table, msg.append, function(index, key) { - var name = event.target.innerHTML.trim() - can.Option("name", name) - can.run(event, [name]) + can.run(event, [can.Option("name", event.target.innerHTML.trim())]) }) break case "TH": @@ -19,18 +25,19 @@ Volcanos("onimport", {help: "导入数据", list: [], } var code = can.page.Append(can, output, [{view: ["code", "div", msg.Result()||can.Export(event, null, "file")]}]).code; - can.page.Select(can, output, "svg", function(svg) {can.group = can.svg = svg + can.page.Select(can, output, "svg", function(svg) {can.group = can.svg = svg; can.onaction.init(event, can, msg, "init", svg); - can.onaction.list[1] = ["group", "svg", "add"] + can.onaction.list[2] = ["group", "svg", "add"]; can.page.Select(can, svg, "*", function(item, index) { can.onaction.init(event, can, msg, index, item); switch (item.tagName) { case "g": - can.onaction.list[1].push(item.Value("class")) + can.onaction.list[2].push(item.Value("class")); break } }) }), can.point = []; + return typeof cb == "function" && cb(msg), code; }, which: function(event, table, list, cb) {if (event.target == table) {return cb(-1, "")} @@ -42,53 +49,65 @@ Volcanos("onimport", {help: "导入数据", list: [], }, }) Volcanos("onfigure", {help: "图形绘制", list: [], - move: { - draw: function(event, can, point) { - if (point.length == 1) { - if (event.type != "click") {return} - // 记录图形 - can.current = {target: event.target} - } else if (point.length == 2) { - if (event.type == "click") {return can.point = [], delete(can.current)} - } + select: {draw: function(event, can, point) {if (point.length == 1) {return} + var p0 = point[0], p1 = point[1]; + var data = { + "x": p0.x > p1.x? p1.x: p0.x, + "y": p0.y > p1.y? p1.y: p0.y, + "width": Math.abs(p0.x-p1.x), + "height": Math.abs(p0.y-p1.y), + "fill": "#11000000", + "class": "temp", + } + can.Status(event, data, "width"); + event.type == "click" && point.length == 2 && (can.point = []) + return data; + }}, + resize: {draw: function(event, can, point) { + if (point.length == 1) {if (event.type != "click") {return} + // 记录图形 + can.current = {target: event.target} + } else if (point.length == 2) { + if (event.type == "click") {can.point = [], delete(can.current); return} + } - var target = can.current.target - var figure = can.onfigure[can.current.target.tagName]; - var move = figure.data.move || {x: "x", y: "y"} - if (point.length == 1) { - // 记录起点 - can.current.x = parseInt(target.Value(move.x)) - can.current.y = parseInt(target.Value(move.y)) - } else { - // 移动图形 - target.Value(move.x, can.current.x+point[1].x-point[0].x) - target.Value(move.y, can.current.y+point[1].y-point[0].y) - } - }, - }, - resize: { - draw: function(event, can, point) { - if (point.length == 1) { - if (event.type != "click") {return} - // 记录图形 - can.current = {target: event.target} - } else if (point.length == 2) { - if (event.type == "click") {return can.point = [], delete(can.current)} - } + var target = can.current.target + var figure = can.onfigure[target.tagName]; + if (point.length == 1) { + // 记录起点 + can.core.Item(figure.data.resize, function(key, value) { + can.current[key] = parseInt(target.Value(value)) + }) + } else { + var resize = figure.data.resize; + target.Value(resize.width, can.current.width + point[1].x - point[0].x) + target.Value(resize.height, can.current.height + point[1].y - point[0].y) + } + }}, + move: {draw: function(event, can, point) { + if (point.length == 1) {if (event.type != "click") {return} + // 记录图形 + can.current = {target: event.target} + } else if (point.length == 2) { + if (event.type == "click") {return can.point = [], delete(can.current), null} + } - var target = can.current.target - var figure = can.onfigure[can.current.target.tagName]; - var move = figure.data.move || {x: "x", y: "y"} - if (point.length == 1) { - // 记录起点 - can.core.List(figure.data.resize, function(item) { - can.current[item] = parseInt(target.Value(item)) - }) - } else { - // 绽放图形 - figure.resize(event, can, point, can.current, target) - } - }, + var target = can.current.target + var figure = can.onfigure[can.current.target.tagName]; + var move = figure.data.move || {x: "x", y: "y"} + if (point.length == 1) { + // 记录起点 + can.current.x = parseInt(target.Value(move.x)) + can.current.y = parseInt(target.Value(move.y)) + } else { + // 移动图形 + target.Value(move.x, can.current.x+point[1].x-point[0].x) + target.Value(move.y, can.current.y+point[1].y-point[0].y) + } + }}, + svg: { + data: {resize: {width: "width", height: "height"}}, + show: function(event, can, value, target) {}, }, text: { data: {move: {x: "x", y: "y"}}, // hi @@ -96,29 +115,22 @@ Volcanos("onfigure", {help: "图形绘制", list: [], }, rect: { data: { - resize: ["width", "height", "rx"], + resize: {width: "width", height: "height"}, move: {x: "x", y: "y"}, copy: ["width", "height", "rx", "ry"], rx: 4, ry: 4, }, // - draw: function(event, can, point) { - if (point.length == 1) {return} + draw: function(event, can, point) {if (point.length < 2) {return} var p0 = point[0], p1 = point[1]; var data = { "x": p0.x > p1.x? p1.x: p0.x, "y": p0.y > p1.y? p1.y: p0.y, "width": Math.abs(p0.x-p1.x), "height": Math.abs(p0.y-p1.y), + "rx": this.data.rx, + "ry": this.data.ry, } - can.core.Item(can.onfigure.rect.data, function(key, value) { - data[key] = value - }) can.Status(event, data, "width"); - event.type == "click" && point.length == 2 && (can.point = []) - return data; - }, - resize: function(event, can, point, current, target) { - target.Value("width", current.width + point[1].x - point[0].x) - target.Value("height", current.height + point[1].y - point[0].y) + return event.type == "click" && point.length == 2 && (can.point = []), data; }, text: function(event, can, data, target) { data.x = target.x.baseVal.value+target.width.baseVal.value/2 @@ -131,6 +143,30 @@ Volcanos("onfigure", {help: "图形绘制", list: [], + " + (" + value.width.baseVal.value + "," + value.height.baseVal.value+ ")" }, }, + line: { + data: { + resize: {width: "x2", height: "y2"}, + move: {x: "x1", y: "y1"}, copy: ["x1", "y1", "x2", "y2"], + }, // + draw: function(event, can, point) {if (point.length < 2) {return} + var p0 = point[0], p1 = point[1]; + var data = { + "x1": p0.x, "y1": p0.y, + "x2": p1.x, "y2": p1.y, + } + return event.type == "click" && point.length == 2 && (can.point = []), data; + }, + text: function(event, can, data, target) { + data.x = (target.x1.baseVal.value + target.x2.baseVal.value) / 2 + data.y = (target.y1.baseVal.value + target.y2.baseVal.value) / 2 + return data + }, + show: function(event, can, value, target) { + return value.tagName + + ": (" + value.x1.baseVal.value + "," + value.y1.baseVal.value+ ")" + + " - (" + value.x2.baseVal.value + "," + value.y2.baseVal.value+ ")" + }, + }, circle: { data: {move: {x: "cx", y: "cy"}, copy: ["r"]}, // draw: function(event, can, point) { @@ -176,28 +212,6 @@ Volcanos("onfigure", {help: "图形绘制", list: [], + " > (" + parseInt(value.rx.baseVal.value) + parseInt(value.ry.baseVal.value) + ")" }, }, - line: { - data: {}, // - draw: function(event, can, point) { - var p0 = point[0], p1 = point[1]; - var data = { - "x1": p0.x, "y1": p0.y, - "x2": p1.x, "y2": p1.y, - } - event.type == "click" && point.length == 2 && (can.point = []) - return data; - }, - text: function(event, can, data, target) { - data.x = (target.x1.baseVal.value + target.x2.baseVal.value) / 2 - data.y = (target.y1.baseVal.value + target.y2.baseVal.value) / 2 - return data - }, - show: function(event, can, value, target) { - return value.tagName - + ": (" + value.x1.baseVal.value + "," + value.y1.baseVal.value+ ")" - + " - (" + value.x2.baseVal.value + "," + value.y2.baseVal.value+ ")" - }, - }, path: { data: {}, // draw: function(event, can, point) { @@ -211,7 +225,6 @@ Volcanos("onfigure", {help: "图形绘制", list: [], } }).join(" ") } - console.log(data) event.type == "click" && point.length == 4 && (can.point = []) return data; }, @@ -261,24 +274,27 @@ Volcanos("onfigure", {help: "图形绘制", list: [], }, }, }) -Volcanos("onaction", {help: "组件菜单", list: ["保存", +Volcanos("onaction", {help: "组件菜单", list: ["保存", "清空", ["group", "svg", "add"], ["stroke-width", 1, 2, 3, 4, 5], ["stroke", "red", "yellow", "green", "purple", "blue", "cyan", "white", "black"], - ["fill", "red", "yellow", "green", "purple", "blue", "cyan", "white", "black"], - ["shape", "move", "resize", "rect", "circle", "ellipse", "path", "line", "polyline", "polygon"], + ["fill", "red", "yellow", "green", "purple", "blue", "cyan", "white", "black", "#0000"], + ["shape", "move", "select", "resize", "rect", "circle", "ellipse", "path", "line", "polyline", "polygon"], + ["grid", 1, 2, 3, 4, 5, 10, 20], ], "保存": function(event, can, msg, cmd, target) { can.run(event, ["action", cmd, can.Option("name"), can.Export(event, can.svg, "file")], function() { can.user.toast("保存成功") }, true) }, + "清空": function(event, can, msg, cmd, target) {can.svg.innerHTML = ""}, + group: function(event, can, value, cmd, target) { switch (value) { case "svg": return can.group = can.svg; case "add": can.user.prompt("add group", function(name) { - can.svg.append(can.group = document.createElementNS('http://www.w3.org/2000/svg', 'g')) + can.svg.append(can.onaction.init(event, can, value, cmd, can.group = document.createElementNS('http://www.w3.org/2000/svg', 'g'))) can.group.Value("class", name) can.core.List(["stroke-width", "stroke", "fill"], function(name) { can.group.Value(name, can.Action(name)) @@ -300,11 +316,7 @@ Volcanos("onaction", {help: "组件菜单", list: ["保存", stroke: function(event, can, value, cmd, target) {can.group.Value(cmd, value)}, fill: function(event, can, value, cmd, target) {can.group.Value(cmd, value)}, shape: function(event, can, value, cmd, target) {can.shape = value}, - - resize: function(event, can, value, cmd, item) {var target = can.target.firstChild; - if (cmd == "x") {target.style.width = target.offsetHeight + value + "px"} - if (cmd == "y") {target.style.height = target.offsetHeight + value + "px"} - }, + grid: function(event, can, value, cmd, target) {can.grid = value}, init: function(event, can, msg, cmd, item) { item.ondblclick = item.oncontextmenu = function(event) {can.user.carte(event, shy("", can.ondetail, can.ondetail.list, function(event, key, meta) {var cb = meta[key]; @@ -312,10 +324,10 @@ Volcanos("onaction", {help: "组件菜单", list: ["保存", }), can), event.stopPropagation(), event.preventDefault()} item.onclick = function() { } - item.Value = function(key, value) {return value && item.setAttribute(key, value), item.getAttribute(key||"class")||""} + item.Value = function(key, value) {return value && item.setAttribute(key, value), item.getAttribute(key||"class")||item[key]&&item[key].baseVal&&item[key].baseVal.value||item[key]&&item[key].baseVal||""} return item; }, - push: function(event, can, msg, cmd, target) { + push: function(event, can, msg, cmd, target) {cmd = {select: "rect"}[cmd] || cmd var rect = document.createElementNS("http://www.w3.org/2000/svg", cmd); target.appendChild(can.onaction.init(event, can, msg, cmd, rect)); can.core.Item(msg, function(key, value) {rect.Value(key, value)}); @@ -333,11 +345,14 @@ Volcanos("onaction", {help: "组件菜单", list: ["保存", }, onclick: function(event, can) {if (!can.svg) {return} - var p = can.svg.getBoundingClientRect() - var point = {x: event.clientX-p.x, y: event.clientY-p.y} + var p = can.svg.getBoundingClientRect(); + var point = {x: event.clientX-p.x, y: event.clientY-p.y}; + point.x = point.x - point.x % parseInt(can.Action("grid")); + point.y = point.y - point.y % parseInt(can.Action("grid")); - can.point = (can.point || []).concat([point]) - can.onaction.draw(event, can, can.point) + can.point = (can.point || []).concat([point]); + can.temp && can.page.Remove(can, can.temp) && delete(can.temp); + can.onaction.draw(event, can, can.point); }, onmouseover: function(event, can) { can.Status(event, event.target, "which") @@ -345,24 +360,16 @@ Volcanos("onaction", {help: "组件菜单", list: ["保存", onmousemove: function(event, can) {if (!can.svg || can.point.length == 0) {return} var p = can.svg.getBoundingClientRect() var point = {x: event.clientX-p.x, y: event.clientY-p.y} + point.x = point.x - point.x % parseInt(can.Action("grid")); + point.y = point.y - point.y % parseInt(can.Action("grid")); can.temp && can.page.Remove(can, can.temp) && delete(can.temp) can.temp = can.onaction.draw(event, can, can.point.concat(point)) can.Status(event, point, "point") }, - onkeydown: function(event, can) { - if (event.key == "Enter") { - can.point = [] - return - } - }, -}) -Volcanos("onchoice", {help: "组件交互", list: ["保存", "清空", ["rect", "rect", "line", "circle"]], - "清空": function(event, can, msg, cmd, target) { - console.log("choice", cmd) - }, }) +Volcanos("onchoice", {help: "组件交互", list: ["保存", "清空"]}) Volcanos("ondetail", {help: "组件详情", list: ["编辑", "复制", "删除"], "编辑": function(event, can, msg, index, key, cmd, target) { can.user.prompt("文字", function(text) { @@ -387,9 +394,7 @@ Volcanos("ondetail", {help: "组件详情", list: ["编辑", "复制", "删除"] can.core.List(figure.copy, function(item) {data[item] = target.Value(item)}); return data && can.onaction.push(event, can, data, target.tagName, can.group||can.svg) }, - "删除": function(event, can, msg, index, key, cmd, target) { - can.page.Remove(can, target) - }, + "删除": function(event, can, msg, index, key, cmd, target) {can.page.Remove(can, target)}, }) Volcanos("onstatus", {help: "组件状态", list: ["begin", "width", "point", "which"], "begin": function(event, can, value, cmd, target) {target.innerHTML = value? value.x+","+value.y: ""}, diff --git a/plugin/wiki/word.js b/plugin/wiki/word.js index 47d16b70..71f68109 100644 --- a/plugin/wiki/word.js +++ b/plugin/wiki/word.js @@ -1,4 +1,6 @@ Volcanos("onimport", {help: "导入数据", list: [], + _begin: function(can) {}, + _start: function(can) {}, init: function(can, msg, cb, output, action, option) {output.innerHTML = ""; if (msg.append && msg.append.length > 0) { var table = can.page.AppendTable(can, output, msg, msg.append); @@ -17,12 +19,21 @@ Volcanos("onimport", {help: "导入数据", list: [], return typeof cb == "function" && cb(msg), table; } - can.page.Append(can, output, [{view: "preview", inner: msg.Option("preview"), style: { - float: "left", "max-height": "250px", overflow: "auto", - border: "solid 2px red", - }}]) - var last = can.page.Append(can, output, [{type: "textarea", cols: 32, rows: 19, inner: msg.Result()}]).last; - return typeof cb == "function" && cb(msg), can.view = last; + can.preview = can.page.Append(can, output, [{view: "preview", inner: msg.Result(), + style: {border: "solid 2px red"}, + }]).last + + can.page.Select(can, can.preview, ".story", function(item) { + var figure = can.onfigure[item.dataset.type] || can.onfigure[item.localName]; + + item.onclick = function(event) {can.node = item} + item.oncontextmenu = function(event) {var target = event.target; can.user.carte(event, shy("", can.ondetail, figure.menu||can.ondetail.list, function(event, key, meta) {var cb = meta[key]; + typeof cb == "function" && cb(event, can, msg, 0, key, key, target); + }), can), event.stopPropagation(), event.preventDefault()} + + figure && figure.init && figure.init({}, can, item.localName, "init", item) + }) + return typeof cb == "function" && cb(msg), can.preview; }, which: function(event, table, list, cb) {if (event.target == table) {return cb(-1, "")} can.page.Select(can, table, "tr", function(tr, index) {if (event.target == tr) {return cb(index-1, "")} @@ -32,12 +43,235 @@ Volcanos("onimport", {help: "导入数据", list: [], }) }, }) -Volcanos("onaction", {help: "组件菜单", list: ["保存"], - "保存": function(event, can, msg, cmd, target) { - can.run(event, ["action", cmd, can.Option("name"), can.view.value], function() { +Volcanos("onfigure", {help: "图形绘制", list: [], + premenu: { + init: function(event, can, value, cmd, target) { + can.page.Append(can, target, can.page.Select(can, can.preview, "h1.story,h2.story,h3.story", function(item) {var data = item.dataset; + return {text: [item.innerHTML, "li"], onclick: function(event) { + item.scrollIntoView(); + }}; + })) + }, + save: function(event, can, value, cmd, target) {return "premenu"}, + }, + endmenu: { + init: function(event, can, value, cmd, target) {}, + save: function(event, can, value, cmd, target) {return "endmenu"}, + }, + h1: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "h1", "h1"], dataset: {type: "title", name: "", text: ""}, inner: "h1...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'title "' + value.replace(data.name+" ", "") + '"': "" + }, + }, + h2: { + push: function(event, can, value, cmd, target) { + return [{view: ["story", "h2", "h2"], dataset: {type: "title", name: "", text: ""}, inner: "h2...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'chapter "' + value.replace(data.name+" ", "") + '"': "" + }, + }, + h3: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "h3", "h3"], dataset: {type: "title", name: "", text: ""}, inner: "h3...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'section "' + value.replace(data.name+" ", "") + '"': "" + }, + }, + brief: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "p", "p"], dataset: {type: "brief", name: "", text: ""}, inner: "brief...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'brief "'+data.name+'" `' + value + '`': "" + }, + }, + refer: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "ul"], dataset: {type: "refer", name: "", text: ""}, list: [{type: "li", inner: "refer...."}]}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'refer "'+data.name+'" `\n' + can.page.Select(can, target, "li", function(item) { + return item.innerHTML.replace(": ", " ") + }).join("\n") + '\n`': "" + }, + }, + spark: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "p", "p"], dataset: {type: "spark", name: "", text: ""}, inner: "spark...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'spark "'+data.name+'" `' + value + '`': "" + }, + }, + + local: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "div"], dataset: {type: "local", name: "", text: ""}, inner: "local...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'local "'+data.name+'" '+' `' + data.text + '`': "" + }, + }, + shell: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "code", "code"], dataset: {type: "shell", name: "", text: "", dir: "./"}, inner: "shell...."}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'shell "'+data.name+'" '+'"'+data.dir+'"' +' `' + data.text + '`': "" + }, + }, + order: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "ul"], dataset: {type: "order", name: "", text: ""}, list: [{type: "li", inner: "order...."}]}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'order "'+data.name+'" `\n' + can.page.Select(can, target, "li", function(item) { + return item.innerHTML + }).join("\n") + '\n`': "" + }, + }, + table: { + data: {menu: ["追加行", "追加列", "删除行", "删除列"]}, + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "table", "table"], dataset: {type: "table", name: "", text: ""}, list: [ + {type: "tr", list: [{type: "th"}, {type: "th"}]}, + {type: "tr", list: [{type: "td"}, {type: "td"}]}, + ]}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'table "'+data.name+'" `\n' + can.page.Select(can, target, "tr", function(tr) { + return can.page.Select(can, tr, "th,td", function(td) { + return td.innerHTML + }).join(" ") + }).join("\n") + '\n`': "" + }, + }, + stack: { + init: function(event, can, value, cmd, target) {var data = target.dataset; + can.page.Select(can, target, "div.stack", function(stack) {var data = stack.dataset||{}; + function fold(stack) { + stack.nextSibling && (stack.nextSibling.style.display = "none") + can.page.Select(can, stack, "span.state", function(state) { + if (state.innerText == "o") {return} + can.page.ClassList.add(can, stack, "fold") + can.page.ClassList.del(can, stack, "span") + state.innerText = ">" + }) + } + function span(stack) { + stack.nextSibling && (stack.nextSibling.style.display = "") + can.page.Select(can, stack, "span.state", function(state) { + if (state.innerText == "o") {return} + can.page.ClassList.add(can, stack, "span") + can.page.ClassList.del(can, stack, "fold") + state.innerText = "v" + }) + } + function mark(stack, color) { + stack.style.background = color; + stack.style.color = color == ""? "": "white"; + } + + stack.onclick = function(event) {stack.nextSibling && (stack.nextSibling.style.display == "none"? span(stack): fold(stack))} + stack.oncontextmenu = function(event) {var detail = can.feature.detail || can.ondetail.list, target = event.target; + can.user.carte(event, shy("", can.ondetail, ["全部折叠", "全部展开", "标记颜色", "清除颜色", "red", "green", "blue"], function(event, cmd, meta) {var cb = meta[cmd]; + switch (cmd) { + case "red": + case "green": + case "blue": + mark(target, cmd) + break + case "标记颜色": + can.user.prompt("请输入颜色:", function(color) { + mark(target, color) + }) + break + case "清除颜色": + mark(target, "") + break + case "全部折叠": + fold(stack), can.page.Select(can, stack.nextSibling, "div.stack", fold) + break + case "全部展开": + span(stack), can.page.Select(can, stack.nextSibling, "div.stack", span) + break + } + })) + } + }) + }, + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["stack", "div"], dataset: {type: "stack", name: "", text: ""}}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'stack "'+data.name+'"' +' `' + data.text + '`': "" + }, + }, + + label: { + init: function(event, can, value, cmd, target) {var data = target.dataset; + target.Value = function(key, value) {return value && target.setAttribute(key, value), target.getAttribute(key||"class")||target[key]&&target[key].baseVal&&target[key].baseVal.value||target[key]&&target[key].baseVal||""} + }, + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "svg"], dataset: {type: "story", name: "", text: ""}}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'label "'+data.name+'"' +' `\n' + data.text + '\n`' + " " + [ + target.Value("font-size")||16, target.Value("stroke")||"yellow", target.Value("fill")||"blue", + ].join(" "): "" + }, + }, + chain: { + push: function(event, can, value, cmd, target) {var data = target.dataset; + return [{view: ["story", "svg"], dataset: {type: "story", name: "", text: ""}}] + }, + save: function(event, can, value, cmd, target) {var data = target.dataset; + return value? 'chain "'+data.name+'"' +' `\n' + data.text + '\n`': "" + }, + }, +}) +Volcanos("onaction", {help: "组件菜单", list: ["保存", ["操作", "只读", "排序", "编辑"], + "插入", ["元素", "h1", "h2", "h3", "brief", "refer", "spark", "shell", "order", "table", "stack"]], + + "保存": function(event, can, value, cmd, target) { + var save = can.page.Select(can, target, ".story", function(story) { + var figure = can.onfigure[story.dataset.type] || can.onfigure[story.localName]; + return figure && figure.save && figure.save(event, can, story.innerHTML, cmd, story) || story.innerHTML + }).join("\n\n") + + can.run(event, ["action", cmd, can.Option("name"), save], function(msg) { can.user.toast("保存成功") }, true) }, + "只读": function(event, can, value, cmd, target) { + can.page.Select(can, can.preview, ".story", function(item) { + item.setAttribute("contenteditable", false) + item.setAttribute("draggable", false) + }) + }, + "排序": function(event, can, value, cmd, target) { + can.page.Select(can, can.preview, ".story", function(item) { + item.setAttribute("draggable", true) + item.ondragstart = function(event) {can.drag = event.target} + item.ondragover = function(event) {event.preventDefault()} + item.ondrop = function(event) {event.preventDefault() + can.preview.insertBefore(can.drag, item) + } + }) + }, + "编辑": function(event, can, value, cmd, target) { + can.page.Select(can, can.preview, ".story", function(item) { + item.setAttribute("contenteditable", true) + }) + }, + "插入": function(event, can, value, cmd, target) {var figure = can.onfigure[can.Action("元素")]; + can.page.Append(can, can.preview, figure.push(event, can, value, cmd, target)).first.setAttribute("contenteditable", true) + }, }) Volcanos("onchoice", {help: "组件交互", list: ["保存", "清空", ["rect", "rect", "line", "circle"]], "清空": function(event, can, msg, cmd, target) { @@ -60,20 +294,32 @@ Volcanos("ondetail", {help: "组件详情", list: ["编辑", "删除"], target.Text = p }, target.Text && target.Text.innerText || "") }, - "复制": function(event, can, msg, index, key, cmd, target) { - var figure = can.onfigure[target.tagName] - figure.copy(event, can, target) - }, "删除": function(event, can, msg, index, key, cmd, target) { can.page.Remove(can, target) }, -}) -Volcanos("onstatus", {help: "组件状态", list: ["begin", "width", "point", "which"], - "begin": function(event, can, value, cmd, target) {target.innerHTML = value? value.x+","+value.y: ""}, - "width": function(event, can, value, cmd, target) {target.innerHTML = value? value.width+","+value.height: ""}, - "point": function(event, can, value, cmd, target) {target.innerHTML = value.x+","+value.y}, - "which": function(event, can, value, cmd, target) {var figure = can.onfigure[value.tagName]; - target.innerHTML = figure? figure.show(event, can, value, target): value.tagName; + + "删除行": function(event, can, msg, index, key, cmd, target) { + var table = target.parentNode.parentNode + var tr = target.parentNode + table.removeChild(tr) + }, + "追加行": function(event, can, msg, index, key, cmd, target) { + var tr = document.createElement("tr") + can.page.Append(can, tr, can.page.Select(can, target.parentNode, "td,th", function() { + return {type: "td", inner: " "} + })) + target.parentNode.parentNode.append(tr) + }, + "追加列": function(event, can, msg, index, key, cmd, target) { + var table = target.parentNode.parentNode + var tr = target.parentNode + var index = can.page.Select(can, tr, "th,td", function(item, index) { + return item == target && index || undefined + })[0] + + can.page.Select(can, table, "tr", function(tr, index) { + can.page.Append(can, tr, [{type: index == 0? "th": "td", inner: " "}]) + }) }, }) Volcanos("onexport", {help: "导出数据", list: []}) diff --git a/proto.js b/proto.js index 21ad0e1c..3369f3a1 100644 --- a/proto.js +++ b/proto.js @@ -14,35 +14,66 @@ function shy(help, meta, list, cb) { // 封装函数 return cb; } function Volcanos(name, can, libs, cb, msg) { // 封装模块 - // 全局属性 - var list = arguments.callee.list || [], meta = arguments.callee.meta || { - create_time: new Date(), path: "/static/volcanos/", index: 1, cache: {}, - }; - - can = can || {}; - can._name = name; + // 全局缓存 + var list = arguments.callee.list || [], meta = arguments.callee.meta || {index: 1, cache: {}}; + arguments.callee.meta = meta, arguments.callee.list = list; // 定义原型 var id = 1, conf = {}, conf_cb = {}, sync = {}, cache = {}; - can[name] || list.push({_name: name, can: can, create_time: new Date()}) && (can.__proto__ = { - _create_time: new Date(), _name: name, _path: "", _help: "插件模块", load: function(name) { + can = can || {}, list.push(can) && (can.__proto__ = {_name: name, _help: "插件模块", _create_time: new Date(), _load: function(name) { if (meta.cache[name]) {var cache = meta.cache[name]; for (var i = 0; i < cache.length; i++) {var item = cache[i]; - if (item.can._name == can._name) {continue} - can[item._name] = item.can; + if (item._name == can._name) {continue} + can[item._name] = item; } return can } meta.cache[name] = [] for (var i = meta.index; i < list.length; i++) {var item = list[i]; - if (item.can._name == can._name || item.can._type == "local") {continue} - can[item._name] = item.can; + if (item._name == can._name || item._type == "local") {continue} + can[item._name] = item; meta.cache[name].push(item); } meta.index = i; return can }, + require: function(libs, cb) { + if (!libs || libs.length == 0) { + // 加载完成 + typeof cb == "function" && setTimeout(function() {cb(can)}, 10); + return + } + + if (can[libs[0]]) { + // 已经加载 + can.require(libs.slice(1), cb) + return + } + if (meta.cache[libs[0]]) { + // 缓存加载 + can._load(libs[0]), can.require(libs.slice(1), cb) + return + } + + if (libs[0].endsWith(".wasm")) {var go = new Go(); + // 加载汇编 + WebAssembly.instantiateStreaming(fetch(libs[0]), go.importObject).then((result) => { + go.argv = [can]; + go.run(result.instance); + can.require(libs.slice(1), cb); + }).catch((err) => { + console.error(err); + }); + return + } + + // 加载脚本 + can.Dream(document.body, libs[0].indexOf(".") == -1? libs[0]+".js": libs[0], function() { + can._load(libs[0]), can.require(libs.slice(1), cb); + }) + }, + ID: shy("生成器", function() {return id++}), Log: shy("日志器", function() {console.log(arguments)}), Conf: shy("配置器", function(key, value, cb) {if (key == undefined) {return conf} @@ -78,8 +109,7 @@ function Volcanos(name, can, libs, cb, msg) { // 封装模块 msg = event.msg = msg || event.msg || {}, msg.__proto__ = proto || { _create_time: can.base.Time(), _source: can, Log: shy("输出日志", function() {console.log(arguments)}), - Ids: function(index, key) { - var id = index; + Ids: function(index, key) {var id = index; msg && msg.id && (id = msg.id[index]) || msg && msg.name && (id = msg.name[index]); return id; }, @@ -96,6 +126,25 @@ function Volcanos(name, can, libs, cb, msg) { // 封装模块 for (var i = 0; i < arguments.length; i++) {msg.result.push(arguments[i])} return msg; }), + Push: function(key, value) {msg.append = msg.append || [] + if (typeof key == "object") { + value? can.core.List(value, function(item) { + msg.Push(item, key[item]||"") + }): can.core.Item(key, function(key, value) { + msg.Push(key, value||"") + }) + return + } + + for (var i = 0; i < msg.append.length; i++) { + if (msg.append[i] == key) { + break + } + } + if (i >= msg.append.length) {msg.append.push(key)} + msg[key] = msg[key] || [] + msg[key].push(""+value) + }, Copy: function(res) { res.result && (msg.result = res.result) res.append && (msg.append = res.append) && res.append.forEach(function(item) { @@ -128,21 +177,20 @@ function Volcanos(name, can, libs, cb, msg) { // 封装模块 return [name, ext, txt] }, }; - msg.event = event - return msg + return msg.event = event, msg }), Dream: shy("构造器", function(target, type, line, key) { if (type.endsWith(".css")) { var style = document.createElement("link"); style.rel = "stylesheet", style.type = "text/css"; - style.href = (type.startsWith("/")? "": (can._path||meta.path))+type + style.href = (type.startsWith("/")? "": Config.volcano)+type; style.onload = line; target.appendChild(style); return style } if (type.endsWith(".js")) { var script = document.createElement("script"); - script.src = (type.startsWith("/")? "": (can._path||meta.path))+type, + script.src = (type.startsWith("/")? "": Config.volcano)+type; script.onload = line; target.appendChild(script); return script @@ -181,11 +229,13 @@ function Volcanos(name, can, libs, cb, msg) { // 封装模块 }), Story: shy("存储器", function(type, meta, list) { }), - }), arguments.callee.meta = meta, arguments.callee.list = list; + }); - // 加载模块 - function next() { - libs && libs.length > 1? Volcanos(name, can, libs.slice(1), cb): typeof cb == "function" && setTimeout(function() {cb(can); if (can.target) { + can.require(libs, function() { + can.onimport && can.onimport._begin && can.onimport._begin(can) + typeof cb == "function" && cb(can); + if (can.target) { + // 初始化主模块 function run(event, msg, key, cb) { if (typeof cb == "function") { // 本地命令 @@ -199,41 +249,15 @@ function Volcanos(name, can, libs, cb, msg) { // 封装模块 can.core.Item(can.onaction, function(key, cb) {key.indexOf("on") == 0 && (can.target[key] = function(event) {cb(event, can)})}); // 注册action can.action && (can.action.innerHTML = ""), can.onaction && can.page.AppendAction(can, can.action, can.onaction.list, function(event, value, key) { - key? run(event, value, key, can.onaction[key]): run(event, msg, value, can.onaction[value]); + key? run(event, value, key, can.onaction[key]||can.onaction[value]): run(event, msg, value, can.onaction[value]); }) // 注册choice can.target.oncontextmenu = function(event) {can.user.carte(event, shy("", can.onchoice, can.onchoice.list, function(event, key, meta) { run(event, msg, key, can.onchoice[key] || can.onaction[key]); }), can), event.stopPropagation(), event.preventDefault()} - }}, 10); - } - if (libs && libs.length > 0) { - if (can[libs[0]]) { - // 重复加载 - next() - } else if (meta.cache[libs[0]]) { - // 缓存加载 - can.load(libs[0]), next() - } else { - // 加载脚本 - if (libs[0].endsWith(".wasm")) {var go = new Go(); - WebAssembly.instantiateStreaming(fetch(libs[0]), go.importObject).then((result) => { - go.argv = [can]; - go.run(result.instance); - next(); - }).catch((err) => { - console.error(err); - }); - } else { - can.Dream(document.body, libs[0].indexOf(".") == -1? libs[0]+".js": libs[0], function() { - can.load(libs[0]), next(); - }) - } } - } else { - // 独立模块 - next() - } + can.onimport && can.onimport._start && can.onimport._start(can) + }) return can } diff --git a/style.css b/style.css index 1907fe1d..5b033420 100644 --- a/style.css +++ b/style.css @@ -254,6 +254,49 @@ fieldset table td.select { background-color:red; } +fieldset div.code { + color:white; + font-size:14px; + font-family:monospace; + background-color:#272822; + white-space:pre; + padding:10px; + overflow:auto; + border:solid 3px green; + max-height:640px; +} +fieldset div.code span.red { + color:red; +} +fieldset div.code span.green { + color:green; +} + +fieldset .story { + border:solid 2px #f000; +} +fieldset .story:hover { + border:solid 2px red; +} + +fieldset ul.story li:hover { + border:solid 2px red; + cursor:pointer; +} + +fieldset code.story { + display:block; + color:white; + font-size:14px; + font-family:monospace; + background-color:#272822; + white-space:pre; + padding:10px; + overflow:auto; + border:solid 3px green; + max-height:640px; +} + fieldset div.stack:hover { background-color:red; } @@ -272,20 +315,25 @@ fieldset ul.stack:hover { border:solid 2px red; } -fieldset div.code { - color:white; - font-size:14px; - font-family:monospace; - background-color:#272822; - white-space:pre; - padding:10px; - overflow:auto; - border:solid 3px green; - max-height:640px; +fieldset td.over { + border:solid 2px red; } -fieldset div.code span.red { + +sup.more { color:red; } -fieldset div.code span.green { - color:green; + +fieldset.input { + z-index: 10000; + border:solid 2px yellow; +} +fieldset.input.date table tr:hover { + background-color:yellow; +} +fieldset.input.date table td:hover { + background-color:red; + cursor:pointer; +} +fieldset.input.date table td.now { + background-color:red; }