efront 3.16.1 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/apps/pivot/api/edit.js +1 -0
  2. package/apps/pivot/api/list.js +20 -0
  3. package/apps/pivot/api.yml +8 -4
  4. package/apps/pivot/dict/edit.js +1 -0
  5. package/apps/pivot/dict/list.js +12 -0
  6. package/apps/pivot/link/chat.js +29 -0
  7. package/apps/pivot/link/chat.less +5 -0
  8. package/apps/pivot/link/list.html +8 -3
  9. package/apps/pivot/link/list.js +23 -2
  10. package/apps/pivot/link/list.less +3 -0
  11. package/apps/pivot/log/boot.js +13 -10
  12. package/apps/pivot/main.less +1 -0
  13. package/apps/pivot/menu.yml +4 -1
  14. package/apps/pivot/proxy/list.js +9 -8
  15. package/apps/pivot/task/list.js +1 -1
  16. package/apps/pivot/user/api.html +2 -0
  17. package/apps/pivot/user/api.js +14 -0
  18. package/apps/pivot/user/api.less +0 -0
  19. package/coms/basic/Speed.js +2 -3
  20. package/coms/basic/assert.js +5 -3
  21. package/coms/basic/lazy.js +21 -7
  22. package/coms/basic/lazy_test.js +62 -0
  23. package/coms/basic/parseURL.js +21 -2
  24. package/coms/basic/refilm_decode.js +4 -2
  25. package/coms/frame/chat.html +13 -0
  26. package/coms/frame/chat.js +39 -0
  27. package/coms/frame/chat.less +125 -0
  28. package/coms/frame/design.html +7 -0
  29. package/coms/frame/design.js +23 -0
  30. package/coms/frame/design.less +17 -0
  31. package/coms/frame/dict.js +21 -0
  32. package/coms/frame/edit.js +1 -1
  33. package/coms/frame/left.html +1 -1
  34. package/coms/frame/list.js +1 -1
  35. package/coms/frame/route.js +1 -0
  36. package/coms/kugou/song.html +1 -1
  37. package/coms/kugou/song.js +4 -3
  38. package/coms/pivot/pedit.js +3 -3
  39. package/coms/pivot/plist.js +2 -2
  40. package/coms/zimoli/Item.js +40 -25
  41. package/coms/zimoli/appendChild.js +6 -8
  42. package/coms/zimoli/cloneVisible.js +1 -0
  43. package/coms/zimoli/container.js +10 -0
  44. package/coms/zimoli/createItemTarget.js +7 -0
  45. package/coms/zimoli/data.js +26 -12
  46. package/coms/zimoli/design.html +5 -4
  47. package/coms/zimoli/design.less +8 -3
  48. package/coms/zimoli/drag.js +5 -3
  49. package/coms/zimoli/field.html +1 -1
  50. package/coms/zimoli/getGenerator.js +4 -4
  51. package/coms/zimoli/getTreeFromData.js +3 -0
  52. package/coms/zimoli/list.js +5 -5
  53. package/coms/zimoli/menu.js +16 -13
  54. package/coms/zimoli/menuItem.js +2 -2
  55. package/coms/zimoli/menuList.html +1 -1
  56. package/coms/zimoli/menuList.js +14 -14
  57. package/coms/zimoli/menuList.less +1 -1
  58. package/coms/zimoli/model.js +4 -3
  59. package/coms/zimoli/on.js +1 -1
  60. package/coms/zimoli/once.js +6 -5
  61. package/coms/zimoli/onmounted.js +1 -1
  62. package/coms/zimoli/render.js +61 -24
  63. package/coms/zimoli/renderDefaults.js +1 -0
  64. package/coms/zimoli/resize.js +18 -0
  65. package/coms/zimoli/scrollbar.js +20 -8
  66. package/coms/zimoli/scrollbar.less +22 -1
  67. package/coms/zimoli/tree.js +3 -3
  68. package/coms/zimoli/vbox.js +7 -3
  69. package/coms/zimoli/zimoli.js +1 -1
  70. package/package.json +1 -1
  71. package/public/efront.js +1 -1
@@ -0,0 +1 @@
1
+ pedit.bind(null, "接口", "api");
@@ -0,0 +1,20 @@
1
+ var types = refilm`
2
+ 数值/number
3
+ 文本/input
4
+ `;
5
+ model.setModels({
6
+ design: frame$dict.bind(null, types),
7
+ });
8
+ return plist.bind(null, '接口管理', "api", refilm`
9
+ *接口路径/path 100
10
+ 接口名/name 100
11
+ 请求方法/method select [get,post,put,patch,options]
12
+ 数据格式/format select [JSON,JSAM,URLencode]
13
+ !参数/fields design ${[
14
+ {
15
+ name: "修改",
16
+ }
17
+ ]}
18
+ 加密方式/crypt select [timeencode,encode62]
19
+ *是否启用/status radio [不启用,启用]
20
+ `, '/api/edit');
@@ -1,4 +1,4 @@
1
- / authorization=:
1
+ / authorization=:
2
2
  login: options ::login-:a
3
3
  run: options :::run
4
4
  share: options ::share-:opt?:path
@@ -6,15 +6,19 @@
6
6
  cluster: options ::cluster-:opt?:id
7
7
  list: options :::type
8
8
  edit: options :::type-:key?:value
9
+ add: options :::type-:key+:value
9
10
  params: options ::params-:key
10
11
  invoke: options ::invoke-:key?:params
11
12
  version: options ::version
12
13
  uptime: options ::uptime
13
14
  count: options ::count
14
15
  bootlog: options ::similar
15
- https://www.ip.cn/ :
16
+ link: options ::link
17
+ care: options ::care-:id
18
+ cast: options ::cast-:id?:msg
19
+ https://www.ip.cn/:
16
20
  iplocation: get https://www.ip.cn/api/index?ip=:ip&type=1
17
21
  # https://ipchaxun.com/ :
18
- # iplocation: get:[].info%20label:nth-child(n+2)>span:nth-child(2) :ip/
22
+ # iplocation: get:[].info%20label:nth-child(n+2)>span:nth-child(2) :ip/
19
23
  # https://www.ip138.com/:
20
- # iplocation: get:head>script:nth-last-child(1) iplookup.asp?ip=:ip&action=2
24
+ # iplocation: get:head>script:nth-last-child(1) iplookup.asp?ip=:ip&action=2
@@ -0,0 +1 @@
1
+ pedit.bind(null, "字典", "dict");
@@ -0,0 +1,12 @@
1
+ var types = refilm`
2
+ 数值/number
3
+ 文本/input
4
+ `;
5
+ model.setModels({
6
+ dict: frame$dict.bind(null, types),
7
+ });
8
+ return plist.bind(null, '接口管理', "dict", refilm`
9
+ *字典ID/key 100
10
+ 字典名/name 100
11
+ 字典数据/options dict
12
+ `, '/dict/edit');
@@ -0,0 +1,29 @@
1
+ async function link(id, page) {
2
+ if (!id) {
3
+ id = await data.from("link");
4
+ }
5
+ page.$scope.title = `会话窗口(<span nodrag>${id}</span>)`;
6
+ page.roomid = id;
7
+ var removed = false;
8
+ on("remove")(page, function () {
9
+ removed = true;
10
+ if (xhr.abort) xhr.abort();
11
+ });
12
+ var xhr = null;
13
+ while (true) {
14
+ if (removed) break;
15
+ xhr = data.from("care", { id }, function (data) {
16
+ page.$scope.msglist.push.apply(page.$scope.msglist, data);
17
+ });
18
+ await xhr;
19
+ }
20
+ }
21
+ function main(id) {
22
+ console.log(id)
23
+ var page = frame$chat();
24
+ care(page, 'send', function (msg) {
25
+ data.from("cast", { id: page.roomid, msg });
26
+ });
27
+ link(id, page);
28
+ return page;
29
+ }
@@ -0,0 +1,5 @@
1
+ [nodrag] {
2
+ cursor: text;
3
+ user-select: text;
4
+ display: inline-block;
5
+ }
@@ -1,3 +1,7 @@
1
+ <btn @click="chat()">新建连接</btn>
2
+ <div>
3
+ 自动刷新<swap -model="autoreload"></swap>
4
+ </div>
1
5
  <div class="clusters">
2
6
  <a -repeat="(c,i) in clusters" ng-class="{current:i===index.index}" @click="active(i,c)">
3
7
  <span -text="c"></span>
@@ -5,8 +9,9 @@
5
9
  </div>
6
10
  <lattice -src="c in clients">
7
11
  <padding>
8
- <span -text=c.id></span>
9
- <span class="time" -text=filterTime(c.optime)></span>
10
-
12
+ <item @click="chat(c.id)">
13
+ <span -text=c.id></span>
14
+ <span class="time" -text=filterTime(c.optime)></span>
15
+ </item>
11
16
  </padding>
12
17
  </lattice>
@@ -1,11 +1,23 @@
1
+ var autoreload = true;
1
2
  function main() {
2
3
  var page = div();
3
4
  page.innerHTML = template;
4
5
  renderWithDefaults(page, {
5
- async load() {
6
- this.clusters = data.from("cluster", { opt: "list" });
6
+ load: lazy(async function () {
7
+ this.clusters = data.asyncInstance("cluster", { opt: "list" });
7
8
  await this.clusters;
8
9
  this.active();
10
+ }, -1000),
11
+ chat(id) {
12
+ popup("/link/chat", id);
13
+ },
14
+ get autoreload() {
15
+ return autoreload;
16
+ },
17
+ set autoreload(v) {
18
+ autoreload = v;
19
+ clearInterval(loadid);
20
+ if (autoreload) page.$reload();
9
21
  },
10
22
  index: data.getInstance("index"),
11
23
  clusters: [],
@@ -20,6 +32,15 @@ function main() {
20
32
  this.clients = data.from("cluster", { opt: "list", id: clusters[index] });
21
33
  },
22
34
  });
35
+ var loadid = 0;
36
+ on("append")(page, function () {
37
+ if (autoreload) loadid = setInterval(function () {
38
+ page.$scope.load();
39
+ }, 30);
40
+ });
41
+ on('remove')(page, function () {
42
+ clearInterval(loadid);
43
+ });
23
44
  page.$scope.load();
24
45
  return page;
25
46
  }
@@ -11,4 +11,7 @@
11
11
  .button.current {
12
12
  background: #28c;
13
13
  color: #fff;
14
+ }
15
+ btn{
16
+ padding: 0 16px;
14
17
  }
@@ -11,9 +11,9 @@ var fields = refilm`
11
11
  appendChild(e, l);
12
12
  };
13
13
  if (e.data.address) setAddress(e.data.address);
14
- else data.from("iplocation", { ip: m[0] }, function (a) {
15
- e.data.address = a.address;
14
+ else e.data.address = data.from("iplocation", { ip: m[0] }, function (a) {
16
15
  setAddress(a.address);
16
+ return a.address;
17
17
  });
18
18
  }
19
19
  return e;
@@ -24,8 +24,11 @@ var fields = refilm`
24
24
  端口/port ${async function (e) {
25
25
  var { data, field } = e;
26
26
  var ports = data[field.key].split(/,/);
27
- var loaded = [];
28
- for (var p of ports) {
27
+ var loaded = data.loaded || ports;
28
+ data.loaded = loaded;
29
+ e.innerHTML = loaded.join(' ');
30
+ if (data.loaded === ports) for (let cx = 0, dx = ports.length; cx < dx; cx++) {
31
+ var p = ports[cx];
29
32
  var p0 = p;
30
33
  var protocol = /^https/.test(p) ? "https://" : "http://";
31
34
  p = p.replace(/[^\d]+/g, '');
@@ -40,18 +43,18 @@ var fields = refilm`
40
43
  }
41
44
  var xhr = await cross("options", `${protocol}${ip}${p}/:version`);
42
45
  if (xhr.responseText === 'efront ' + data.version) {
43
- loaded.push(`<span style="color:green">${p0}</span>`);
46
+ loaded[cx] = (`<span style="color:green">${p0}</span>`);
44
47
  } else {
45
- loaded.push(`<span style="color:red">${p0}</span>`);
48
+ loaded[cx] = (`<span style="color:red">${p0}</span>`);
46
49
  }
47
50
  } catch (e) {
48
- loaded.push(`<span style="color:gray">${p0}</span>`);
51
+ loaded[cx] = (`<span style="color:gray">${p0}</span>`);
49
52
  }
50
- e.innerHTML = loaded.join('');
53
+ e.innerHTML = loaded.join(' ');
51
54
  }
52
55
  }}
53
- 版本 / version text
54
- 进程 / pid
56
+ 版本/version input
57
+ 进程/pid
55
58
  `;
56
59
  function main() {
57
60
  var page = div();
@@ -1,4 +1,5 @@
1
1
  >:not([layer]) {
2
2
  padding: 50px 10px 0;
3
3
  min-height: 100%;
4
+ display: block;
4
5
  }
@@ -4,14 +4,17 @@ WEB:
4
4
  短链接: /proxy/list
5
5
  文件管理: /wow/root
6
6
  长连接管理: /link/list
7
+ 字典: /dict/list
8
+ 接口: /api/list
7
9
  任务:
8
10
  密钥管理: /token/list
9
11
  任务建立: /task/list
10
12
  定期执行: /tick/list
13
+ # 服务器: /api/host
11
14
  用户:
12
15
  账号列表: /user/list
13
16
  标签管理: /user/tag/list
14
17
  服务器日志:
15
18
  访问计数: /log/count
16
19
  启动记录: /log/boot
17
- # 并发记忆: /log/lock
20
+ # 并发记忆: /log/lock
@@ -1,12 +1,13 @@
1
1
  var fields = refilm`
2
2
  *代理路径/url input/20
3
3
  真实路径/realpath url/2000
4
- / - ${[{
5
- name: "访问",
6
- do(o) {
7
- var url = o.url;
8
- if (!/^\//.test(url)) url = "/" + url;
9
- window.open(url,null);
10
- }
11
- }]}`;
4
+ 动作/action select/200 [跳转,转发]
5
+ / $ ${[{
6
+ name: "访问",
7
+ do(o) {
8
+ var url = o.url;
9
+ if (!/^\//.test(url)) url = "/" + url;
10
+ window.open(url, null);
11
+ }
12
+ }]}`;
12
13
  return plist.bind(null, '短链接', "proxy", fields, "/proxy/edit");
@@ -3,7 +3,7 @@ plist.bind(null, '任务管理', "task", refilm`
3
3
  *任务名/name 100
4
4
  *是否启用/status radio [不启用,启用]
5
5
  任务代码/code text
6
- / - ${[
6
+ / $ ${[
7
7
  {
8
8
  when(o) {
9
9
  return o.status === 1;
@@ -0,0 +1,2 @@
1
+ <xlist #navbar ng-src="m in apilist"></xlist>
2
+ <container src@="navbar.selected?.path"></container>
@@ -0,0 +1,14 @@
1
+ function main() {
2
+ var page = document.createElement('user-api');
3
+ page.innerHTML = template;
4
+ renderWithDefaults(page, {
5
+ apilist: ["查询", "添加", "删除", "登录"].map(a => {
6
+ var [name, path] = a.split(' ');
7
+ return { name };
8
+ }),
9
+ xlist: menu,
10
+ })
11
+ page.$scope.apilist[1].actived = true;
12
+ console.log(page.$scope)
13
+ return page;
14
+ }
File without changes
@@ -22,12 +22,11 @@ function inertia(gun) {
22
22
  }
23
23
  var smooth = function () {
24
24
  var args = spd.read();
25
- if (decrease && args.filter(a => Math.abs(a) > .5).length === 0) {
26
- spd.reset();
25
+ if (decrease && args.filter(a => Math.abs(a) > 2).length === 0) {
27
26
  _decrease();
28
27
  return;
29
28
  }
30
- if (args.filter(a => Math.abs(a) > .1).length === 0) {
29
+ if (args.filter(a => Math.abs(a) > .5).length === 0) {
31
30
  spd.reset();
32
31
  return;
33
32
  }
@@ -1,5 +1,6 @@
1
- var dump = function (a) {
2
- if (a instanceof Object) console.error('对象的属性不符合'), console.log(" ", a);
1
+ var dump = function (a, msg) {
2
+ if (a instanceof Object) console.error('对象的属性不符合'), console.log(msg ? msg + " " : " ", a);
3
+ else if (msg) console.error(msg + ":", a);
3
4
  else console.error(a);
4
5
  };
5
6
  var assert = function (result, expect, log = dump) {
@@ -48,7 +49,8 @@ var assert = function (result, expect, log = dump) {
48
49
  }
49
50
  if (!res) {
50
51
  if (!hasCollect) collect()();
51
- if (log) log(errors);
52
+ if (typeof log === 'function') log(errors);
53
+ else dump(errors, log);
52
54
  }
53
55
  return res;
54
56
  }
@@ -5,13 +5,28 @@
5
5
  function lazy(run, time = false) {
6
6
  var wait = +time ? setTimeout : requestAnimationFrame;
7
7
  var ing, args, that;
8
+ var hire = function () {
9
+ if (time >= 0) {
10
+ if (ing === true) ing = wait(fire, +time / 2);
11
+ else wait(fire, +time / 2), ing = -2;
12
+ }
13
+ else {
14
+ wait(fire, -time);
15
+ }
16
+ };
8
17
  var fire = function () {
9
18
  if (time >= 0) {
10
19
  if (ing === true) {
11
- ing = wait(fire, +time);
20
+ ing = wait(fire, +time / 2);
21
+ }
22
+ else if (ing > 0) {
23
+ wait(fire, +time / 2);
24
+ ing = -1;
12
25
  }
13
- else if (isFinite(ing)) {
26
+ else if (ing === -1) {
14
27
  ing = run.apply(that, args);
28
+ if (ing instanceof Promise) ing.then(hire, hire);
29
+ else ing = false;
15
30
  }
16
31
  else {
17
32
  ing = false;
@@ -20,13 +35,12 @@ function lazy(run, time = false) {
20
35
  else {
21
36
  if (ing === true) {
22
37
  ing = run.apply(that, args);
23
- wait(fire, -time);
24
- if (!ing) ing = 1;
38
+ if (ing instanceof Promise) ing.then(hire, hire);
39
+ else ing = wait(fire, -time);
25
40
  } else {
26
41
  ing = false;
27
42
  }
28
43
  }
29
- if (ing instanceof Promise) ing.then(fire, fire);
30
44
  };
31
45
  return function () {
32
46
  args = arguments;
@@ -37,8 +51,8 @@ function lazy(run, time = false) {
37
51
  }
38
52
  else {
39
53
  ing = run.apply(that, args);
40
- if (ing instanceof Promise) ing.then(fire, fire);
41
- ing = wait(fire, -time);
54
+ if (ing instanceof Promise) ing.then(hire, hire);
55
+ else ing = wait(fire, -time);
42
56
  }
43
57
  };
44
58
  }
@@ -0,0 +1,62 @@
1
+ var lazy = require("./lazy");
2
+ var assert = require("./assert");
3
+ async function test(sch, pending, callsch) {
4
+ pending = +pending || 0;
5
+ var wait = t => new Promise(a => setTimeout(a, t));
6
+ var waits = t => wait(t * Math.abs(sch));
7
+ var waite = async (t) => (await waits(t), await wait(pending));
8
+ var count = 0, start = Date.now(), time = start;
9
+ var f = lazy(function () {
10
+ count++;
11
+ var now = Date.now();
12
+ var delta = now - time;
13
+ time = now;
14
+ if (count > 1) assert(delta >= Math.abs(sch), true, '触发间隔' + delta);
15
+ console.log('sch', sch, 'count', count, 'pass', now - start, 'delta', delta, 'pending', pending);
16
+ if (pending) return wait(pending);
17
+ }, sch);
18
+ f();
19
+ f();
20
+ f();
21
+ f();
22
+ f();
23
+ callsch = +callsch || 1;
24
+ var i = setInterval(f, callsch);
25
+ await wait(.5);
26
+ if (sch < 0) assert(count, 1, '周期小于0,一个周期内触发');
27
+ if (sch > 0) assert(count, 0, '周期大于0时,一个周期内不触发');
28
+ await waite(1.5);
29
+ if (sch < 0) assert(count, 2, '周期小于0,不到两个周期内触发');
30
+ await waits(9);
31
+ if (sch > 0 && sch > callsch) assert(count, 0, '周期大于0时,10个周期内不触发');
32
+ clearInterval(i);
33
+ await waits(2);
34
+ if (sch > 0 && sch > callsch) assert(count, 1, '周期大于0时,等待一个多周期后触发');
35
+ await waite(2);
36
+ var saved_count = count;
37
+ await waite(5);
38
+ assert(saved_count, count, '未调用时不触发');
39
+ f();
40
+ await waite(2);
41
+ assert(count, saved_count + 1, '非连续调用时,第一次触发');
42
+ f();
43
+ await waite(2);
44
+ assert(count, saved_count + 2, '非连续调用时,第二次触发');
45
+ f();
46
+ await waite(2);
47
+ assert(count, saved_count + 3, '非连续调用时,第二次触发');
48
+ }
49
+ test(100);
50
+ test(-100);
51
+ test(100, 10);
52
+ test(100, 80);
53
+ test(100, 180);
54
+ test(-100, 10, 11);
55
+ test(-100, 80, 81);
56
+ test(-100, 180, 181);
57
+ test(100, 10, 11);
58
+ test(100, 80, 81);
59
+ test(100, 180, 181);
60
+ // test(-100, 180);
61
+ // test(NaN);
62
+ // test(NaN, 80);
@@ -1,5 +1,24 @@
1
- // -------/// ---------------1---------------------------------///////////////////2-----3--------//////// ------4----2/////5---------------------------------------------------6-----------------------------------------------------------------------------//////////////-7--5///8-------9----------//10--11---10///--12-----8//
2
- var reg = /^([^\:\/\\\?#\[]+\:(?![^\:\/\\\?\#]*@|[\/\\][^\/\\]))?(?:\/\/|\\\\)?(?:(([^\:\/\\\?#]+)?(?:\:([^\/\\\?#]+))?)@)?(([^\/\\@\?\#\.]*?[^\/\\@\:\?\#\.\d][^\/\\@\:\?\#\.]*?|[^\/\\@\:\?\#\.]+(?:\:[\@\/\\\?#\.]*[^\d\@\:\/\\\?#\.]+|\.[^\/\\@\:\?\#]+?))?(?:(?:\:|^)(\d+))?)(((?:\/|\\|^)[^\?#]*)?(\?([^#]*))?(#[\s\S]*)?)$/;
1
+ // 下图来自 https://nodejs.org/dist/latest-v16.x/docs/api/url.html#urlobjectauth
2
+ // ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
3
+ // │ href │
4
+ // ├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
5
+ // │ protocol │ │ auth │ host │ path │ hash │
6
+ // │ │ │ ├─────────────────┬──────┼──────────┬────────────────┤ │
7
+ // │ │ │ │ hostname │ port │ pathname │ search │ │
8
+ // │ │ │ │ │ │ ├─┬──────────────┤ │
9
+ // │ │ │ │ │ │ │ │ query │ │
10
+ // " https: // user : pass @ sub.example.com : 8080 /p/a/t/h ? query=string #hash "
11
+ // │ │ │ │ │ hostname │ port │ │ │ │
12
+ // │ │ │ │ ├─────────────────┴──────┤ │ │ │
13
+ // │ protocol │ │ username │ password │ host │ │ │ │
14
+ // ├──────────┴──┼──────────┴──────────┼────────────────────────┤ │ │ │
15
+ // │ origin │ │ origin │ pathname │ search │ hash │
16
+ // ├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
17
+ // │ href │
18
+ // └────────────────────────────────────────────────────────────────────────────────────────────────┘
19
+
20
+ // -------/// ---------------1---------------------------------///////////////////2-----3--------//////// ------4----2/////5---------------------------------------------------6-----------------------------------------------------------------------------//////////////-7--5///8-------9----------//10--11---10/8/--12----////
21
+ var reg = /^([^\:\/\\\?#\[]+\:(?![^\:\/\\\?\#]*@|[\/\\][^\/\\]))?(?:\/\/|\\\\)?(?:(([^\:\/\\\?#]+)?(?:\:([^\/\\\?#]+))?)@)?(([^\/\\@\?\#\.]*?[^\/\\@\:\?\#\.\d][^\/\\@\:\?\#\.]*?|[^\/\\@\:\?\#\.]+(?:\:[\@\/\\\?#\.]*[^\d\@\:\/\\\?#\.]+|\.[^\/\\@\:\?\#]+?))?(?:(?:\:|^)(\d+))?)(((?:\/|\\|^)[^\?#]*)?(\?([^#]*))?)(#[\s\S]*)?$/;
3
22
  function parseURL(url) {
4
23
  if (url === undefined || url === null) url = '';
5
24
  var [__, protocol, auth, username, password, host, hostname, port, path, pathname, search, query, hash] = reg.exec(url);
@@ -277,14 +277,15 @@ function parse(piece) {
277
277
  var reg = /^[\*\+\-\!\-\$&\?\~]|[\*\+\-\!\-\$&\?\~]$/;
278
278
  if (!reg.test(a)) return a;
279
279
  required = test(/^\*|\*$/, a);
280
- inlist = test(/^[\+\!]|[\+\!]$/, a);
280
+ if (test(/^[\+]|[\+]$/, a)) inlist = true;
281
+ if (test(/^[\!]|[\!]$/, a)) inlist = false;
281
282
  hidden = test(/^\-|\-$/, a);
282
283
  readonly = test(/^[\$&]|[\$&]$/, a);
283
284
  delete_onempty = test(/^\?|\?$/, a);
284
285
  delete_onsubmit = test(/^\~|\~$/, a);
285
286
  return a.replace(reg, '');
286
287
  };
287
- type = is(type);
288
+ var type1 = is(type);
288
289
  if (typeof name === 'string') {
289
290
  if (!isContainer) {
290
291
  if (!type) {
@@ -299,6 +300,7 @@ function parse(piece) {
299
300
  type = last_type;
300
301
  }
301
302
  } else {
303
+ type = type1;
302
304
  last_type = type;
303
305
  }
304
306
  }
@@ -0,0 +1,13 @@
1
+ <div head -html="title">
2
+ </div>
3
+ <grid body>
4
+ <chat -src="m in msglist">
5
+ <msg class="msg" -src="m"></msg>
6
+ </chat>
7
+ <div textarea>
8
+ <div contenteditable="true" -model="text"></div>
9
+ </div>
10
+ </grid>
11
+ <div foot>
12
+ <btn @click="send()">发送</btn>
13
+ </div>
@@ -0,0 +1,39 @@
1
+
2
+ function msg(elem) {
3
+ care(elem, function (data) {
4
+ if (!data) return;
5
+ var m = JSAM.parse(data);
6
+ if (m) switch (m.type) {
7
+ case "html":
8
+ elem.innerHTML = m.content;
9
+ break;
10
+ default:
11
+ elem.innerText = data;
12
+ }
13
+ })
14
+ }
15
+ function chat(title = '会话窗口') {
16
+ var page = view();
17
+ page.innerHTML = template;
18
+ drag.on(page.firstChild, page);
19
+ resize.on(page);
20
+ renderWithDefaults(page, {
21
+ chat: list,
22
+ title,
23
+ grid,
24
+ msglist: [],
25
+ text: '',
26
+ localid: Math.random(),
27
+ msg,
28
+ send() {
29
+ if (!this.text) return;
30
+ cast(page, "send", JSAM.stringify({
31
+ type: 'html',
32
+ sender: this.localid,
33
+ content: this.text,
34
+ }));
35
+ this.text = '';
36
+ }
37
+ });
38
+ return page;
39
+ }