(function() { const PROJECT_HIDE = "web.code.inner:project", TABFILE_HIDE = "web.code.inner:tabview" const CURRENT_FILE = "web.code.inner:currentFile", SELECT_LINE = "web.code.inner:selectLine" const VIEW_CREATE = "tabview.view.create", VIEW_REMOVE = "tabview.view.remove", LINE_SELECT = "tabview.line.select" Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.clear(can), can.onappend.style(can, code.INNER) if (msg.Option(nfs.FILE)) { can.Option(nfs.FILE, msg.Option(nfs.FILE)) msg.Option(nfs.PATH) && can.Option(nfs.PATH, msg.Option(nfs.PATH)) msg.Option(nfs.LINE) && can.Option(nfs.LINE, msg.Option(nfs.LINE)) } if (msg.Result() == "" && can.Option(nfs.LINE) == "1") { return } var files = can.core.Split(can.Option(nfs.FILE), ice.FS); can.Option(nfs.FILE, files[0]) var paths = can.core.Split(can.Option(nfs.PATH), ice.FS); can.Option(nfs.PATH, paths[0]) can.core.List(paths.concat(can.core.Split(msg.Option(nfs.REPOS))), function(p) { if (can.base.endWith(p, "-story/", "-dict/")) { return } if (p && paths.indexOf(p) == -1 && p[0] != ice.PS) { paths.push(p) } }) can.db = {paths: paths, tabview: {}, _history: [], history: [], profile_size: {}, display_size: {}, toolkit: {}}, can.onengine.plugin(can, can.onplugin) can.ui = can.onappend.layout(can, can._output, "", [html.PROJECT, [html.TABS, nfs.PATH, [html.CONTENT, html.PROFILE], html.DISPLAY, html.PLUG]]) can.ui._content = can.ui.content, can.ui._profile = can.ui.profile, can.ui._display = can.ui.display, can.onmotion.hidden(can, can.ui.plug) switch (can.Mode()) { case chat.SIMPLE: // no break case chat.FLOAT: can.onmotion.hidden(can, can.ui.project); break case chat.CMD: can.onmotion.hidden(can, can._status), can.onkeymap._build(can) can.misc.sessionStorage(can, PROJECT_HIDE) == html.HIDE && can.onmotion.hidden(can, can.ui.project) if (can.misc.sessionStorage(can, TABFILE_HIDE) == html.HIDE) { can.onmotion.hidden(can, can.ui.project), can.onmotion.hidden(can, can.ui.tabs) } var plug = can.base.Obj(msg.Option(html.PLUG), []).concat(can.misc.Search(can, log.DEBUG) == ice.TRUE? ["can.debug", "log.debug"]: []) // plug.length > 0 && can.run({}, [ctx.ACTION, ctx.COMMAND].concat(plug.reverse()), function(msg) { msg.Table(function(value) { can.onimport.toolkit(can, value) }) }) case chat.FULL: // no break default: can.onimport.project(can, paths), can.onimport._tabs(can) can.onmotion.delay(can, function() { can.core.Next(files.slice(1), function(file, next) { can.onimport._tabview(can, paths[0], file, "", next) }, function() { can.core.List(can.base.Obj(msg.Option(html.TABS)), function(item) { can.onimport.tabview(can, paths[0], item, ctx.INDEX) }) if (can.user.isWebview) { var last = can.misc.localStorage(can, CURRENT_FILE); if (last) { var ls = can.core.Split(last, ice.DF); ls.length > 0 && can.onimport._tabview(can, ls[0], ls[1], ls[2]) } } }) }) } var args = can.misc.SearchHash(can); can.db.tabview[can.onexport.keys(can)] = msg can.onimport.tabview(can, can.Option(nfs.PATH), can.Option(nfs.FILE), can.Option(nfs.LINE), function() { if (!can.user.isWebview && args.length > 0 && can.isCmdMode()) { can.onimport._tabview(can, args[args.length-3]||can.Option(nfs.PATH), args[args.length-2]||can.Option(nfs.FILE), args[args.length-1]) } }), can.base.isFunc(cb) && cb(msg) }, _keydown: function(can) { can.onkeymap._build(can) }, _tabs: function(can) { if (!can.isCmdMode()) { return can.ui.tabs = can._action } can.user.isMobile || can.core.List([ {name: can.page.unicode.menu, onclick: function() { can.user.carte(event, can, can.onaction, can.onaction.list.concat(can.user.isWebview? ["全屏", "录屏", "编辑器", "浏览器"]: [])) }}, false && {name: can.page.unicode.back, style: {"font-size": "14px", "padding-top": "3px"}, onclick: function(event) { var list = {}; can.user.carte(event, can, {_style: "history"}, can.core.List(can.db.history, function(item) { var value = [item.path, item.file, item.line, ice.TB+(item.text&&item.text.length>30? item.text.slice(0, 30)+"...": item.text||"")].join(ice.DF); if (!list[value]) { list[value] = item; return value } }).reverse(), function(event, button, meta, carte) { carte.close() var ls = button.split(ice.DF); can.onimport.tabview(can, ls[0], ls[1], ls[2]) }) }}, {name: can.page.unicode.refresh, style: {"font-size": "24px", "padding-top": "1px"}, onclick: function() { location.reload() }}, false && {name: can.page.unicode.reback, style: {"font-size": "14px", "padding-top": "3px"}, onclick: function() { var list = {}; can.user.carte(event, can, {_style: "tabview"}, can.core.Item(can.db.tabview), function(event, button, meta, carte) { carte.close() var ls = button.split(ice.DF); can.onimport.tabview(can, ls[0], ls[1]) }) }}, ], function(item) { can.page.Append(can, can.ui.tabs, [can.base.Copy(item, {view: [[html.ICON, web.WEBSITE], html.DIV, item.name]})]) }) can.page.Append(can, can.ui.tabs, can.user.header(can)) }, __tabPath: function(can, skip) { can.onmotion.clear(can, can.ui.path) can.onimport._tabPath(can, ice.PS, nfs.PATH, can.base.Path(can.Option(nfs.PATH), can.Option(nfs.FILE)), function(ls) { if (ls[0] == ice.USR && ls.length > 2) { can.onimport.tabview(can, ls.slice(0, 2).join(ice.PS)+ice.PS, ls.slice(2).join(ice.PS)) } else if (ls.length > 1) { can.onimport.tabview(can, ls.slice(0, 1).join(ice.PS)+ice.PS, ls.slice(1).join(ice.PS)) } else { can.onimport.tabview(can, nfs.PWD, ls[0]) } }, can.ui.path), can.onimport._tabFunc(can, can.ui.path, skip), can.onimport._tabMode(can), can.onimport._tabIcon(can) }, _tabPath: function(can, ps, key, value, cb, target) { can.core.List(can.core.Split(value, ps), function(value, index, array) { can.page.Append(can, target, [{text: [value+(index 10? ["filter"]: []).concat(msg.Table(function(value) { var p = can.core.Split(value[key], ps).pop()+(can.base.endWith(value[key], ps)? ps: ""); return _trans[p] = value[key], p })), function(event, button) { can.base.endWith(button, ps)? can.onimport.tabPath(event, can, ps, key, pre+button, cb, carte): cb(can.core.Split(_trans[button], ps)) }, parent)._target, file = can.core.Split(event.target.innerHTML.trim(), ice.PT)[0] can.page.Select(can, carte, html.DIV_ITEM, function(target) { target.innerHTML.trim() != event.target.innerHTML.trim() && can.base.beginWith(target.innerHTML, file+ice.PT) && carte.insertBefore(target, carte.firstChild) }) function remove(p) { if (p && p._sub) { remove(p._sub), can.page.Remove(can, p._sub), delete(p._sub) } } if (parent) { remove(parent), parent._sub = carte } }) }, _tabFunc: function(can, target, skip) { can.ui.path.ondblclick = function(event) { var show = can.onmotion.toggle(can, can.ui.tabs); can.onmotion.toggle(can, can.ui.project, show), can.onimport.layout(can) can.isCmdMode() && can.misc.sessionStorage(can, TABFILE_HIDE, show? "": html.HIDE) } if (skip) { var func = can.db._func||{list: []} } else { var func = can.onexport.func(can); can.db._func = func } if (func.list.length > 0) { can.db.tabFunc = can.db.tabFunc||{} var last = can.db.tabFunc[can.Option(nfs.PATH)+can.Option(nfs.FILE)]||{}; can.db.tabFunc[can.Option(nfs.PATH)+can.Option(nfs.FILE)] = last var carte, list = [web.FILTER]; can.core.Item(last, function(key) { list.push(key) }), list = list.concat(func.list) } can.page.Append(can, target, [{view: [[html.ITEM, "func"], html.SPAN, (func.current||"func")+"/"+can.db.max+func.percent+ice.SP+can.base.Size(can._msg.result[0].length)], onclick: function(event) { carte = can.user.carte(event, can, {_style: nfs.PATH}, list, function(ev, button) { last[button] = true, carte.close() can.onimport.tabview(can, can.Option(nfs.PATH), can.Option(nfs.FILE), can.core.Split(button, ice.DF)[1]) }) }}]) }, _tabMode: function(can) { var mode = can.db.mode||"", target = can.ui.current; if (target && mode != mdb.PLUGIN) { mode += ice.SP+target.selectionStart+ice.PS+target.value.length } can.page.Append(can, can.ui.path, [{text: [mode, "", ["mode", can.db.mode||""]], onclick: function(event) { var list = {}; can.core.Item(can.onkeymap._mode[can.db.mode], function(k, cb) { list[cb.help+ice.TB+k] = function(event, can, button) { can.core.CallFunc(cb, {event: event, can: can}) } }) can.core.Item(can.onkeymap._mode[can.db.mode+"_ctrl"], function(k, cb) { list[cb.help+ice.TB+"C-"+k] = function(event, can, button) { can.core.CallFunc(cb, {event: event, can: can}) } }) can.user.carte(event, can, list, []) }}]) }, _tabIcon: function(can) { can.user.isWindows || can.page.Append(can, can.ui.path, can.core.Item({ "\u25E8 ": function(event) { if (can.page.isDisplay(can.ui.profile)) { return can.onmotion.hidden(can, can.ui.profile), can.onimport.layout(can) } can.onaction.show(event, can) }, "\u25E8": shy({"font-size": "23px", rotate: "90deg", translate: "1px 1px"}, function(event) { if (can.page.isDisplay(can.ui.display)) { return can.onmotion.hidden(can, can.ui.display), can.onimport.layout(can) } can.onaction.exec(event, can) }), "\u25E7": function(event) { var show = can.onmotion.toggle(can, can.ui.project); can.onimport.layout(can) can.isCmdMode() && can.misc.sessionStorage(can, PROJECT_HIDE, show? "": html.HIDE) }, "\u2756": shy({"font-size": "20px", translate: "0 2px"}, function(event) { can.onaction.plug(event, can) }), "\u271A": shy({"font-size": "20px", translate: "0 2px"}, function(event) { can.onaction.open(event, can) }), }, function(text, cb) { return cb && {text: [text, html.SPAN, html.VIEW], style: cb.meta, onclick: cb} })) }, _tabview: function(can, path, file, line, cb) { var key = can.onexport.keys(can, path, file) if (!can.user.isWebview) { return can.onimport.tabview(can, path, file, line, cb) } if (!can.db.tabview[key]) { return can.onimport.tabview(can, path, file, line, cb), can.db.tabview[key] = true } }, tabview: function(can, path, file, line, cb) { path = path||can.Option(nfs.PATH); var key = can.onexport.keys(can, path, file); can.db._keylist = [] function isIndex() { return line == ctx.INDEX } function isSpace() { return line == web.SPACE } function show(skip) { can._msg && can._msg.Option(nfs.LINE, can.Option(nfs.LINE)), can._msg = can.db.tabview[key] can.Option(can.onimport.history(can, {path: path, file: file, line: line||can.misc.sessionStorage(can, SELECT_LINE+ice.DF+path+file)||can._msg.Option(nfs.LINE)||1})) can.onsyntax._init(can, can._msg, function(content) { var msg = can._msg; can.onexport.hash(can) can.isCmdMode() && can.onexport.title(can, path+file), can.onmotion.select(can, can.ui.tabs, html.DIV_TABS, msg._tab), can.isCmdMode() && msg._tab.scrollIntoView() if (isIndex()) { can.ui.path.innerHTML = can.Option(nfs.FILE) } else if (isSpace()) { can.ui.path.innerHTML = can.page.Format(html.A, can.misc.MergePodCmd(can, {pod: can.Option(nfs.FILE)})) } else { can.onimport.__tabPath(can) } can.page.SelectChild(can, can.ui._content.parentNode, can.page.Keys(html.DIV_CONTENT, html.FIELDSET_STORY, [[[html.IFRAME, html.CONTENT]]]), function(target) { if (can.onmotion.toggle(can, target, target == msg._content)) { can.ui.content = msg._content } }), can.ui.content._plugin = msg._plugin, can.ui.profile._plugin = msg._profile can.page.SelectChild(can, can.ui._content.parentNode, can.page.Keys(html.DIV_PROFILE, [[[html.IFRAME, html.PROFILE]]]), function(target) { if (can.onmotion.toggle(can, target, target == msg._profile)) { can.ui.profile = msg._profile } }), can.onimport.layout(can), can.ui.current && can.onmotion.toggle(can, can.ui.current, !isIndex() && !isSpace()) skip || can.onaction.selectLine(can, can.Option(nfs.LINE), true), can.base.isFunc(cb) && cb(), cb = null var ls = can.db.file.split(ice.PS); if (ls.length > 4) { ls = [ls.slice(0, 2).join(ice.PS)+"/.../"+ls.slice(-2).join(ice.PS)] } can.Status(kit.Dict(nfs.FILE, ls.join(ice.PS), mdb.TYPE, can.db.parse)) }) } function load(msg) { var skip = false; can.db.tabview[key] = msg can.onimport.tabs(can, [{name: can.base.beginWith(file, "http://")? file.split(ice.QS)[0]: file.split(isIndex()? ice.PT: ice.PS).pop(), text: file, _menu: shy([ nfs.SAVE, nfs.TRASH, web.REFRESH, ], function(event, button, meta) { can.onaction[button](event, can, button) })}], function(event, tabs) { can._tab = msg._tab = tabs._target, show(skip), skip = true }, function(tabs) { can.onengine.signal(can, VIEW_REMOVE, msg), can.ui.zone.source.refresh() msg._content != can.ui._content && can.page.Remove(can, msg._content), msg._profile != can.ui._profile && can.page.Remove(can, msg._profile) delete(can.ui._content._cache[key]), delete(can.ui._profile._cache[key]), delete(can.ui.display._cache[key]) delete(can._cache_data[key]), delete(can.db.tabview[key]) }, can.ui.tabs) } can.db._keylist = [] if (can.db.tabview[key]) { return !can._msg._tab && !can.isSimpleMode()? load(can.db.tabview[key]): show() } isIndex()||isSpace()? load(can.request({}, {index: file, line: line})): can.run({}, [path, file], load, true) }, history: function(can, record) { can.base.Eq(record, can.db.history[can.db.history.length-1], mdb.TEXT) || can.db.history.push(record) return can.Status(ice.BACK, can.db.history.length), record }, project: function(can, path) { can.onimport.zone(can, can.core.Item(can.onfigure, function(name, cb) { if (can.base.isFunc(cb)) { return {name: name, _trans: can.onfigure._trans? can.onfigure._trans[name]||"": "", _init: function(target, zone) { return cb(can, target, zone, path) }} } }), can.ui.project), can.user.isMobile && !can.user.isLandscape() && can.onmotion.hidden(can, can.ui.project) }, profile: function(can, msg) { var _msg = can.db.tabview[can.onexport.keys(can)] if (msg.Result().indexOf("