efront 3.32.0 → 3.33.1

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.
@@ -0,0 +1,5 @@
1
+ function ArrayFillApply(size, item) {
2
+ var result = Array(size);
3
+ for (var cx = 0; cx < size; cx++)result[cx] = item;
4
+ return result;
5
+ }
@@ -0,0 +1,6 @@
1
+ var backEach = function (arr, run, context) {
2
+ for (var cx = arr.length - 1; cx >= 0; cx--) {
3
+ run.call(context, arr[cx], cx, arr);
4
+ }
5
+ };
6
+ module.exports = backEach;
@@ -1,8 +1,10 @@
1
1
  function removeFromList(list, item) {
2
- for (var cx = list.length - 1; cx >= 0; cx--) {
3
- if (list[cx] === item) {
4
- list.splice(cx, 1);
5
- }
2
+ var count = 0;
3
+ var cx = list.indexOf(item);
4
+ while (cx >= 0) {
5
+ list.splice(cx, 1);
6
+ count++;
7
+ cx = list.indexOf(item, cx);
6
8
  }
7
- return list;
9
+ return count;
8
10
  }
@@ -0,0 +1,3 @@
1
+ var a = [1, 2, 3];
2
+ assert(removeFromList(a, 2), 1);
3
+ assert(a, [1, 3]);
@@ -4,15 +4,15 @@ function serialize(map) {
4
4
  for (var cx = 1, dx = arguments.length; cx < dx; cx++) {
5
5
  var a = arguments[cx];
6
6
  if (typeof a === 'string') {
7
- if (!spliter) spliter = a;
8
- else if (!equals) equals = a;
7
+ if (spliter === undefined) spliter = a;
8
+ else if (equals === undefined) equals = a;
9
9
  }
10
10
  else {
11
11
  encode = a;
12
12
  }
13
13
  }
14
- if (!spliter) spliter = '&';
15
- if (!equals) equals = '=';
14
+ if (spliter === undefined) spliter = '&';
15
+ if (equals === undefined) equals = '=';
16
16
  if (encode === void 0) encode = spliter === "&" && equals === "=" ? encodeURIComponent : trim;
17
17
  var result = [];
18
18
  for (var k in map) {
@@ -16,7 +16,7 @@ function map(f, o) {
16
16
  } else {
17
17
  for (var cx in this) {
18
18
  if (!isFinite(cx)) break;
19
- res[cx] = f.call(o, this[cx], cx, this);
19
+ res[cx] = f.call(o, this[cx], +cx, this);
20
20
  }
21
21
  }
22
22
  return res;
@@ -28,7 +28,7 @@ function forEach(f, o) {
28
28
  }
29
29
  for (var cx in this) {
30
30
  if (!isFinite(cx)) break;
31
- f.call(o, this[cx], cx, this);
31
+ f.call(o, this[cx], +cx, this);
32
32
  }
33
33
  }
34
34
  function filter(f, o) {
@@ -39,7 +39,7 @@ function filter(f, o) {
39
39
  }
40
40
  for (var cx in this) {
41
41
  if (!isFinite(cx)) break;
42
- if (f.call(o, this[cx], cx, this))
42
+ if (f.call(o, this[cx], +cx, this))
43
43
  result.push(this[cx]);
44
44
  }
45
45
  return result;
@@ -48,7 +48,7 @@ function indexOf(searchElement, fromIndex = 0) {
48
48
  if (fromIndex < 0) fromIndex += this.length;
49
49
  if (fromIndex < 0) fromIndex = 0;
50
50
  for (var cx = fromIndex, dx = this.length; cx < dx; cx++) {
51
- if (cx in this && this[cx] === searchElement) return cx;
51
+ if (cx in this && this[cx] === searchElement) return +cx;
52
52
  }
53
53
  return -1;
54
54
  }
@@ -65,16 +65,17 @@ var keys = function keys(object) {
65
65
  }
66
66
  return result;
67
67
  };
68
- if (![].map) Array.prototype.map = map;
69
- if (![].forEach) Array.prototype.forEach = forEach;
70
- if (![].indexOf) Array.prototype.indexOf = indexOf;
71
- if (![].filter) Array.prototype.filter = filter;
68
+ var ArrayProto = Array.prototype;
69
+ if (!ArrayProto.map) ArrayProto.map = map;
70
+ if (!ArrayProto.forEach) ArrayProto.forEach = forEach;
71
+ if (!ArrayProto.indexOf) ArrayProto.indexOf = indexOf;
72
+ if (!ArrayProto.filter) ArrayProto.filter = filter;
72
73
  if (!"".trim) String.prototype.trim = trim;
73
74
  if (!Object.keys) Object.keys = keys;
74
75
  if (!Object.create) Object.create = function (object) {
75
76
  return { __proto__: object };
76
77
  };
77
- if (!function () { }.bind) Function.prototype.bind = function (context) {
78
+ if (!Function.prototype.bind) Function.prototype.bind = function (context) {
78
79
  var args = [].slice.call(arguments, 1);
79
80
  var f = this;
80
81
  return function () {
@@ -1,8 +1,31 @@
1
- <div head>
2
- <template -src="title">
1
+ <div head mount>
2
+ <btn -if="users.length>0" class="menubtn" @click="showList=!showList" type_="showList?'default':'white'">
3
+ <i></i>
4
+ <i></i>
5
+ <i></i>
6
+ </btn>
7
+ <template -if="user">
8
+ <span -bind="user.name"></span>
9
+ &nbsp;<span class="id">(<span -bind="user.id"></span>)</span>
3
10
  </template>
11
+ <template -elseif="title" -src="title"> </template>
4
12
  <close @click="remove()"></close>
5
13
  </div>
14
+ <list -if="users.length>0" -src="u in users">
15
+ <btn class="user" @click="user=u" type_="u===user?'default':'white'">
16
+ <avatar -if="user.icon" -style="{'background-image':'url(\'icons/'+u.icon+'.ico\')'}"></avatar>
17
+ <avatar -else>
18
+ </avatar>
19
+ <span -text="u.name"></span>&nbsp;
20
+ <div class="unread" -if="u.msgread<u.msglist?.length">
21
+ <span -bind="u.msglist.length-u.msgread"></span>
22
+ </div>
23
+ <div>
24
+ <span class="id" -text="u.id"></span>
25
+ </div>
26
+ <span class="local" -if="u.id===localid">本机</span>
27
+ </btn>
28
+ </list>
6
29
  <grid #body disabled>
7
30
  <chat -src="m in msglist">
8
31
  <padding>
@@ -11,9 +34,15 @@
11
34
  </padding>
12
35
  </chat>
13
36
  <div textarea @mousedown="this.firstChild.focus()">
14
- <div @keydown.alt.enter="send()" contenteditable="true" -model="text"></div>
37
+ <div @keydown.alt.enter="send('html',text)" contenteditable="true" -model="text"></div>
15
38
  </div>
16
39
  </grid>
17
40
  <div foot>
18
- <btn @click="send();">发送</btn>
41
+ <a class="file" @click="chooseFile()" -if="user">
42
+ <template -src="fileIcon"></template>
43
+ <span>
44
+ 文件
45
+ </span>
46
+ </a>
47
+ <a @click="send('html',text);">发送</a>
19
48
  </div>
@@ -1,8 +1,16 @@
1
+ function clickfile(event) {
2
+ var target = getTargetIn(this, event.target, false);
3
+ var children = this.children;
4
+ for (var cx = 0, dx = children.length; cx < dx; cx++) {
5
+ var c = children[cx];
6
+ if (c === target) {
7
+ break;
8
+ }
9
+ }
10
+ this.$eval(`pullFile(m.content[${cx}])`);
11
+ }
1
12
 
2
- function msg(elem, { m: data }, parentScopes) {
3
- if (!data) return;
4
- data = encode62.timedecode(data);
5
- var m = JSAM.parse(data);
13
+ function msg(elem, { m }, parentScopes) {
6
14
  if (m.sender === parentScopes[parentScopes.length - 1].localid) {
7
15
  elem.setAttribute("self", "");
8
16
  }
@@ -10,61 +18,217 @@ function msg(elem, { m: data }, parentScopes) {
10
18
  case "html":
11
19
  elem.innerHTML = m.content;
12
20
  break;
21
+ case "file":
22
+ var files = m.content;
23
+ elem.setAttribute("files", '');
24
+ elem.innerHTML = files.map(f => `<a class=file>${shapes$file}${f.name}</a>`).join("");
25
+ elem.files = files;
26
+ onclick(elem, clickfile);
27
+ break;
13
28
  default:
14
- elem.innerText = data;
29
+ elem.innerText = m.content;
15
30
  }
16
31
  }
17
- var userManager = function (users, m) {
32
+ var userManager = function (users, map) {
18
33
  for (var cx = 0, dx = users.length; cx < dx; cx++) {
19
34
  var u = users[cx];
20
- if (u.id === m.id) {
35
+ if (u.id in map) {
36
+ var m = map[u.id];
21
37
  if (m.deleted) users.splice(cx, 1);
22
38
  else Object.assign(u, m);
39
+ delete map[u.id];
23
40
  return;
24
41
  }
25
42
  }
26
- if (!m.deleted) users.push(m);
43
+ var ms = Object.keys(map).map(k => map[k]);
44
+ for (var u of ms) u.msgread = 0;
45
+ users.push.apply(users, ms);
27
46
  };
47
+ var saved_event, moving = null;
48
+ var dragpage = {
49
+ start(event) {
50
+ moving = null;
51
+ saved_event = null;
52
+ if (getTargetIn(a => /^(msg)$/i.test(a.tagName), event.target)) return;
53
+ if (!this.$scope.users.length) return;
54
+ saved_event = event;
55
+ },
56
+ move(event) {
57
+ if (!saved_event) return;
58
+ if (event.moveLocked) return;
59
+ var target = this;
60
+ if (target.hasAttribute('resizing') || target.hasAttribute("dragging")) {
61
+ saved_event = null;
62
+ return;
63
+ }
64
+ var deltaX = saved_event.clientX - event.clientX;
65
+ var deltaY = saved_event.clientY - event.clientY;
66
+ event.preventDefault();
67
+ if (!moving) {
68
+ if (!onclick.preventClick) return;
69
+ if (Math.abs(deltaY) * 1.5 >= Math.abs(deltaX)) {
70
+ saved_event = null;
71
+ return;
72
+ }
73
+ moving = {
74
+ restX: parseFloat(getComputedStyle(target).paddingLeft) - saved_event.clientX,
75
+ }
76
+ target.style.transition = 'none';
77
+ }
78
+ event.moveLocked = true;
79
+ moving.deltaX = deltaX;
80
+ var left = event.clientX + moving.restX;
81
+ if (left < 0) left = 0;
82
+ var menuWidth = target.children[1].offsetWidth;
83
+ if (left > menuWidth) left = menuWidth;
84
+ target.style.paddingLeft = fromOffset(left);
85
+ },
86
+ end() {
87
+ if (!moving) return;
88
+ var target = this;
89
+ target.style.transition = "";
90
+ var left = freeOffset(target.style.paddingLeft);
91
+ var menuWidth = target.children[1].offsetWidth;
92
+ target.style.paddingLeft = '';
93
+ if (moving.deltaX < 0 && left > menuWidth * .1 || moving.deltaX > 0 && left > menuWidth * .9 || !moving.deltaX && left > menuWidth >> 1) {
94
+ target.$scope.showList = true;
95
+ addClass(target, "showList")
96
+ }
97
+ else {
98
+ target.$scope.showList = false;
99
+ removeClass(target, "showList")
100
+ }
101
+ render.refresh();
102
+ }
103
+ }
28
104
  function chat(title = '会话窗口') {
29
105
  var page = view();
30
106
  page.innerHTML = template;
31
107
  drag.on(page.firstElementChild, page);
32
108
  resize.on(page);
33
- var localid = Date.now() + Math.sin(Math.random());
109
+ var localid = title.id || (Date.now() / 1000 | 0) + Math.sin(Math.random());
34
110
  var users = [];
111
+ var addToMsgList = function (list, msgs) {
112
+ list.push.apply(list, msgs);
113
+ if (list === page.$scope.msglist) {
114
+ var chat = page.querySelector("chat");
115
+ var lastmsg = chat.getLastVisibleElement();
116
+ if (msgs.length && (!lastmsg || lastmsg.offsetTop + lastmsg.offsetHeight === chat.scrollHeight)) {
117
+ chat.go(list.length ? list.length - 1 : 0);
118
+ }
119
+ if (page.$scope.user) page.$scope.user.msgread = list.length;
120
+ }
121
+ else {
122
+ page.$scope.totalunread += msgs.length;
123
+ }
124
+ }
35
125
  page.push = function (msgs) {
36
126
  var { msglist } = this.$scope;
127
+ var userMap = null;
37
128
  msgs = msgs.filter(m => {
38
129
  if (!m) return false;
39
130
  if (isString(m)) return true;
40
131
  switch (m.type) {
41
132
  case 'user':
42
- userManager(users, m);
133
+ if (!userMap) userMap = Object.create(null);
134
+ if (!m.icon) m.icon = m.id.replace(/[\.\d]+$/, '');
135
+ userMap[m.id] = m;
43
136
  break;
44
137
  }
45
138
  return false;
139
+ }).map(m => JSAM.parse(encode62.timedecode(m))).filter(m => {
140
+ if (m.type === 'accept') {
141
+ page.$scope.pushFile(m.content);
142
+ return false;
143
+ }
144
+ return true;
46
145
  });
47
- msglist.push.apply(msglist, msgs);
48
- var chat = page.querySelector("chat");
49
- var lastmsg = chat.getLastVisibleElement();
50
- if (msgs.length && (!lastmsg || lastmsg.offsetTop + lastmsg.offsetHeight === chat.scrollHeight)) {
51
- chat.go(msglist.length ? msglist.length - 1 : 0);
146
+ if (userMap) {
147
+ userManager(users, userMap);
148
+ if (users.indexOf(page.$scope.user) < 0) page.$scope.user = users[0];
149
+ if (users.length > 0 && page.$scope.showList === 0) page.$scope.showList = true;
150
+ }
151
+ if (msgs.length) {
152
+ var msgMap = Object.create(null);
153
+ for (var m of msgs) {
154
+ var { sender } = m;
155
+ if (sender) {
156
+ if (!msgMap[sender]) msgMap[sender] = [];
157
+ msgMap[sender].push(m);
158
+ }
159
+ }
160
+ if (users.length) for (var u of users) {
161
+ if (u.id in msgMap) {
162
+ if (!u.msglist) u.msglist = [];
163
+ addToMsgList(u.msglist, msgMap[u.id]);
164
+ }
165
+ }
166
+ else {
167
+ addToMsgList(msglist, msgs);
168
+ }
52
169
  }
53
170
  };
54
171
  page.renders = [function () {
55
172
  this.$scope.resize(this.$scope.body);
56
173
  }];
174
+ page.localid = localid;
175
+ Object.defineProperty(page, 'userid', {
176
+ get() {
177
+ var user = this.$scope.user;
178
+ if (user) return user.id;
179
+ }
180
+ });
181
+ page.setAttribute('ng-class', "{showList:showList}");
182
+ var fid = 0;
183
+ var filesMap = Object.create(null);
57
184
  renderWithDefaults(page, {
58
185
  chat: list,
59
186
  title,
60
187
  msglist: [],
188
+ showList: 0,
61
189
  users,
62
190
  text: '',
63
191
  localid,
192
+ totalunread: 0,
193
+ _user: null,
194
+ fileIcon: shapes$file,
195
+ set user(v) {
196
+ if (!v.msglist) v.msglist = []
197
+ if (v.msgread !== v.msglist.length) {
198
+ v.msgread = v.msglist.length;
199
+ this.totalunread -= v.msglist.length - v.msgread;
200
+ }
201
+ this.msglist = v.msglist;
202
+ this._user = v;
203
+ },
204
+ get user() {
205
+ return this._user;
206
+ },
64
207
  msg,
65
208
  remove() {
66
209
  remove(page);
67
210
  },
211
+ async pullFile(f) {
212
+ cast(page, 'pullfile', f);
213
+ },
214
+ async pushFile(msg) {
215
+ cast(page, 'pushfile', [msg.channel, filesMap[msg.file]]);
216
+ },
217
+ async chooseFile() {
218
+ /**
219
+ * @type {[:File]}
220
+ */
221
+ var files = await chooseFile('*.*', true);
222
+ this.sendFiles(files);
223
+ },
224
+ sendFiles(files) {
225
+ var flist = [];
226
+ for (var f of files) {
227
+ flist.push({ name: f.name, size: f.size, id: ++fid, mtime: +f.lastModified });
228
+ filesMap[fid] = f;
229
+ }
230
+ return this.send('file', flist);
231
+ },
68
232
  resize(body) {
69
233
  var textarea = body.querySelector("[textarea]");
70
234
  var lastElementChild = textarea.lastElementChild;
@@ -72,22 +236,36 @@ function chat(title = '会话窗口') {
72
236
  if (Math.abs(targetHeight - textarea.clientHeight - textarea.clientTop) < 2) return;
73
237
  body.resizeCell(textarea, 'top', textarea.clientHeight - targetHeight - 2);
74
238
  },
75
- send() {
76
- if (!this.text) return;
77
- var data = JSAM.stringify({
78
- type: 'html',
79
- sender: this.localid,
80
- content: this.text,
81
- });
82
239
 
83
- data = encode62.timeencode(data);
84
- if (this.text.length > 2000) {
240
+ send(type, content) {
241
+ if (!content) return;
242
+ var msg = {
243
+ type,
244
+ sender: this.localid,
245
+ content,
246
+ };
247
+ var data = JSAM.stringify(msg);
248
+ if (data.length > 2000) {
85
249
  return alert("信息太长,无法发送!");
86
250
  }
251
+ if (this.user && this.user.id !== this.localid) {
252
+ addToMsgList(this.msglist, [msg]);
253
+ }
254
+ data = encode62.timeencode(data);
87
255
  cast(page, "send", data);
88
256
  this.body.lastElementChild.focus();
89
257
  this.text = '';
90
258
  }
91
259
  });
260
+ var headHeight = 0;
261
+ resizingList.set(page, function () {
262
+ var height = page.firstElementChild.offsetHeight;
263
+ if (height !== headHeight) {
264
+ headHeight = height;
265
+ css(page.firstElementChild, { marginBottom: fromOffset(-headHeight) });
266
+ css(page.$scope.body.firstElementChild, { paddingTop: fromOffset(headHeight) });
267
+ }
268
+ });
269
+ moveupon(page, dragpage);
92
270
  return page;
93
271
  }