mirror of
https://shylinux.com/x/volcanos
synced 2025-04-25 16:58:06 +08:00
opt can
This commit is contained in:
parent
3fc7aba1b3
commit
55b49df60a
163
frame.js
163
frame.js
@ -3,9 +3,10 @@ Volcanos("onengine", {help: "搜索引擎", list: [], _init: function(can, meta,
|
|||||||
can.run = function(event, cmds, cb) { var msg = can.request(event); cmds = cmds||[]
|
can.run = function(event, cmds, cb) { var msg = can.request(event); cmds = cmds||[]
|
||||||
return (can.onengine[cmds[0]]||can.onengine._remote)(event, can, msg, can, cmds, cb)
|
return (can.onengine[cmds[0]]||can.onengine._remote)(event, can, msg, can, cmds, cb)
|
||||||
}
|
}
|
||||||
if (can.user.isExtension) { Volcanos.meta.args = JSON.parse(localStorage.getItem(ctx.ARGS))||{} }
|
if (can.user.isExtension) { Volcanos.meta.args = can.base.Obj(localStorage.getItem(ctx.ARGS), {}) }
|
||||||
|
|
||||||
can.core.Next(list, function(item, next) { item.type = chat.PANEL
|
can.core.Next(list, function(item, next) { item.type = chat.PANEL
|
||||||
can.onappend._init(can, item, item.list, function(panel) { panel.Conf(item)
|
can.onappend._init(can, can.base.Copy(item, can.core.Value(can._root, can.core.Keys(chat.RIVER, item.name))), item.list, function(panel) {
|
||||||
panel.run = function(event, cmds, cb) { var msg = panel.request(event); cmds = cmds||[]
|
panel.run = function(event, cmds, cb) { var msg = panel.request(event); cmds = cmds||[]
|
||||||
return (can.onengine[cmds[0]]||can.onengine._remote)(event, can, msg, panel, cmds, cb)
|
return (can.onengine[cmds[0]]||can.onengine._remote)(event, can, msg, panel, cmds, cb)
|
||||||
}, can[item.name] = panel, panel._root = can, panel._trans = panel.onaction && panel.onaction._trans||{}
|
}, can[item.name] = panel, panel._root = can, panel._trans = panel.onaction && panel.onaction._trans||{}
|
||||||
@ -13,15 +14,15 @@ Volcanos("onengine", {help: "搜索引擎", list: [], _init: function(can, meta,
|
|||||||
can.core.ItemCB(panel.onaction, function(key, cb) {
|
can.core.ItemCB(panel.onaction, function(key, cb) {
|
||||||
can.onengine.listen(can, key, function(msg) { can.core.CallFunc(cb, {can: panel, msg: msg}) })
|
can.onengine.listen(can, key, function(msg) { can.core.CallFunc(cb, {can: panel, msg: msg}) })
|
||||||
}), can.core.CallFunc([panel.onaction, "_init"], {can: panel, cb: next, target: panel._target})
|
}), can.core.CallFunc([panel.onaction, "_init"], {can: panel, cb: next, target: panel._target})
|
||||||
panel.Conf(can.core.Value(can._root, can.core.Keys(chat.RIVER, item.name)))
|
|
||||||
panel.Conf("style") && can.page.Modify(can, panel._target, {style: panel.Conf("style")})
|
can.page.Modify(can, panel._target, {style: panel.Conf(ctx.STYLE)})
|
||||||
}, target)
|
}, target)
|
||||||
}, function() { can.misc.Log(can.user.title(), ice.RUN, can)
|
}, function() { can.misc.Log(can.user.title(), ice.RUN, can)
|
||||||
can.require([can.volcano], null, function(can, name, sub) { can[name] = sub })
|
can.require([can.volcano], null, function(can, name, sub) { can[name] = sub })
|
||||||
can.onlayout.topic(can), can.onmotion._init(can, target), can.onkeymap._init(can)
|
can.ondaemon._init(can), can.onmotion._init(can, target), can.onkeymap._init(can)
|
||||||
can.ondaemon._init(can), can.onengine.signal(can, chat.ONMAIN, can.request())
|
can.onlayout.topic(can), can.onengine.signal(can, chat.ONMAIN, can.request())
|
||||||
can.base.isFunc(cb) && cb()
|
can.onmotion.float.auto(can, target), can.base.isFunc(cb) && cb()
|
||||||
}), can.onmotion.float.auto(can, document.body)
|
})
|
||||||
},
|
},
|
||||||
_search: function(event, can, msg, panel, cmds, cb) {
|
_search: function(event, can, msg, panel, cmds, cb) {
|
||||||
var sub, mod = can, fun = can, key = ""; can.core.List(cmds[1].split(ice.PT), function(value) {
|
var sub, mod = can, fun = can, key = ""; can.core.List(cmds[1].split(ice.PT), function(value) {
|
||||||
@ -31,27 +32,23 @@ Volcanos("onengine", {help: "搜索引擎", list: [], _init: function(can, meta,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return can.core.CallFunc(fun, {
|
return can.core.CallFunc(fun, {
|
||||||
"event": event, "can": sub, "msg": msg,
|
"event": event, "can": sub, "msg": msg, "cmds": cmds.slice(2), "cb": cb, "target": sub._target,
|
||||||
"button": key, "cmd": key, "arg": cmds.slice(2), "cmds": cmds.slice(2),
|
"button": key, "cmd": key, "arg": cmds.slice(2), "list": cmds.slice(2),
|
||||||
"list": cmds.slice(2), "cb": cb, "target": sub._target,
|
|
||||||
}, mod)
|
}, mod)
|
||||||
},
|
},
|
||||||
_engine: function(event, can, msg, panel, cmds, cb) { return false },
|
_engine: function(event, can, msg, panel, cmds, cb) { return false },
|
||||||
_plugin: function(event, can, msg, panel, cmds, cb) {
|
_plugin: function(event, can, msg, panel, cmds, cb) {
|
||||||
if (can.onengine.plugin.meta[cmds[0]]) {
|
|
||||||
can.core.CallFunc(can.onengine.plugin.meta[cmds[0]], {msg: msg, cmds: cmds.slice(1), cb: cb})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (cmds[0] == ctx.ACTION && cmds[1] == ice.RUN && can.onengine.plugin.meta[cmds[2]]) {
|
if (cmds[0] == ctx.ACTION && cmds[1] == ice.RUN && can.onengine.plugin.meta[cmds[2]]) {
|
||||||
can.core.CallFunc(can.onengine.plugin.meta[cmds[2]], {msg: msg, cmds: cmds.slice(3), cb: cb})
|
return can.core.CallFunc(can.onengine.plugin.meta[cmds[2]], {msg: msg, cmds: cmds.slice(3), cb: cb}), true
|
||||||
return true
|
}
|
||||||
|
if (can.onengine.plugin.meta[cmds[0]]) {
|
||||||
|
return can.core.CallFunc(can.onengine.plugin.meta[cmds[0]], {msg: msg, cmds: cmds.slice(1), cb: cb}), true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
_remote: function(event, can, msg, panel, cmds, cb) {
|
_remote: function(event, can, msg, panel, cmds, cb) {
|
||||||
if (panel.onengine._engine(event, can, msg, panel, cmds, cb)) { return }
|
if (panel.onengine._engine(event, can, msg, panel, cmds, cb)) { return }
|
||||||
if (panel.onengine._plugin(event, can, msg, panel, cmds, cb)) { return }
|
if (panel.onengine._plugin(event, can, msg, panel, cmds, cb)) { return }
|
||||||
can.onengine.signal(can, chat.ONREMOTE, can.request({}, {_follow: panel._follow, _msg: msg, _cmds: cmds}))
|
|
||||||
|
|
||||||
var key = can.core.Keys(panel._name, cmds.join(ice.FS))
|
var key = can.core.Keys(panel._name, cmds.join(ice.FS))
|
||||||
if (can.user.isLocalFile) { var msg = can.request(event); msg.Clear(ice.MSG_APPEND)
|
if (can.user.isLocalFile) { var msg = can.request(event); msg.Clear(ice.MSG_APPEND)
|
||||||
@ -60,22 +57,12 @@ Volcanos("onengine", {help: "搜索引擎", list: [], _init: function(can, meta,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var names = msg.Option("_names")||panel._names||((can.Conf("iceberg")||"/chat/")+panel._name)
|
var names = msg.Option("_names")||panel._names||((can.Conf("iceberg")||"/chat/")+panel._name)
|
||||||
|
can.onengine.signal(can, chat.ONREMOTE, can.request({}, {_follow: panel._follow, _msg: msg, _cmds: cmds}))
|
||||||
can.misc.Run(event, can, {names: names, daemon: can.core.Keys(can.ondaemon._list[0], msg._daemon)}, cmds, function(msg) {
|
can.misc.Run(event, can, {names: names, daemon: can.core.Keys(can.ondaemon._list[0], msg._daemon)}, cmds, function(msg) {
|
||||||
Volcanos.meta.pack[key] = msg, delete(msg._handle), delete(msg._toast)
|
Volcanos.meta.pack[key] = msg, delete(msg._handle), delete(msg._toast), can.base.isFunc(cb) && cb(msg)
|
||||||
// if (msg.result && msg.result[0] == ice.ErrWarn) { can.user.toast(can, msg.Result(), "", 10000); return }
|
|
||||||
can.base.isFunc(cb) && cb(msg)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
listen: shy("监听事件", {}, [], function(can, name, cb) {
|
|
||||||
arguments.callee.meta[name] = (arguments.callee.meta[name]||[]).concat(cb)
|
|
||||||
}),
|
|
||||||
signal: shy("触发事件", function(can, name, msg) { msg = msg||can.request()
|
|
||||||
name == chat.ONREMOTE? can.misc.Log("signal", name, msg.Option("_msg")): can.misc.Log("signal", name, msg)
|
|
||||||
can.core.List(can.onengine.listen.meta[name], function(cb) {
|
|
||||||
can.core.CallFunc(cb, {msg: msg, event: msg._event})
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
plugin: shy("添加插件", {}, [], function(can, name, command) { name = can.base.trimPrefix(name, "can.")
|
plugin: shy("添加插件", {}, [], function(can, name, command) { name = can.base.trimPrefix(name, "can.")
|
||||||
var type = html.TEXT; command.list = can.core.List(command.list, function(item) {
|
var type = html.TEXT; command.list = can.core.List(command.list, function(item) {
|
||||||
switch (typeof item) {
|
switch (typeof item) {
|
||||||
@ -89,20 +76,22 @@ Volcanos("onengine", {help: "搜索引擎", list: [], _init: function(can, meta,
|
|||||||
default: return {type: type, name: item}
|
default: return {type: type, name: item}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}), arguments.callee.meta[can.core.Keys("can", name)] = command
|
||||||
arguments.callee.meta[can.core.Keys("can", name)] = command
|
}),
|
||||||
|
listen: shy("监听事件", {}, [], function(can, name, cb) { arguments.callee.meta[name] = (arguments.callee.meta[name]||[]).concat(cb) }),
|
||||||
|
signal: shy("触发事件", function(can, name, msg) { msg = msg||can.request()
|
||||||
|
name == chat.ONREMOTE? can.misc.Log("signal", name, msg.Option("_msg")): can.misc.Log("signal", name, msg)
|
||||||
|
can.core.List(can.onengine.listen.meta[name], function(cb) { can.core.CallFunc(cb, {event: msg._event, msg: msg}) })
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
Volcanos("ondaemon", {help: "推荐引擎", list: [], _init: function(can, name) { if (can.user.isLocalFile) { return }
|
Volcanos("ondaemon", {help: "推荐引擎", list: [], _init: function(can, name) { if (can.user.isLocalFile) { return }
|
||||||
can.misc.WSS(can, {type: html.CHROME, name: can.misc.Search(can, "daemon")||name||""}, function(event, msg, cmd, arg) { if (!msg) { return }
|
can.misc.WSS(can, {type: html.CHROME, name: can.misc.Search(can, "daemon")||name||""}, function(event, msg, cmd, arg) { if (!msg) { return }
|
||||||
can.base.isFunc(can.ondaemon[cmd])? can.core.CallFunc(can.ondaemon[cmd], {
|
can.base.isFunc(can.ondaemon[cmd])? can.core.CallFunc(can.ondaemon[cmd], {
|
||||||
"can": can, "msg": msg, "cmd": cmd, "arg": arg, "cb": function() { msg.Reply() },
|
"can": can, "msg": msg, "cmd": cmd, "arg": arg, "cb": function() { msg.Reply() },
|
||||||
}): can.onengine._search({}, can, msg, can, ["_search", cmd].concat(arg), function() {
|
}): can.onengine._search({}, can, msg, can, ["_search", cmd].concat(arg), function() { msg.Reply() })
|
||||||
msg.Reply()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
can.onengine.listen(can, chat.ONSEARCH, function(msg, word) { var meta = can.onengine.plugin.meta
|
can.onengine.listen(can, chat.ONSEARCH, function(msg, word) { var meta = can.onengine.plugin.meta
|
||||||
if (word[0] != "*" && word[0] != ctx.COMMAND) { return }
|
if (word[0] != mdb.FOREACH && word[0] != ctx.COMMAND) { return }
|
||||||
var list = word[1] == ""? meta: meta[word[1]]? kit.Dict(word[1], meta[word[1]]): {}
|
var list = word[1] == ""? meta: meta[word[1]]? kit.Dict(word[1], meta[word[1]]): {}
|
||||||
can.core.Item(list, function(name, command) { name = can.base.trimPrefix(name, "can.")
|
can.core.Item(list, function(name, command) { name = can.base.trimPrefix(name, "can.")
|
||||||
can.core.List(msg.Option(ice.MSG_FIELDS).split(ice.FS), function(item) {
|
can.core.List(msg.Option(ice.MSG_FIELDS).split(ice.FS), function(item) {
|
||||||
@ -115,24 +104,18 @@ Volcanos("ondaemon", {help: "推荐引擎", list: [], _init: function(can, name)
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, _list: [""],
|
}, _list: [""],
|
||||||
pwd: function(can, msg, arg) {
|
pwd: function(can, msg, arg) { can.ondaemon._list[0] = arg[0] },
|
||||||
can.ondaemon._list[0] = arg[0]
|
|
||||||
},
|
|
||||||
grow: function(can, msg, arg) {
|
grow: function(can, msg, arg) {
|
||||||
var sub = can.ondaemon._list[msg.Option(ice.MSG_TARGET)]
|
var sub = can.ondaemon._list[msg.Option(ice.MSG_TARGET)]
|
||||||
sub.onimport._grow(sub, can.page.Color(arg.join("")))
|
sub.onimport._grow(sub, can.page.Color(arg.join("")))
|
||||||
},
|
},
|
||||||
toast: function(can, msg, arg) {
|
toast: function(can, msg, arg) { can.core.CallFunc(can.user.toast, {can: can, msg: msg, cmds: arg}) },
|
||||||
can.onmotion.float.add(can, chat.FLOAT, can.core.CallFunc(can.user.toast, {can: can, msg: msg, cmds: arg}))
|
confirm: function(can, msg, arg) { if (can.user.confirm(arg[0])) { msg.Echo(ice.TRUE) } },
|
||||||
},
|
|
||||||
confirm: function(can, msg, arg) {
|
|
||||||
if (can.user.confirm(arg[0])) { msg.Echo(ice.TRUE) }
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta, list, cb, target, field) {
|
Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta, list, cb, target, field) {
|
||||||
meta.name = (meta.name||"").split(ice.SP)[0].split(ice.PT).pop()
|
meta.name = (meta.name||"").split(ice.SP)[0].split(ice.PT).pop()
|
||||||
field = field||can.onappend.field(can, meta.type, meta, target).first
|
field = field||can.onappend.field(can, meta.type, meta, target).first
|
||||||
var legend = can.page.Select(can, field, ice.PT+html.LEGEND)[0]||can.page.Select(can, field, html.LEGEND)[0]
|
var legend = can.page.Select(can, field, html.LEGEND)[0]
|
||||||
var option = can.page.Select(can, field, html.FORM_OPTION)[0]
|
var option = can.page.Select(can, field, html.FORM_OPTION)[0]
|
||||||
var action = can.page.Select(can, field, html.DIV_ACTION)[0]
|
var action = can.page.Select(can, field, html.DIV_ACTION)[0]
|
||||||
var output = can.page.Select(can, field, html.DIV_OUTPUT)[0]
|
var output = can.page.Select(can, field, html.DIV_OUTPUT)[0]
|
||||||
@ -143,84 +126,70 @@ Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta,
|
|||||||
_inputs: {}, _outputs: [], _history: [],
|
_inputs: {}, _outputs: [], _history: [],
|
||||||
|
|
||||||
Status: function(key, value) {
|
Status: function(key, value) {
|
||||||
if (sub.base.isObject(key)) { return sub.core.Item(key, sub.Status), key }
|
if (can.base.isObject(key)) { return can.core.Item(key, sub.Status), key }
|
||||||
sub.page.Select(sub, status, [[[html.DIV, key], html.SPAN]], function(item) {
|
can.page.Select(can, status, [[[html.DIV, key], html.SPAN]], function(item) {
|
||||||
return value == undefined? (value = item.innerHTML): (item.innerHTML = value)
|
return value == undefined? (value = item.innerHTML): (item.innerHTML = value)
|
||||||
}); return value
|
}); return value
|
||||||
},
|
},
|
||||||
Action: function(key, value) { return sub.page.SelectArgs(sub, action, key, value)[0] },
|
Action: function(key, value) { return can.page.SelectArgs(can, action, key, value)[0] },
|
||||||
Option: function(key, value) { return sub.page.SelectArgs(sub, option, key, value)[0] },
|
Option: function(key, value) { return can.page.SelectArgs(can, option, key, value)[0] },
|
||||||
Update: function(event, cmds, cb, silent) { sub.onappend._output0(sub, sub.Conf(), event||{}, cmds||sub.Input(), cb, silent); return true },
|
Update: function(event, cmds, cb, silent) { sub.onappend._output0(sub, sub.Conf(), event||{}, cmds||sub.Input(), cb, silent); return true },
|
||||||
Input: function(cmds, silent) {
|
Input: function(cmds, silent) {
|
||||||
cmds = cmds && cmds.length > 0? cmds: sub.page.SelectArgs(sub, option, ""), cmds = can.base.trim(cmds)
|
cmds = cmds && cmds.length > 0? cmds: can.page.SelectArgs(can, option, ""), cmds = can.base.trim(cmds)
|
||||||
silent || cmds[0] == ctx.ACTION || sub.base.Eq(sub._history[sub._history.length-1], cmds) || sub._history.push(cmds)
|
silent || cmds[0] == ctx.ACTION || can.base.Eq(sub._history[sub._history.length-1], cmds) || sub._history.push(cmds)
|
||||||
return cmds
|
return cmds
|
||||||
},
|
},
|
||||||
Clone: function() { meta.args = sub.page.SelectArgs(sub, option, "")
|
Clone: function() { meta.args = can.page.SelectArgs(can, option, "")
|
||||||
can.onappend._init(can, meta, list, function(sub) { can.base.isFunc(cb) && cb(sub, true)
|
can.onappend._init(can, meta, list, function(sub) { can.base.isFunc(cb) && cb(sub, true)
|
||||||
can.core.Timer(10, function() { for (var k in sub._inputs) { can.onmotion.focus(can, sub._inputs[k]._target); break } })
|
can.core.Timer(10, function() { for (var k in sub._inputs) { can.onmotion.focus(can, sub._inputs[k]._target); break } })
|
||||||
}, target)
|
}, target)
|
||||||
},
|
},
|
||||||
}, list, function(sub) { sub.Conf(meta), meta.feature = sub.base.Obj(meta.feature, {})
|
}, list, function(sub) { sub.Conf(meta), meta.feature = can.base.Obj(meta.feature, {})
|
||||||
sub.page.ClassList.add(sub, field, meta.index? meta.index.split(ice.PT).pop(): meta.name)
|
can.page.ClassList.add(can, field, meta.index? meta.index.split(ice.PT).pop(): meta.name)
|
||||||
sub.page.ClassList.add(sub, field, meta.style||meta.feature.style||"")
|
can.page.ClassList.add(can, field, meta.style||meta.feature.style||"")
|
||||||
|
|
||||||
sub.page.Modify(sub, sub._legend, {onmouseenter: function(event) {
|
meta.inputs && sub.onappend._option(sub, meta, sub._option, meta.msg)
|
||||||
sub.user.carte(event, sub, sub.onaction, sub.onaction.list.concat([["所有 ->"].concat(can.core.Item(meta.feature._trans))], [cli.CLOSE]))
|
if (meta.msg) { var msg = sub.request(); msg.Copy(can.base.Obj(meta.msg)), sub.onappend._output(sub, msg, msg.Option(ice.MSG_DISPLAY)) }
|
||||||
}})
|
|
||||||
|
|
||||||
if (meta.msg) { var msg = sub.request(); msg.Copy(sub.base.Obj(meta.msg))
|
can.page.Modify(can, sub._legend, {onmouseenter: function(event) {
|
||||||
meta.inputs && sub.onappend._option(sub, meta, sub._option, true)
|
can.user.carte(event, sub, sub.onaction, sub.onaction.list.concat([["所有 ->"].concat(can.core.Item(meta.feature._trans))], [cli.CLOSE]))
|
||||||
sub.onappend._output(sub, msg, msg.Option(ice.MSG_DISPLAY))
|
}}), can.base.isFunc(cb) && cb(sub)
|
||||||
} else {
|
|
||||||
meta.inputs && sub.onappend._option(sub, meta, sub._option)
|
|
||||||
}
|
|
||||||
|
|
||||||
can.base.isFunc(cb) && cb(sub)
|
|
||||||
}); return sub
|
}); return sub
|
||||||
},
|
},
|
||||||
_option: function(can, meta, option, skip) { meta = meta||{}; var index = -1, args = can.base.Obj(meta.args||meta.arg||meta.opt, []), opts = can.base.Obj(meta.opts, {})
|
_option: function(can, meta, option, skip) { meta = meta||{}; var index = -1, args = can.base.Obj(meta.args||meta.arg||meta.opt, []), opts = can.base.Obj(meta.opts, {})
|
||||||
function add(item, next) { item.type != html.BUTTON && index++
|
function add(item, next) { item = can.base.isString(item)? {type: html.TEXT, name: item}: item, item.type != html.BUTTON && index++
|
||||||
return Volcanos(item.name, {_follow: can.core.Keys(can._follow, item.name),
|
return Volcanos(item.name, {_follow: can.core.Keys(can._follow, item.name),
|
||||||
_target: can.onappend.input(can, item, args[index]||opts[item.name], option||can._option),
|
_target: can.onappend.input(can, item, args[index]||opts[item.name], option||can._option),
|
||||||
_option: can._option, _action: can._action, _output: can._output, _status: can._status,
|
_option: can._option, _action: can._action, _output: can._output, _status: can._status,
|
||||||
Option: can.Option, Action: can.Action, Status: can.Status, CloneField: can.Clone,
|
Option: can.Option, Action: can.Action, Status: can.Status, CloneField: can.Clone,
|
||||||
CloneInput: function() { can.onmotion.focus(can, add(item)._target) },
|
CloneInput: function() { can.onmotion.focus(can, add(item)._target) },
|
||||||
}, [item.display||chat.PLUGIN_INPUT_JS], function(input) { input.Conf(item)
|
}, [item.display, chat.PLUGIN_INPUT_JS], function(input) { input.Conf(item)
|
||||||
input.run = function(event, cmds, cb, silent) { var msg = can.request(event)
|
input.run = function(event, cmds, cb, silent) { var msg = can.request(event)
|
||||||
if (msg.RunAction(event, can.core.Value(can, "_outputs.-1"), cmds)) { return }
|
if (msg.RunAction(event, can.core.Value(can, "_outputs.-1"), cmds)) { return }
|
||||||
if (msg.RunAction(event, input, cmds)) { return }
|
if (msg.RunAction(event, input, cmds)) { return }
|
||||||
return can.Update(event, can.Input(cmds, silent), cb, silent)
|
return can.Update(event, can.Input(cmds, silent), cb, silent)
|
||||||
}, can._inputs[item.name] = input, input.sup = can
|
}, can._inputs[item.name] = input, input.sup = can
|
||||||
|
|
||||||
can.core.ItemCB(input.onaction, function(key, cb) {
|
can.core.ItemCB(input.onaction, function(key, cb) { input._target[key] = function(event) { cb(event, input) } })
|
||||||
input._target[key] = function(event) { cb(event, input) }
|
can.core.ItemCB(item, function(key, cb) { input._target[key] = function(event) { cb(event, input) } })
|
||||||
}), skip? next(): can.core.CallFunc([input.onaction, "_init"], [input, item, [], next, input._target]);
|
skip? next(): can.core.CallFunc([input.onaction, "_init"], [input, item, next, input._target]);
|
||||||
can.core.ItemCB(item, function(key, cb) {
|
|
||||||
input._target[key] = function(event) { cb(event, input) }
|
|
||||||
});
|
|
||||||
(item.action||can.core.Value(meta, "feature.inputs")) && can.onappend.figure(input, item, input._target)
|
(item.action||can.core.Value(meta, "feature.inputs")) && can.onappend.figure(input, item, input._target)
|
||||||
})
|
})
|
||||||
}; can.core.Next(can.base.Obj(meta.inputs, can.core.Value(can, "onimport.list")).concat(meta.type == chat.FLOAT? [{type: html.BUTTON, name: cli.CLOSE}]: []), add)
|
}; can.core.Next(can.base.Obj(meta.inputs, can.core.Value(can, "onimport.list")).concat(meta.type == chat.FLOAT? [{type: html.BUTTON, name: cli.CLOSE}]: []), add)
|
||||||
},
|
},
|
||||||
_action: function(can, list, action, meta) { meta = meta||can.onaction, action = action||can._action, can.onmotion.clear(can, action)
|
_action: function(can, list, action, meta) { meta = meta||can.onaction, action = action||can._action, can.onmotion.clear(can, action)
|
||||||
can.core.List(can.base.Obj(list, can.core.Value(can, "onaction.list")), function(item) { if (item == undefined) { return } can.onappend.input(can, item == ""? /*空白*/ {type: html.SPACE}:
|
return can.core.List(can.base.Obj(list, can.core.Value(can, "onaction.list")), function(item) { if (item == undefined) { return } can.onappend.input(can, item == ""? /*空白*/ {type: html.SPACE}:
|
||||||
can.base.isString(item)? /*按键*/ {type: html.BUTTON, value: can.user.trans(can, item), onclick: function(event) {
|
can.base.isString(item)? /*按键*/ {type: html.BUTTON, value: can.user.trans(can, item), onclick: function(event) {
|
||||||
var cb = meta[item]||meta["_engine"]
|
var cb = meta[item]||meta["_engine"]; cb? can.core.CallFunc(cb, {event: event, can: can, button: item}): can.run(event, [ctx.ACTION, item].concat(can.sup.Input()))
|
||||||
cb? can.core.CallFunc(cb, {event: event, can: can, button: item}): can.run(event, [ctx.ACTION, item].concat(can.sup.Input()))
|
|
||||||
|
|
||||||
}}: item.length > 0? /*列表*/ {type: html.SELECT, name: item[0], values: item.slice(1), onchange: function(event) {
|
}}: item.length > 0? /*列表*/ {type: html.SELECT, name: item[0], values: item.slice(1), onchange: function(event) {
|
||||||
var which = item[event.target.selectedIndex+1]
|
var which = item[event.target.selectedIndex+1]
|
||||||
can.core.CallFunc(meta[which], [event, can, which])
|
can.core.CallFunc(meta[which], [event, can, which])
|
||||||
can.core.CallFunc(meta[item[0]], [event, can, item[0], which])
|
can.core.CallFunc(meta[item[0]], [event, can, item[0], which])
|
||||||
|
|
||||||
}}: /*其它*/ item
|
}}: /*其它*/ item, "", action)}), meta
|
||||||
, "", action)})
|
|
||||||
return meta
|
|
||||||
},
|
},
|
||||||
_output0: function(can, meta, event, cmds, cb, silent) { var msg = can.request(event)
|
_output0: function(can, meta, event, cmds, cb, silent) { var msg = can.request(event); if (msg.RunAction(event, can, cmds)) { return }
|
||||||
if (msg.RunAction(event, can, cmds)) { return }
|
|
||||||
|
|
||||||
if (msg.Option(ice.MSG_HANDLE) != ice.TRUE && cmds && cmds[0] == ctx.ACTION && meta.feature[cmds[1]]) { can.request(event, {action: cmds[1]})
|
if (msg.Option(ice.MSG_HANDLE) != ice.TRUE && cmds && cmds[0] == ctx.ACTION && meta.feature[cmds[1]]) { can.request(event, {action: cmds[1]})
|
||||||
return can.user.input(event, can, meta.feature[cmds[1]], function(ev, button, data, list, args) { var msg = can.request(event, {_handle: ice.TRUE}, can.Option())
|
return can.user.input(event, can, meta.feature[cmds[1]], function(ev, button, data, list, args) { var msg = can.request(event, {_handle: ice.TRUE}, can.Option())
|
||||||
can.Update(event, cmds.slice(0, 2).concat(args), function(msg) { can.Update({}, can.Input(), cb) }, true)
|
can.Update(event, cmds.slice(0, 2).concat(args), function(msg) { can.Update({}, can.Input(), cb) }, true)
|
||||||
@ -233,32 +202,28 @@ Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msg.Option("_toast")) { var toast = can.user.toast(can, msg.Option("_toast"), "", -1) }
|
if (msg.Option("_toast")) { var toast = can.user.toast(can, msg.Option("_toast"), "", -1) }
|
||||||
return can.run(event, cmds, function(msg) { var sub = can.core.Value(can, "_outputs.-1")||{}; can._msg = msg, sub._msg = msg
|
return can.run(event, cmds, function(msg) { var sub = can.core.Value(can, "_outputs.-1")||{}; can._msg = msg, sub._msg = msg, toast && toast.close()
|
||||||
toast && toast.close()
|
|
||||||
var process = msg._can == can || msg._can == sub
|
|
||||||
if (can.base.isFunc(cb)) { can.core.CallFunc(cb, {can: can, msg: msg}); return }
|
if (can.base.isFunc(cb)) { can.core.CallFunc(cb, {can: can, msg: msg}); return }
|
||||||
|
var process = msg._can == can || msg._can == sub
|
||||||
if (process && can.core.CallFunc([sub, "onimport._process"], {can: sub, msg: msg})) { return }
|
if (process && can.core.CallFunc([sub, "onimport._process"], {can: sub, msg: msg})) { return }
|
||||||
if (process && can.core.CallFunc([can, "onimport._process"], {can: can, msg: msg})) { return }
|
if (process && can.core.CallFunc([can, "onimport._process"], {can: can, msg: msg})) { return }
|
||||||
if (silent) { return }
|
!silent && can.onappend._output(can, msg, msg.Option(ice.MSG_DISPLAY)||meta.display||meta.feature.display)
|
||||||
|
|
||||||
can.onappend._output(can, msg, msg.Option(ice.MSG_DISPLAY)||meta.display||meta.feature.display)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_output: function(can, msg, display, output) { display = display||chat.PLUGIN_TABLE_JS, output = output||can._output
|
_output: function(can, msg, display, output) { display = display||chat.PLUGIN_TABLE_JS, output = output||can._output
|
||||||
Volcanos(display, {_follow: can.core.Keys(can._follow, display), _display: display, _target: output, _fields: can._target,
|
Volcanos(display, {_follow: can.core.Keys(can._follow, display), _display: display, _target: output, _fields: can._target,
|
||||||
_option: can._option, _action: can._action, _output: can._output, _status: can._status, _legend: can._legend,
|
_option: can._option, _action: can._action, _output: can._output, _status: can._status, _legend: can._legend, _inputs: {},
|
||||||
Update: can.Update, Option: can.Option, Action: can.Action, Status: can.Status,
|
Update: can.Update, Option: can.Option, Action: can.Action, Status: can.Status,
|
||||||
_inputs: {},
|
|
||||||
}, [display, chat.PLUGIN_TABLE_JS], function(table) { table.Conf(can.Conf())
|
}, [display, chat.PLUGIN_TABLE_JS], function(table) { table.Conf(can.Conf())
|
||||||
table.run = function(event, cmds, cb, silent) { var msg = can.request(event)
|
table.run = function(event, cmds, cb, silent) { var msg = can.request(event)
|
||||||
if (msg.RunAction(event, table, cmds)) { return }
|
if (msg.RunAction(event, table, cmds)) { return }
|
||||||
return can.Update(event, can.Input(cmds, silent), cb, silent)
|
return can.Update(event, can.Input(cmds, silent), cb, silent)
|
||||||
}, can._outputs.push(table), table.sup = can, table._msg = msg
|
}, can._outputs.push(table), table.sup = can, table._msg = msg
|
||||||
|
|
||||||
if (msg.result && msg.result[0] == "can.code.inner.plugin" && table.onimport && table.onimport.list.length > 0) {
|
if (can.Conf(ctx.INDEX) == "can.code.inner.plugin" && table.onimport && table.onimport.list.length > 0) {
|
||||||
can.onmotion.clear(can, can._option)
|
can.onmotion.clear(can, can._option), can.onappend._option(can, {inputs: table.onimport.list})
|
||||||
can.onappend._option(can, {inputs: table.onimport.list, args: msg.result.slice(1)})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table.onimport && can.core.CallFunc(table.onimport._init, {can: table, msg: msg, list: msg.result||msg.append||[], cb: function(msg) {
|
table.onimport && can.core.CallFunc(table.onimport._init, {can: table, msg: msg, list: msg.result||msg.append||[], cb: function(msg) {
|
||||||
table.onappend._action(table, msg.Option(ice.MSG_ACTION)||can.Conf(ice.MSG_ACTION))
|
table.onappend._action(table, msg.Option(ice.MSG_ACTION)||can.Conf(ice.MSG_ACTION))
|
||||||
table.onappend._status(table, msg.Option(ice.MSG_STATUS))
|
table.onappend._status(table, msg.Option(ice.MSG_STATUS))
|
||||||
@ -266,7 +231,7 @@ Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta,
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
_status: function(can, list, status) { status = status||can._status, can.onmotion.clear(can, status)
|
_status: function(can, list, status) { status = status||can._status, can.onmotion.clear(can, status)
|
||||||
can.core.List(can.base.Obj(list, can.core.Value(can, "onexport.list")), function(item) { item = can.base.isObject(item)? item: {name: item}
|
can.core.List(can.base.Obj(list, can.core.Value(can, [chat.ONEXPORT, mdb.LIST])), function(item) { item = can.base.isObject(item)? item: {name: item}
|
||||||
can.page.Append(can, status, [{view: can.base.join([html.ITEM, item.name]), title: item.name, list: [
|
can.page.Append(can, status, [{view: can.base.join([html.ITEM, item.name]), title: item.name, list: [
|
||||||
{text: [item.name, html.LABEL]}, {text: [": ", html.LABEL]}, {text: [(item.value||"")+"", html.SPAN, item.name]},
|
{text: [item.name, html.LABEL]}, {text: [": ", html.LABEL]}, {text: [(item.value||"")+"", html.SPAN, item.name]},
|
||||||
], }])
|
], }])
|
||||||
@ -275,7 +240,7 @@ Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta,
|
|||||||
|
|
||||||
tabs: function(can, list, cb, cbs, action) { action = action||can._action
|
tabs: function(can, list, cb, cbs, action) { action = action||can._action
|
||||||
return can.page.Append(can, action, can.core.List(list, function(meta) {
|
return can.page.Append(can, action, can.core.List(list, function(meta) {
|
||||||
return {text: [meta.name, html.DIV, chat.TABS], title: meta.text, onclick: function(event) {
|
return {text: [meta.name, html.DIV, html.TABS], title: meta.text, onclick: function(event) {
|
||||||
can.base.isFunc(cb) && cb(event, meta)
|
can.base.isFunc(cb) && cb(event, meta)
|
||||||
}, _init: function(item) { const OVER = "over"
|
}, _init: function(item) { const OVER = "over"
|
||||||
function close(item) { var next = item.nextSibling || item.previousSibling
|
function close(item) { var next = item.nextSibling || item.previousSibling
|
||||||
@ -287,11 +252,11 @@ Volcanos("onappend", {help: "渲染引擎", list: [], _init: function(can, meta,
|
|||||||
can.user.carte(event, can, kit.Dict(
|
can.user.carte(event, can, kit.Dict(
|
||||||
"close tab", function(event) { close(item) },
|
"close tab", function(event) { close(item) },
|
||||||
"close other", function(event) {
|
"close other", function(event) {
|
||||||
can.page.Select(can, action, chat.DIV_TABS, function(_item) {
|
can.page.Select(can, action, html.DIV_TABS, function(_item) {
|
||||||
_item == item || close(_item)
|
_item == item || close(_item)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"close all", function(event) { can.page.Select(can, action, chat.DIV_TABS, close) },
|
"close all", function(event) { can.page.Select(can, action, html.DIV_TABS, close) },
|
||||||
), ["close tab", "close other", "close all"])
|
), ["close tab", "close other", "close all"])
|
||||||
},
|
},
|
||||||
ondragstart: function(event) { var target = event.target; target.click()
|
ondragstart: function(event) { var target = event.target; target.click()
|
||||||
|
@ -17,6 +17,8 @@ Volcanos("core", {help: "数据结构",
|
|||||||
if (data == undefined) { return }
|
if (data == undefined) { return }
|
||||||
if (key == undefined) { return data }
|
if (key == undefined) { return data }
|
||||||
|
|
||||||
|
if (typeof key == lang.OBJECT && key.length > 0) { key = key.join(ice.PT) }
|
||||||
|
|
||||||
if (typeof key == lang.OBJECT) { for (var k in key) {
|
if (typeof key == lang.OBJECT) { for (var k in key) {
|
||||||
arguments.callee.call(this, data, k, key[k])
|
arguments.callee.call(this, data, k, key[k])
|
||||||
}; return data }
|
}; return data }
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
Volcanos("misc", {help: "通信协议", Message: function(event, can) { var msg = {}
|
Volcanos("misc", {help: "通信协议", Message: function(event, can) { var msg = {}
|
||||||
var proto = {_event: event, _can: can,
|
var proto = {_event: event, _can: can,
|
||||||
RunAction: function(event, sub, cmds) { var msg = can.request(event)
|
RunAction: function(event, sub, cmds, meta) { var msg = can.request(event); meta = meta || sub&&sub.onaction || {}
|
||||||
if (msg.Option(ice.MSG_HANDLE) == ice.TRUE) { return }
|
if (msg.Option(ice.MSG_HANDLE) == ice.TRUE) { return }
|
||||||
if (cmds && cmds[0] == ctx.ACTION && sub && can.base.isFunc(sub.onaction[cmds[1]])) {
|
if (cmds && cmds[0] == ctx.ACTION && can.base.isFunc(meta[cmds[1]])) {
|
||||||
return msg.Option(ice.MSG_HANDLE, ice.TRUE), can.core.CallFunc(sub.onaction[cmds[1]], {event: event, can: sub, msg: msg, button: cmds[1], cmd: cmds[1]}), true
|
return msg.Option(ice.MSG_HANDLE, ice.TRUE), can.core.CallFunc(meta[cmds[1]], {event: event, can: sub, msg: msg, button: cmds[1], cmd: cmds[1]}), true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Volcanos({name: "chat", panels: [
|
Volcanos({name: "chat", panels: [
|
||||||
{name: "Header", help: "标题栏", pos: chat.HEAD, state: ["time", "usernick", "avatar"]},
|
{name: "Header", help: "标题栏", pos: chat.HEAD, state: ["time", "usernick", "avatar"]},
|
||||||
{name: "River", help: "群聊组", pos: chat.LEFT, action: ["create", "refresh"]},
|
{name: "River", help: "群聊组", pos: html.LEFT, action: ["create", "refresh"]},
|
||||||
{name: "Action", help: "工作台", pos: chat.MAIN},
|
{name: "Action", help: "工作台", pos: chat.MAIN},
|
||||||
{name: "Footer", help: "状态条", pos: chat.FOOT, state: ["ncmd"]},
|
{name: "Footer", help: "状态条", pos: chat.FOOT, state: ["ncmd"]},
|
||||||
{name: "Search", help: "搜索框", pos: chat.AUTO},
|
{name: "Search", help: "搜索框", pos: chat.AUTO},
|
||||||
|
@ -23,9 +23,9 @@ Volcanos("onimport", {help: "导入数据", list: [], _init: function(can, msg)
|
|||||||
meta.id && (sub._option.dataset = sub._option.dataset||{}, sub._option.dataset.id = meta.id)
|
meta.id && (sub._option.dataset = sub._option.dataset||{}, sub._option.dataset.id = meta.id)
|
||||||
|
|
||||||
can.page.Modify(can, sub._output, {style: kit.Dict(html.MAX_WIDTH, meta.width)})
|
can.page.Modify(can, sub._output, {style: kit.Dict(html.MAX_WIDTH, meta.width)})
|
||||||
can.page.Append(can, can._action, [{view: [chat.TABS, html.DIV, meta.name], onclick: function(event) {
|
can.page.Append(can, can._action, [{view: [html.TABS, html.DIV, meta.name], onclick: function(event) {
|
||||||
can.onmotion.select(can, can._output, html.FIELDSET_PLUGIN, sub._target)
|
can.onmotion.select(can, can._output, html.FIELDSET_PLUGIN, sub._target)
|
||||||
can.onmotion.select(can, can._action, chat.DIV_TABS, event.target)
|
can.onmotion.select(can, can._action, html.DIV_TABS, event.target)
|
||||||
}, onmouseenter: sub._legend.onmouseenter}])
|
}, onmouseenter: sub._legend.onmouseenter}])
|
||||||
},
|
},
|
||||||
_menu: function(can, msg) { if (can.user.mod.isPod||can.user.isMobile) { return }
|
_menu: function(can, msg) { if (can.user.mod.isPod||can.user.isMobile) { return }
|
||||||
@ -154,7 +154,7 @@ Volcanos("onaction", {help: "交互操作", list: [], _init: function(can, cb, t
|
|||||||
|
|
||||||
if (button == "tabs") {
|
if (button == "tabs") {
|
||||||
can.onmotion.select(can, can._output, html.FIELDSET_PLUGIN, 0)
|
can.onmotion.select(can, can._output, html.FIELDSET_PLUGIN, 0)
|
||||||
can.onmotion.select(can, can._action, chat.DIV_TABS, 0)
|
can.onmotion.select(can, can._action, html.DIV_TABS, 0)
|
||||||
} else if (button == "free") {
|
} else if (button == "free") {
|
||||||
can.page.Select(can, can._target, [[html.DIV_OUTPUT, html.FIELDSET_PLUGIN]], function(item, index) {
|
can.page.Select(can, can._target, [[html.DIV_OUTPUT, html.FIELDSET_PLUGIN]], function(item, index) {
|
||||||
can.page.Modify(can, item, {style: {left: 40*index, top: 40*index}})
|
can.page.Modify(can, item, {style: {left: 40*index, top: 40*index}})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Volcanos("onaction", {help: "控件交互", list: [], _init: function(can, meta, list, cb, target) {
|
Volcanos("onaction", {help: "控件交互", list: [], _init: function(can, meta, cb, target) {
|
||||||
can.base.isFunc(cb) && cb(); switch (meta.type) {
|
can.base.isFunc(cb) && cb(); switch (meta.type) {
|
||||||
case html.SELECT: meta.value && (target.value = meta.value); break
|
case html.SELECT: meta.value && (target.value = meta.value); break
|
||||||
case html.BUTTON: meta.action == ice.AUTO && target.click(); break
|
case html.BUTTON: meta.action == ice.AUTO && target.click(); break
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
fieldset.inner>div.action {
|
fieldset.inner>div.action {
|
||||||
float:none; display:block;
|
float:none; display:block;
|
||||||
height:26px; overflow:auto;
|
overflow:auto;
|
||||||
}
|
}
|
||||||
fieldset.inner>div.action div.tabs {
|
fieldset.inner>div.action div.tabs {
|
||||||
border:solid 2px red; padding:2px;
|
border:solid 2px red; padding:2px;
|
||||||
|
@ -146,7 +146,7 @@ Volcanos("onimport", {help: "导入数据", _init: function(can, msg, cb, target
|
|||||||
can.onmotion.clear(can, target)
|
can.onmotion.clear(can, target)
|
||||||
if (msg.Option("_process") == "_field") {
|
if (msg.Option("_process") == "_field") {
|
||||||
msg.Table(function(meta) { meta.display = msg.Option("_display")
|
msg.Table(function(meta) { meta.display = msg.Option("_display")
|
||||||
// delete(Volcanos.meta.cache[meta.display])
|
delete(Volcanos.meta.cache[meta.display])
|
||||||
can.onimport.plugin(can, meta, target, function(sub) {
|
can.onimport.plugin(can, meta, target, function(sub) {
|
||||||
can.onmotion.focus(can, can.page.Select(can, sub._option, html.OPTION_ARGS)[0])
|
can.onmotion.focus(can, can.page.Select(can, sub._option, html.OPTION_ARGS)[0])
|
||||||
width && sub.ConfWidth(width)
|
width && sub.ConfWidth(width)
|
||||||
@ -215,7 +215,7 @@ Volcanos("onsyntax", {help: "语法高亮", list: ["keyword", "prefix", "line"],
|
|||||||
var p = cache_data[can.file]; p && (can.current = p.current, can.max = p.max)
|
var p = cache_data[can.file]; p && (can.current = p.current, can.max = p.max)
|
||||||
can.page.Modify(can, can.ui.profile, {style: {display: p? p.profile_display: html.NONE}})
|
can.page.Modify(can, can.ui.profile, {style: {display: p? p.profile_display: html.NONE}})
|
||||||
can.page.Modify(can, can.ui.display, {style: {display: p? p.display_display: html.NONE}})
|
can.page.Modify(can, can.ui.display, {style: {display: p? p.display_display: html.NONE}})
|
||||||
can.onmotion.select(can, can._action, chat.DIV_TABS, msg._tab)
|
can.onmotion.select(can, can._action, html.DIV_TABS, msg._tab)
|
||||||
can.onmotion.delay(can, function() { can.onimport.layout(can)
|
can.onmotion.delay(can, function() { can.onimport.layout(can)
|
||||||
msg.Option(ctx.INDEX) && can.onmotion.focus(can, can.page.Select(can, can.ui.content, html.OPTION_ARGS)[0])
|
msg.Option(ctx.INDEX) && can.onmotion.focus(can, can.page.Select(can, can.ui.content, html.OPTION_ARGS)[0])
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
fieldset.vimer>div.output input.current {
|
fieldset.vimer>div.output input.current {
|
||||||
background-color:#00000000; color:#00000000;
|
background-color:#00000000; color:#00000000;
|
||||||
font-size:1.2em; font-family:monospace;
|
font-size:1em; font-family:monospace;
|
||||||
position:absolute; left:0;
|
position:absolute; left:0;
|
||||||
margin:0; margin-top:-2px;
|
margin:0; margin-top:-2px;
|
||||||
padding:0; padding-left:9px;
|
padding:0; padding-left:9px;
|
||||||
|
82
proto.js
82
proto.js
@ -124,32 +124,29 @@ var wiki = {
|
|||||||
H3: "h3.story",
|
H3: "h3.story",
|
||||||
DIV_PAGE: "div.page",
|
DIV_PAGE: "div.page",
|
||||||
}
|
}
|
||||||
var chat = {ONIMPORT: "onimport", ONACTION: "onaction", ONKEYMAP: "onkeymap", ONEXPORT: "onexport",
|
var chat = {
|
||||||
LIB: "lib", PAGE: "page", PANEL: "panel", PLUGIN: "plugin", OUTPUT: "output", INPUT: "input", UPLOAD: "upload",
|
LIB: "lib", PAGE: "page", PANEL: "panel", PLUGIN: "plugin", OUTPUT: "output", STORY: "story", FLOAT: "float",
|
||||||
STORY: "story", FLOAT: "float", CONTEXTS: "contexts", CARTE: "carte", TOAST: "toast",
|
TOAST: "toast", CARTE: "carte", INPUT: "input", UPLOAD: "upload", CONTEXTS: "contexts",
|
||||||
LEGNED: "legend", OPTION: "option", ACTION: "action", OUTPUT: "output", STATUS: "status",
|
LEGNED: "legend", OPTION: "option", ACTION: "action", OUTPUT: "output", STATUS: "status",
|
||||||
LAYOUT: "layout", PROJECT: "project", CONTENT: "content", DISPLAY: "display", PROFILE: "profile",
|
LAYOUT: "layout", PROJECT: "project", CONTENT: "content", DISPLAY: "display", PROFILE: "profile",
|
||||||
|
ONIMPORT: "onimport", ONACTION: "onaction", ONKEYMAP: "onkeymap", ONEXPORT: "onexport",
|
||||||
|
|
||||||
TITLE: "title", TOPIC: "topic", BLACK: "black", WHITE: "white", PRINT: "print",
|
TITLE: "title", TOPIC: "topic", BLACK: "black", WHITE: "white", PRINT: "print",
|
||||||
SHARE: "share", RIVER: "river", STORM: "storm", FIELD: "field", TOAST: "toast",
|
SHARE: "share", RIVER: "river", STORM: "storm", FIELD: "field",
|
||||||
PUBLIC: "public", PROTECTED: "protected", PRIVATE: "private",
|
PUBLIC: "public", PROTECTED: "protected", PRIVATE: "private",
|
||||||
USER: "user", TOOL: "tool", NODE: "node",
|
USER: "user", TOOL: "tool", NODE: "node",
|
||||||
|
|
||||||
AGENT: "agent", CHECK: "check", GRANT: "grant",
|
AGENT: "agent", CHECK: "check", GRANT: "grant",
|
||||||
STATE: "state", MENUS: "menus", TRANS: "trans",
|
STATE: "state", MENUS: "menus", TRANS: "trans",
|
||||||
|
SSO: "sso",
|
||||||
|
|
||||||
ONMAIN: "onmain", ONLOGIN: "onlogin", ONSEARCH: "onsearch",
|
ONMAIN: "onmain", ONLOGIN: "onlogin", ONSEARCH: "onsearch",
|
||||||
ONSIZE: "onsize", ONTOAST: "ontoast", ONREMOTE: "onremote",
|
ONSIZE: "onsize", ONTOAST: "ontoast", ONREMOTE: "onremote",
|
||||||
ONKEYDOWN: "onkeydown",
|
ONKEYDOWN: "onkeydown",
|
||||||
|
|
||||||
HEAD: "head", LEFT: "left", MAIN: "main", AUTO: "auto", HIDE: "hide", FOOT: "foot",
|
HEAD: "head", LEFT: "left", MAIN: "main", AUTO: "auto", HIDE: "hide", FOOT: "foot",
|
||||||
SCROLL: "scroll", LEFT: "left", TOP: "top", RIGHT: "right", BOTTOM: "bottom",
|
|
||||||
HEADER: "header", FOOTER: "footer",
|
HEADER: "header", FOOTER: "footer",
|
||||||
|
|
||||||
TABS: "tabs", DIV_TABS: "div.tabs",
|
|
||||||
|
|
||||||
SSO: "sso",
|
|
||||||
|
|
||||||
PLUGIN_STATE_JS: "/plugin/state.js",
|
PLUGIN_STATE_JS: "/plugin/state.js",
|
||||||
PLUGIN_INPUT_JS: "/plugin/input.js",
|
PLUGIN_INPUT_JS: "/plugin/input.js",
|
||||||
PLUGIN_TABLE_JS: "/plugin/table.js",
|
PLUGIN_TABLE_JS: "/plugin/table.js",
|
||||||
@ -180,13 +177,13 @@ var chat = {ONIMPORT: "onimport", ONACTION: "onaction", ONKEYMAP: "onkeymap", ON
|
|||||||
"/plugin/input/province.js",
|
"/plugin/input/province.js",
|
||||||
],
|
],
|
||||||
ACTION_LAYOUT_FMT: `
|
ACTION_LAYOUT_FMT: `
|
||||||
fieldset.Action.grid>div.output fieldset.plugin {
|
fieldset.Action.grid>div.output fieldset.plugin {
|
||||||
width:_width; height:_height;
|
width:_width; height:_height;
|
||||||
}
|
}
|
||||||
fieldset.Action.grid>div.output fieldset.plugin>div.output {
|
fieldset.Action.grid>div.output fieldset.plugin>div.output {
|
||||||
width:_width; height:_height;
|
width:_width; height:_height;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
var team = {
|
var team = {
|
||||||
TASK: "task", PLAN: "plan",
|
TASK: "task", PLAN: "plan",
|
||||||
@ -210,30 +207,29 @@ var html = {
|
|||||||
|
|
||||||
OPTION_ARGS: "select.args,input.args,textarea.args",
|
OPTION_ARGS: "select.args,input.args,textarea.args",
|
||||||
INPUT_ARGS: "input.args,textarea.args",
|
INPUT_ARGS: "input.args,textarea.args",
|
||||||
DIV_ITEM: "div.item", DIV_FLOAT: "div.float",
|
|
||||||
|
|
||||||
INPUT_BUTTON: "input[type=button]",
|
INPUT_BUTTON: "input[type=button]",
|
||||||
|
|
||||||
UPLOAD: "upload", USERNAME: "username", PASSWORD: "password",
|
UPLOAD: "upload", USERNAME: "username", PASSWORD: "password",
|
||||||
INPUT: "input", TEXT: "text", TEXTAREA: "textarea", SELECT: "select", BUTTON: "button",
|
INPUT: "input", TEXT: "text", TEXTAREA: "textarea", SELECT: "select", BUTTON: "button",
|
||||||
FORM: "form", FILE: "file", SPACE: "space", CLICK: "click", SUBMIT: "submit", CANCEL: "cancel",
|
FORM: "form", FILE: "file", SPACE: "space", CLICK: "click", SUBMIT: "submit", CANCEL: "cancel",
|
||||||
DIV: "div", IMG: "img", CODE: "code", SPAN: "span", VIDEO: "video",
|
DIV: "div", IMG: "img", CODE: "code", SPAN: "span", VIDEO: "video",
|
||||||
TABLE: "table", TR: "tr", TH: "th", TD: "td", BR: "br", UL: "ul", LI: "li",
|
TABLE: "table", TR: "tr", TH: "th", TD: "td", BR: "br", UL: "ul", LI: "li",
|
||||||
A: "a", LABEL: "label", INNER: "inner", TITLE: "title",
|
A: "a", LABEL: "label", INNER: "inner", TITLE: "title",
|
||||||
|
H1: "h1", H2: "h2", H3: "h3",
|
||||||
|
|
||||||
CLASS: "class", FLOAT: "float", CLEAR: "clear", BOTH: "both",
|
CLASS: "class", FLOAT: "float", CLEAR: "clear", BOTH: "both",
|
||||||
BACKGROUND: "background", SELECT: "select", HIDDEN: "hidden",
|
BACKGROUND: "background", SELECT: "select", HIDDEN: "hidden",
|
||||||
DISPLAY: "display", BLOCK: "block", NONE: "none",
|
DISPLAY: "display", BLOCK: "block", NONE: "none", FIXED: "fixed",
|
||||||
STROKE_WIDTH: "stroke-width", STROKE: "stroke", FILL: "fill", FONT_SIZE: "font-size", MONOSPACE: "monospace",
|
STROKE_WIDTH: "stroke-width", STROKE: "stroke", FILL: "fill", FONT_SIZE: "font-size", MONOSPACE: "monospace",
|
||||||
SCROLL: "scroll", HEIGHT: "height", WIDTH: "width", LEFT: "left", TOP: "top", RIGHT: "right", BOTTOM: "bottom",
|
SCROLL: "scroll", HEIGHT: "height", WIDTH: "width", LEFT: "left", TOP: "top", RIGHT: "right", BOTTOM: "bottom",
|
||||||
MAX_HEIGHT: "max-height", MAX_WIDTH: "max-width", MARGIN_X: "margin-x", MARGIN_Y: "margin-y",
|
MAX_HEIGHT: "max-height", MAX_WIDTH: "max-width", MARGIN_X: "margin-x", MARGIN_Y: "margin-y",
|
||||||
PLUGIN_MARGIN: 10, ACTION_HEIGHT: 27, ACTION_MARGIN: 200,
|
PLUGIN_MARGIN: 10, ACTION_HEIGHT: 29, ACTION_MARGIN: 200,
|
||||||
|
|
||||||
FIXED: "fixed",
|
|
||||||
|
|
||||||
WSS: "wss", SVG: "svg", CANVAS: "canvas", IFRAME: "iframe", CHROME: "chrome",
|
WSS: "wss", SVG: "svg", CANVAS: "canvas", IFRAME: "iframe", CHROME: "chrome",
|
||||||
LIST: "list", ITEM: "item", MENU: "menu", NODE: "node",
|
LIST: "list", ITEM: "item", MENU: "menu", NODE: "node",
|
||||||
|
DIV_ITEM: "div.item", DIV_FLOAT: "div.float",
|
||||||
|
TABS: "tabs", DIV_TABS: "div.tabs",
|
||||||
HIDE: "hide", SHOW: "show",
|
HIDE: "hide", SHOW: "show",
|
||||||
H1: "h1", H2: "h2", H3: "h3",
|
|
||||||
}
|
}
|
||||||
var lang = {
|
var lang = {
|
||||||
UNDEFINED: "undefined",
|
UNDEFINED: "undefined",
|
||||||
@ -243,14 +239,12 @@ var lang = {
|
|||||||
}
|
}
|
||||||
function shy(help, meta, list, cb) {
|
function shy(help, meta, list, cb) {
|
||||||
var index = 0, args = arguments; function next(type) {
|
var index = 0, args = arguments; function next(type) {
|
||||||
if (index < args.length && (!type || type == typeof args[index])) {
|
if (index < args.length && (!type || type == typeof args[index])) { return args[index++] }
|
||||||
return args[index++]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cb = args[args.length-1]||function() {}
|
cb = args[args.length-1]||function() {}
|
||||||
cb.help = next(lang.STRING)||""
|
cb.help = next(lang.STRING)||""
|
||||||
cb.meta = next(lang.OBJECT)|| {}
|
cb.meta = next(lang.OBJECT)||{}
|
||||||
cb.list = next(lang.OBJECT)||[]
|
cb.list = next(lang.OBJECT)||[]
|
||||||
return cb
|
return cb
|
||||||
}; var _can_name = "", _can_path = ""
|
}; var _can_name = "", _can_path = ""
|
||||||
@ -258,7 +252,7 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
var meta = arguments.callee.meta, list = arguments.callee.list
|
var meta = arguments.callee.meta, list = arguments.callee.list
|
||||||
if (typeof name == lang.OBJECT) { var Config = name; Config.plugin = Config.plugin||chat.plugin_list
|
if (typeof name == lang.OBJECT) { var Config = name; Config.plugin = Config.plugin||chat.plugin_list
|
||||||
Config.panels = Config.panels||chat.panel_list, Config.main = Config.main||{name: "Header"}
|
Config.panels = Config.panels||chat.panel_list, Config.main = Config.main||{name: "Header"}
|
||||||
meta.libs = chat.libs, meta.iceberg = Config.iceberg||meta.iceberg
|
meta.libs = Config.libs||chat.libs, meta.iceberg = Config.iceberg||meta.iceberg
|
||||||
|
|
||||||
// 预加载
|
// 预加载
|
||||||
libs = []; for (var i = 0; i < Config.panels.length; i++) { var panel = Config.panels[i]
|
libs = []; for (var i = 0; i < Config.panels.length; i++) { var panel = Config.panels[i]
|
||||||
@ -272,7 +266,6 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
for (var k in Config) { can[k] = Config[k] }
|
for (var k in Config) { can[k] = Config[k] }
|
||||||
}
|
}
|
||||||
|
|
||||||
can = can||{}
|
|
||||||
var proto = {__proto__: meta, _path: _can_path, _name: name, _load: function(name, each) { // 加载缓存
|
var proto = {__proto__: meta, _path: _can_path, _name: name, _load: function(name, each) { // 加载缓存
|
||||||
var cache = meta.cache[name]||[]; for (list.reverse(); list.length > 0; list) {
|
var cache = meta.cache[name]||[]; for (list.reverse(); list.length > 0; list) {
|
||||||
var sub = list.pop(); sub != can && cache.push(sub)
|
var sub = list.pop(); sub != can && cache.push(sub)
|
||||||
@ -291,16 +284,18 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
return // 加载完成
|
return // 加载完成
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 无效地址
|
||||||
if (!libs[0]) { return can.require(libs.slice(1), cb, each) }
|
if (!libs[0]) { return can.require(libs.slice(1), cb, each) }
|
||||||
libs[0] = libs[0].toLowerCase()
|
|
||||||
|
|
||||||
|
// 补全地址
|
||||||
if (libs[0] == "") {
|
if (libs[0] == "") {
|
||||||
libs[0] = can._name.replace(".js", ".css")
|
libs[0] = can._name.replace(".js", ".css")
|
||||||
} else if (libs[0][0] != ice.PS && libs[0].indexOf(ice.HTTP) != 0) {
|
} else if (libs[0][0] != ice.PS && libs[0].indexOf(ice.HTTP) != 0) {
|
||||||
libs[0] = can._name.slice(0, can._name.lastIndexOf(ice.PS)+1)+libs[0]
|
libs[0] = can._name.slice(0, can._name.lastIndexOf(ice.PS)+1)+libs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求模块
|
// 加载模块
|
||||||
|
libs[0] = libs[0].toLowerCase()
|
||||||
var name = libs[0].split("?")[0]
|
var name = libs[0].split("?")[0]
|
||||||
function next() { can._load(name, each), can.require(libs.slice(1), cb, each) }
|
function next() { can._load(name, each), can.require(libs.slice(1), cb, each) }
|
||||||
meta.cache[name]? next(): (_can_path = libs[0], meta._load(name, next))
|
meta.cache[name]? next(): (_can_path = libs[0], meta._load(name, next))
|
||||||
@ -316,30 +311,32 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
}); return msg
|
}); return msg
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(name, key, cb) {
|
search: function(event, cmds, cb) {
|
||||||
return can.search({}, [can.core.Keys(name, "onexport", key)], cb)
|
if (cmds && typeof cmds == lang.OBJECT && cmds.length > 0 && typeof cmds[0] == lang.OBJECT && cmds[0].length > 0 ) {
|
||||||
|
cmds[0] = cmds[0].join(ice.PT)
|
||||||
|
}
|
||||||
|
return can.run && can.run(event, ["_search"].concat(cmds), cb, true)
|
||||||
},
|
},
|
||||||
|
get: function(name, key, cb) { return can.search({}, [can.core.Keys(name, chat.ONEXPORT, key)], cb) },
|
||||||
set: function(name, key, value) { var msg = can.request({}); msg.Option(key, value)
|
set: function(name, key, value) { var msg = can.request({}); msg.Option(key, value)
|
||||||
return can.search(msg._event, [can.core.Keys(name, "onimport", key)])
|
return can.search(msg._event, [[name, chat.ONIMPORT, key]])
|
||||||
},
|
},
|
||||||
setHeaderMenu: function(list, cb) { can._menu && can.page.Remove(can, can._menu)
|
setHeaderMenu: function(list, cb) { can._menu && can.page.Remove(can, can._menu)
|
||||||
var msg = can.request({}, {trans: can.onaction._trans})
|
var msg = can.request({}, {trans: can.onaction._trans})
|
||||||
return can._menu = can.search(msg._event, ["Header.onimport.menu", can._name].concat(list), cb)
|
return can._menu = can.search(msg._event, [["Header", chat.ONIMPORT, "menu"], can._name].concat(list), cb)
|
||||||
},
|
},
|
||||||
setHeader: function(key, value) { return can.set("Header", key, value) },
|
setHeader: function(key, value) { return can.set("Header", key, value) },
|
||||||
getHeader: function(key, cb) { return can.get("Header", key, cb) },
|
getHeader: function(key, cb) { return can.get("Header", key, cb) },
|
||||||
getAction: function(key, cb) { return can.get("Action", key, cb) },
|
getAction: function(key, cb) { return can.get("Action", key, cb) },
|
||||||
getActionSize: function(cb) { return can.get("Action", "size", cb) },
|
getActionSize: function(cb) { return can.get("Action", "size", cb) },
|
||||||
search: function(event, cmds, cb) { return can.run && can.run(event, ["_search"].concat(cmds), cb, true) },
|
|
||||||
|
|
||||||
ConfHeight: function(value) { return can.Conf(html.HEIGHT, value) },
|
ConfHeight: function(value) { return can.Conf(html.HEIGHT, value) },
|
||||||
ConfWidth: function(value) { return can.Conf(html.WIDTH, value) },
|
ConfWidth: function(value) { return can.Conf(html.WIDTH, value) },
|
||||||
Conf: function(key, value) { var res = can._conf
|
Conf: function(key, value) { var res = can._conf
|
||||||
for (var i = 0; i < arguments.length; i += 2) {
|
for (var i = 0; i < arguments.length; i += 2) {
|
||||||
if (typeof key == lang.OBJECT) {
|
if (typeof key == lang.OBJECT) {
|
||||||
res = can.core.Value(can._conf, arguments[i])
|
res = can.core.Value(can._conf, arguments[i]), i--
|
||||||
i--
|
continue
|
||||||
return
|
|
||||||
}
|
}
|
||||||
res = can.core.Value(can._conf, arguments[i], arguments[i+1])
|
res = can.core.Value(can._conf, arguments[i], arguments[i+1])
|
||||||
}
|
}
|
||||||
@ -347,7 +344,7 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
}, _conf: {},
|
}, _conf: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (navigator.userAgent.indexOf("MSIE") > -1) {
|
can = can||{}; if (navigator.userAgent.indexOf("MSIE") > -1) {
|
||||||
for (var k in proto) { can[k] = proto[k] }
|
for (var k in proto) { can[k] = proto[k] }
|
||||||
} else {
|
} else {
|
||||||
can.__proto__ = proto
|
can.__proto__ = proto
|
||||||
@ -358,6 +355,7 @@ var Volcanos = shy("火山架", {iceberg: "/chat/", volcano: "/frame.js", args:
|
|||||||
} else { // 加入队列
|
} else { // 加入队列
|
||||||
list.push(can)
|
list.push(can)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can._follow) { libs = libs.concat(meta.libs, meta.volcano) }
|
if (can._follow) { libs = libs.concat(meta.libs, meta.volcano) }
|
||||||
if (libs && libs.length > 0) {
|
if (libs && libs.length > 0) {
|
||||||
for (var i = 0; i < libs.length; i++) {
|
for (var i = 0; i < libs.length; i++) {
|
||||||
@ -377,18 +375,18 @@ Volcanos.meta._load = function(url, cb) {
|
|||||||
case nfs.CSS:
|
case nfs.CSS:
|
||||||
var item = document.createElement(mdb.LINK)
|
var item = document.createElement(mdb.LINK)
|
||||||
item.rel = "stylesheet", item.type = "text/css"
|
item.rel = "stylesheet", item.type = "text/css"
|
||||||
item.onload = cb, item.href = url
|
item.href = url, item.onload = cb
|
||||||
return (document.head||document.body).appendChild(item), item
|
return (document.head||document.body).appendChild(item), item
|
||||||
case nfs.JS:
|
case nfs.JS:
|
||||||
var item = document.createElement(ssh.SCRIPT)
|
var item = document.createElement(ssh.SCRIPT)
|
||||||
item.onload = cb, item.onerror = cb, item.src = url
|
item.src = url, item.onload = cb, item.onerror = cb
|
||||||
return document.body.appendChild(item), item
|
return document.body.appendChild(item), item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function can(tool) {
|
function can(tool) {
|
||||||
Volcanos({name: "chat", panels: [
|
Volcanos({name: "chat", panels: [
|
||||||
{name: "Header", help: "标题栏", pos: "hide", state: ["time", "usernick", "avatar"]},
|
{name: "Header", help: "标题栏", pos: chat.HIDE, state: ["time", "usernick", "avatar"]},
|
||||||
{name: "Action", help: "工作台", pos: chat.MAIN, tool: tool},
|
{name: "Action", help: "工作台", pos: chat.MAIN, tool: tool},
|
||||||
{name: "Search", help: "搜索框", pos: "auto"},
|
{name: "Search", help: "搜索框", pos: chat.AUTO},
|
||||||
]})
|
]})
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ setTimeout(function() { Volcanos({Option: function() { return [] },
|
|||||||
},
|
},
|
||||||
field: function(can, msg, arg) {
|
field: function(can, msg, arg) {
|
||||||
can.onappend.plugin(can, {type: chat.CONTEXTS, index: arg[0], args: can.base.Obj(arg[1])}, function(sub, meta) {
|
can.onappend.plugin(can, {type: chat.CONTEXTS, index: arg[0], args: can.base.Obj(arg[1])}, function(sub, meta) {
|
||||||
var pos = {left: msg.Option(chat.LEFT), top: msg.Option(chat.TOP), right: msg.Option(chat.RIGHT), bottom: msg.Option(chat.BOTTOM)}
|
var pos = {left: msg.Option(html.LEFT), top: msg.Option(html.TOP), right: msg.Option(html.RIGHT), bottom: msg.Option(html.BOTTOM)}
|
||||||
can.page.Modify(can, sub._target, {style: pos})
|
can.page.Modify(can, sub._target, {style: pos})
|
||||||
can.onmotion.move(can, sub._target, pos, function(target) {
|
can.onmotion.move(can, sub._target, pos, function(target) {
|
||||||
can.page.Modify(can, sub._output, {style: {
|
can.page.Modify(can, sub._output, {style: {
|
||||||
@ -82,8 +82,8 @@ setTimeout(function() { Volcanos({Option: function() { return [] },
|
|||||||
|
|
||||||
sub.onaction["保存参数"] = function(event) {
|
sub.onaction["保存参数"] = function(event) {
|
||||||
can.request(event, {zone: location.host, id: msg.Option(mdb.ID)})
|
can.request(event, {zone: location.host, id: msg.Option(mdb.ID)})
|
||||||
can.run(event, [chat.FIELD, mdb.MODIFY, chat.TOP, sub._target.offsetTop])
|
can.run(event, [chat.FIELD, mdb.MODIFY, html.TOP, sub._target.offsetTop])
|
||||||
can.run(event, [chat.FIELD, mdb.MODIFY, chat.LEFT, sub._target.offsetLeft])
|
can.run(event, [chat.FIELD, mdb.MODIFY, html.LEFT, sub._target.offsetLeft])
|
||||||
can.run(event, [chat.FIELD, mdb.MODIFY, ctx.ARGS, JSON.stringify(sub.Input([], true))])
|
can.run(event, [chat.FIELD, mdb.MODIFY, ctx.ARGS, JSON.stringify(sub.Input([], true))])
|
||||||
can.user.toastSuccess(can)
|
can.user.toastSuccess(can)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user