efront 4.26.1 → 4.27.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.
@@ -0,0 +1,275 @@
1
+ <style>
2
+ & {
3
+ width: 100%;
4
+ height: 100%;
5
+ position: fixed;
6
+ left: 0;
7
+ top: 0;
8
+ right: 0;
9
+ bottom: 0;
10
+ background: #111;
11
+ }
12
+
13
+ dv {
14
+ border: 1px solid;
15
+ width: 240px;
16
+ height: 180px;
17
+ right: 10px;
18
+ bottom: 10px;
19
+ display: block;
20
+ position: absolute;
21
+ color: #fff9;
22
+ background: #222;
23
+ z-index: 1;
24
+
25
+ >span {
26
+ position: relative;
27
+ }
28
+
29
+ &[full] {
30
+ z-index: 0 !important;
31
+ width: auto !important;
32
+ height: auto !important;
33
+ left: 0 !important;
34
+ right: 0 !important;
35
+ bottom: 0 !important;
36
+ top: 0 !important;
37
+ margin: 0 !important;
38
+ padding: 0 !important;
39
+ border: none;
40
+ }
41
+
42
+ &:after {
43
+ display: block;
44
+ content: "";
45
+ left: 0;
46
+ bottom: 0;
47
+ right: 0;
48
+ top: 0;
49
+ position: absolute;
50
+ }
51
+
52
+ >video {
53
+ display: block;
54
+ position: absolute;
55
+ left: 0;
56
+ right: 0;
57
+ bottom: 0;
58
+ top: 0;
59
+ width: 100%;
60
+ height: 100%;
61
+ }
62
+ }
63
+
64
+ btn.button {
65
+ display: block;
66
+ position: absolute;
67
+ width: 60px;
68
+ line-height: 60px;
69
+ height: 60px;
70
+ border-radius: 30px;
71
+ margin: -23px;
72
+ z-index: 2;
73
+ }
74
+
75
+ [accept] {
76
+ left: 50%;
77
+ top: 50%;
78
+ background: #fff2;
79
+ }
80
+
81
+ [hangup] {
82
+ left: 50%;
83
+ bottom: 30px;
84
+ background: #913;
85
+ }
86
+
87
+ [info],
88
+ [error] {
89
+ display: block;
90
+ position: absolute;
91
+ top: 50%;
92
+ z-index: 1;
93
+ left: 0;
94
+ right: 0;
95
+ text-align: center;
96
+ line-height: 40px;
97
+ margin-top: -20px;
98
+ color: #fff;
99
+ }
100
+
101
+ [error] {
102
+ display: none;
103
+ }
104
+
105
+ &[error] {
106
+
107
+ [info],
108
+ [accept] {
109
+ display: none;
110
+ }
111
+
112
+ [error] {
113
+ display: block;
114
+ }
115
+ }
116
+ </style>
117
+ <div>
118
+ <dv full>
119
+ <video playsinline autoplay webkit-playsinline ondblclick="preventDefault"></video>
120
+ <span -bind="remoteUser.name"></span>
121
+ </dv>
122
+ <dv style="opacity: 0">
123
+ <video muted playsinline webkit-playsinline ondblclick="preventDefault"></video>
124
+ <span></span>
125
+ </dv>
126
+ <btn danger hangup @click="hangup">挂断</btn>
127
+ <btn accept -show="isRemote&&!started" @click="accept()">接听</btn>
128
+ <span error>${i18n`无法打开媒体设备`}</span>
129
+ <span info -show="started">
130
+ <span -bind="status()"></span>
131
+ &nbsp;<time></time>
132
+ </span>
133
+ </div>
134
+ <script>
135
+ var chatrtc = new ChatRTC;
136
+ // fullscreen.open();
137
+ var status = function () {
138
+ return acceptTime ? i18n`通话中` : rejectTime ? i18n`无应答` : i18n`正在呼叫`
139
+ };
140
+ var btn = button;
141
+ var dvs;
142
+ var callingStart = new Date, acceptTime = 0;
143
+ var started = false;
144
+ var interval = 0;
145
+ var timeNode = document.createTextNode("");
146
+ var rejectTime = 0;
147
+ care(this, function ([type, sender, data]) {
148
+ if (sender !== remoteUser.id) return;
149
+ switch (type) {
150
+ case "rtc-close":
151
+ if (acceptTime) return remove(this);
152
+ rejectTime = new Date;
153
+ if (remoteOffer) return remove(this);
154
+ break;
155
+ case "rtc-accept":
156
+ acceptTime = new Date;
157
+ chatrtc.setAnswer(data);
158
+ break;
159
+ case "rtc-didate":
160
+ chatrtc.addDidate(data);
161
+ break;
162
+ }
163
+ });
164
+ interval = setInterval(function () {
165
+ var toNum2 = a => a < 10 ? "0" + a : a;
166
+ var now = new Date;
167
+ var time = callingStart;
168
+ if (acceptTime) time = acceptTime;
169
+ var time = (new Date - time) / 1000 | 0;
170
+ if (time > 60 && !acceptTime && !rejectTime) {
171
+ rejectTime = time;
172
+ }
173
+ if (rejectTime && now - rejectTime > 16 * 1000) {
174
+ remove(page);
175
+ }
176
+ var value = [0, 0, 0, 0];
177
+ if (time >= 86400) {
178
+ value[0] = time / 86400 | 0;
179
+ time -= value[0] * 86400;
180
+ }
181
+ if (time >= 3600) {
182
+ value[1] = time / 3600 | 0;
183
+ time -= value[1] * 3600;
184
+ }
185
+ if (time >= 60) {
186
+ value[2] = time / 60 | 0;
187
+ time -= value[2] * 60;
188
+ }
189
+ value[3] = time;
190
+ var [date, ...time] = value;
191
+ if (date) timeNode.nodeValue = i18n`${date}天 ` + time.map(toNum2).join(":");
192
+ else if (time[0]) timeNode.nodeValue = time.map(toNum2).join(":");
193
+ else timeNode.nodeValue = time.slice(1).map(toNum2).join(":");
194
+
195
+ }, 20);
196
+ var time = function (elem) {
197
+ elem.appendChild(timeNode);
198
+ };
199
+ on('remove')(this, async function () {
200
+ await chatrtc.hangup();
201
+ chatrtc.send = null;
202
+ fullscreen.close();
203
+ chatrtc.remote = null;
204
+ chatrtc.local = null;
205
+ clearInterval(interval);
206
+ })
207
+ var canplay = function () {
208
+ var dv = this.parentNode;
209
+ var ratio = Math.min(dv.clientWidth / this.videoWidth, dv.clientHeight / this.videoHeight);
210
+ if (ratio) {
211
+ move.setSize(dv, [this.videoWidth * ratio, this.videoHeight * ratio]);
212
+ dv.style.opacity = 1;
213
+ }
214
+ }
215
+ once('mounted')(this, function () {
216
+ var [dv1, dv2, hangup, accept] = this.children;
217
+ dvs = [dv1, dv2];
218
+ drag.on(dv1, false);
219
+ drag.on(dv2, false);
220
+ drag.on(hangup, false);
221
+ drag.on(accept, false);
222
+ on("dblclick")(dv1, dblclick);
223
+ on("dblclick")(dv2, dblclick);
224
+ var v1 = chatrtc.remote = dv1.firstElementChild;
225
+ var v2 = chatrtc.local = dv2.firstElementChild;
226
+ v1.oncanplay = canplay;
227
+ v2.oncanplay = canplay;
228
+ if (!isRemote) start();
229
+ });
230
+ var accept = async function () {
231
+ await start();
232
+ acceptTime = new Date;
233
+ };
234
+ var onCandidate = function (candidate) {
235
+ cast(page, ["didate", candidate]);
236
+ };
237
+ var start = async function () {
238
+ try {
239
+ if (!remoteOffer) {
240
+ var offer = await chatrtc.call(onCandidate, remoteOffer);
241
+ cast(page, ['offer', offer]);
242
+ }
243
+ else {
244
+ var answer = await chatrtc.call(onCandidate, remoteOffer);
245
+ cast(page, ['accept', answer]);
246
+ }
247
+ }
248
+ catch {
249
+ page.setAttribute('error', '');
250
+ }
251
+ finally {
252
+ started = true;
253
+ }
254
+ render.refresh();
255
+ }
256
+ var page = this;
257
+ var hangup = async function () {
258
+ cast(page, ['hangup']);
259
+ remove(page);
260
+ };
261
+ var dblclick = function (a) {
262
+ if (this.hasAttribute('full')) return;
263
+ var style = this.getAttribute('style');
264
+ if (dvs.length !== 2) style = '';
265
+ dvs.forEach(v => {
266
+ if (v === this) v.setAttribute('full', ''), v.nodrag = true;
267
+ else v.removeAttribute('full'), v.nodrag = false, v.setAttribute('style', style), canplay.call(v);
268
+ });
269
+ };
270
+ this.onback = e => false;
271
+ var preventDefault = e => e.preventDefault();
272
+ var [remoteUser, localUser, remoteOffer] = arguments;
273
+ var isRemote = !!remoteOffer;
274
+
275
+ </script>
@@ -1,3 +1,8 @@
1
+ <style>
2
+ [left] {
3
+ float: left;
4
+ }
5
+ </style>
1
6
  <div head mount>
2
7
  <btn -if="users.length>0" class="menubtn" @click="showList=!showList" type_="showList?'default':'white'">
3
8
  <i></i>
@@ -7,6 +12,7 @@
7
12
  <template -if="user">
8
13
  <span -bind="user.name"></span>
9
14
  &nbsp;<span class="id">(<span -bind="user.id"></span>)</span>
15
+ <a left -if="user.id!==localid" @click="call()">呼叫</a>
10
16
  </template>
11
17
  <template -elseif="title" -src="title"> </template>
12
18
  <close @click="remove()"></close>
@@ -25,6 +25,10 @@ function msg(elem, { m }, parentScopes) {
25
25
  elem.files = files;
26
26
  onclick(elem, clickfile);
27
27
  break;
28
+ case "rtc-video":
29
+ elem.setAttribute('rtc', 'video');
30
+ elem.innerHTML = "视频通话";
31
+ break;
28
32
  default:
29
33
  elem.innerText = m.content;
30
34
  }
@@ -101,6 +105,120 @@ var dragpage = {
101
105
  render.refresh();
102
106
  }
103
107
  }
108
+
109
+ var rtcMap = Object.create(null);
110
+ var getRtc = function (userid) {
111
+ var rtc = rtcMap[userid];
112
+ if (!rtc) rtc = rtcMap[userid] = new ChatRTC;
113
+ return rtc;
114
+ }
115
+ async function pullFileWithRTC(scope, file) {
116
+ var userid = scope.user.id;
117
+ var rtc = getRtc(userid);
118
+ var h = await window.showSaveFilePicker({ suggestedName: file.name });
119
+ var writable = await h.createWritable();
120
+ var channel = await rtc.createChannel();
121
+ channel.binaryType = 'arraybuffer';
122
+ var writed = 0;
123
+ var span = document.createElement('div');
124
+ span.style.textAlign = 'left';
125
+ span.innerText = '接收' + file.name;
126
+ var msg = document.createElement('span');
127
+ msg.style = 'font-size:10px;font-family: Consolas, "Courier New", monospace, sansif;'
128
+ appendChild(span, msg);
129
+ var tipbox = alert(span, false);
130
+ var report = lazy(function () {
131
+ // <!-- console.log("接收端发送",writed); -->
132
+ msg.innerText = ` (${size(file.size, 2)}\\${size(writed, 2)})`;
133
+ var a = new Uint8Array(16);
134
+ var high = writed / 0x100000000 | 0;
135
+ var low = writed & 0xffffffff;
136
+ a[0] = low & 0xff;
137
+ a[1] = low >>> 8 & 0xff;
138
+ a[2] = low >>> 16 & 0xff;
139
+ a[3] = low >>> 24 & 0xff;
140
+ a[4] = high & 0xff;
141
+ a[5] = high >>> 8 & 0xff;
142
+ a[6] = high >>> 16 & 0xff;
143
+ a[7] = high >>> 24 & 0xff;
144
+ channel.send(a);
145
+ }, -60);
146
+ channel.onopen = async function () {
147
+ // <!-- console.log('接收端打开') -->
148
+ report();
149
+ };
150
+ channel.onclose = function () {
151
+ // <!-- console.log('接收端关闭') -->
152
+ if (writed === file.size) tipbox.setText(`接收完成`, 'success');
153
+ else tipbox.setText('接收异常', "error");
154
+ };
155
+ channel.onerror = function (event) {
156
+ // <!-- console.log('接收端异常',event) -->
157
+ };
158
+ var ondate = function (date) {
159
+ scope.send("didate", date, userid);
160
+ };
161
+ var offer = await rtc.init(ondate);
162
+ scope.send('accept', { file: file.id, channel: channel.id, offer })
163
+ channel.onmessage = async function (event) {
164
+ var buff = new Uint8Array(event.data);
165
+ writed += buff.length;
166
+ // <!-- console.log('接收端收到', writed, file.size); -->
167
+ await writable.write(buff);
168
+ report();
169
+ if (writed >= file.size) {
170
+ writable.close();
171
+ }
172
+ }
173
+ }
174
+ /**
175
+ * @param {File} file
176
+ */
177
+ async function pushFileWithRTC(scope, file, msg) {
178
+ var sender = msg.sender;
179
+ var rtc = getRtc(sender);
180
+ var reader = file.stream().getReader();
181
+ var ondate = function (date) {
182
+ scope.send("didate", date, sender);
183
+ }
184
+ var answer = await rtc.init(ondate, msg.offer);
185
+ scope.send('takeup', answer, sender);
186
+ var remote = await rtc.waitChannel();
187
+ remote.binaryType = 'arraybuffer';
188
+ var writed = 0, reported = 0;
189
+ var readed = reader.read();
190
+ var sizeLimit = 65536;
191
+ remote.onmessage = async function (event) {
192
+ var [low, high] = new Uint32Array(event.data);
193
+ reported = high * 0x100000000 + low;
194
+ // <!-- console.log('发送端收到', size(writed), size(reported)); -->
195
+ if (reported < writed) return;
196
+ var readed1 = readed;
197
+ readed = reader.read();
198
+ var { done, value } = await readed1;
199
+ if (done) {
200
+ if (writed < file.size) console.error('发送未完成', size(file.size), size(writed), value);
201
+ remote.close();
202
+ return;
203
+ }
204
+ // <!-- console.log("发送",size(value.length)); -->
205
+ writed += value.length;
206
+ for (var cx = 0, dx = value.length; cx < dx;) {
207
+ remote.send(value.slice(cx, cx += sizeLimit));
208
+ }
209
+ }
210
+ remote.onclose = function () {
211
+ // <!-- console.log("发送端关闭") -->
212
+ }
213
+ remote.onerror = function (event) {
214
+ // <!-- console.log("发送端异常",event) -->
215
+ }
216
+ remote.onopen = async function () {
217
+ // <!-- console.log("发送端打开") -->
218
+ };
219
+ }
220
+
221
+
104
222
  function chat(title = '会话窗口') {
105
223
  var page = view();
106
224
  page.innerHTML = template;
@@ -122,12 +240,36 @@ function chat(title = '会话窗口') {
122
240
  ps.totalunread += msgs.length;
123
241
  }
124
242
  }
243
+ var msgTemp = Object.create(null);
125
244
  page.push = function (msgs) {
126
245
  var { msglist } = ps;
127
246
  var userMap = null;
247
+ var cached = [], cachedi = 0;
128
248
  msgs = msgs.filter(m => {
129
249
  if (!m) return false;
130
- if (isString(m)) return true;
250
+ if (isString(m)) {
251
+ if (/^\|/.test(m)) {
252
+ var a = /^\|(\d+)\|(\d+)\|(\d+)\|/.exec(m);
253
+ if (a) var [, msgid, total, index] = a;
254
+ total = +total, index = +index, msgid = +msgid;
255
+ var tmp = msgTemp[msgid];
256
+ if (!tmp) {
257
+ tmp = msgTemp[msgid] = Array(total);
258
+ tmp.count = 0;
259
+ }
260
+ if (!tmp[index]) {
261
+ tmp[index] = m.slice(a.index + a[0].length);
262
+ tmp.count++;
263
+ }
264
+ if (tmp.count === total) {
265
+ cached.push([cachedi, tmp.join('')]);
266
+ delete msgTemp[msgid];
267
+ }
268
+ return false;
269
+ }
270
+ cachedi++;
271
+ return true;
272
+ }
131
273
  switch (m.type) {
132
274
  case 'user':
133
275
  if (!userMap) userMap = Object.create(null);
@@ -136,7 +278,11 @@ function chat(title = '会话窗口') {
136
278
  break;
137
279
  }
138
280
  return false;
139
- }).map(m => JSAM.parse(encode62.packdecode(m))).filter(m => {
281
+ });
282
+ backEach(cached, function ([i, m]) {
283
+ msgs.splice(i, 0, m);
284
+ });
285
+ msgs = msgs.map(m => JSAM.parse(encode62.packdecode(m))).filter(m => {
140
286
  if (m.type === 'accept') {
141
287
  ps.pushFile(m.content);
142
288
  return false;
@@ -152,6 +298,30 @@ function chat(title = '会话窗口') {
152
298
  var msgMap = Object.create(null);
153
299
  for (var m of msgs) {
154
300
  var { sender } = m;
301
+ if (m.type === 'rtc-video') {
302
+ }
303
+ switch (m.type) {
304
+ case "rtc-close":
305
+ case "rtc-accept":
306
+ case "rtc-didate":
307
+ if (ps.calling) cast(ps.calling, [m.type, m.sender, m.content]);
308
+ continue;
309
+ case "didate":
310
+ var rtc = rtcMap[m.sender];
311
+ if (rtc) rtc.addDidate(m.content);
312
+ continue;
313
+ case "takeup":
314
+ var rtc = rtcMap[m.sender];
315
+ if (rtc) rtc.setAnswer(m.content);
316
+ continue;
317
+ case "rtc-video":
318
+ if (ps.calling) {
319
+ ps.send("rtc-close", i18n`正在通话中..`, m.sender);
320
+ continue;
321
+ }
322
+ ps.call(sender, m.content);
323
+ break;
324
+ }
155
325
  if (sender) {
156
326
  if (!msgMap[sender]) msgMap[sender] = [];
157
327
  msgMap[sender].push(m);
@@ -181,6 +351,25 @@ function chat(title = '会话窗口') {
181
351
  page.setAttribute('ng-class', "{showList:showList}");
182
352
  var fid = 0;
183
353
  var filesMap = Object.create(null);
354
+ function rtcMessage([type, data]) {
355
+ switch (type) {
356
+ case "offer":
357
+ ps.send('rtc-video', data);
358
+ break;
359
+ case "hangup":
360
+ ps.send('rtc-close', "", ps.remote);
361
+ break;
362
+ case "accept":
363
+ ps.send('rtc-accept', data, ps.remote);
364
+ break;
365
+ case "didate":
366
+ ps.send('rtc-didate', data, ps.remote);
367
+ break;
368
+ }
369
+ }
370
+ function send1(msg, sendto) {
371
+ cast(page, 'send', [sendto, msg]);
372
+ }
184
373
  var ps = {
185
374
  chat: zimoli$list,
186
375
  title,
@@ -188,9 +377,33 @@ function chat(title = '会话窗口') {
188
377
  showList: 0,
189
378
  users,
190
379
  text: '',
380
+ calling: null,
381
+ remote: null,
191
382
  localid,
192
383
  totalunread: 0,
193
384
  _user: null,
385
+ call(remote = this.user, offer) {
386
+ if (this.calling) return;
387
+ this.remote = isObject(remote) ? remote.id : remote;
388
+ if (typeof remote === 'string') {
389
+ for (var u of this.users) {
390
+ if (u.id === remote) {
391
+ remote = u;
392
+ break;
393
+ }
394
+ }
395
+ }
396
+ if (!remote) return;
397
+ var c = chatRtc(remote, this.localid, offer);
398
+ this.calling = c;
399
+
400
+ on('remove')(c, function () {
401
+ ps.calling = null;
402
+ ps.remote = null;
403
+ })
404
+ care(c, rtcMessage);
405
+ popup(c);
406
+ },
194
407
  fileIcon: shapes$file,
195
408
  set user(v) {
196
409
  if (!v.msglist) v.msglist = []
@@ -209,9 +422,14 @@ function chat(title = '会话窗口') {
209
422
  remove(page);
210
423
  },
211
424
  async pullFile(f) {
425
+ if (!f) return;
426
+ if (f.rtc && ChatRTC.enabled && window.showSaveFilePicker) {
427
+ return pullFileWithRTC(this, f);
428
+ }
212
429
  cast(page, 'pullfile', f);
213
430
  },
214
431
  async pushFile(msg) {
432
+ if (msg.offer && ChatRTC.enabled) return pushFileWithRTC(this, filesMap[msg.file], msg);
215
433
  cast(page, 'pushfile', [msg.channel, filesMap[msg.file]]);
216
434
  },
217
435
  async chooseFile() {
@@ -239,7 +457,7 @@ function chat(title = '会话窗口') {
239
457
  f.icon = canvas.toDataURL();
240
458
  URL.revokeObjectURL(u);
241
459
  }
242
- flist.push({ name: f.name, icon: f.icon, size: f.size, id: ++fid, mtime: +f.lastModified });
460
+ flist.push({ name: f.name, rtc: ChatRTC.enabled, icon: f.icon, size: f.size, id: ++fid, mtime: +f.lastModified });
243
461
  filesMap[fid] = f;
244
462
  }
245
463
  return this.send('file', flist);
@@ -252,22 +470,41 @@ function chat(title = '会话窗口') {
252
470
  body.resizeCell(textarea, 'top', textarea.clientHeight - targetHeight - 2);
253
471
  },
254
472
 
255
- send(type, content) {
256
- if (!content) return;
473
+ send(type, content, sendto = page.userid) {
257
474
  var msg = {
258
475
  type,
259
476
  sender: this.localid,
260
477
  content,
261
478
  };
262
479
  var data = JSAM.stringify(msg);
263
- if (data.length > 2000) {
480
+ data = encode62.packencode(data);
481
+ if (data.length > 16000) {
264
482
  return alert("信息太长,无法发送!");
265
483
  }
266
- if (this.user && this.user.id !== this.localid && type !== "accept") {
484
+ if (this.user && this.user.id !== this.localid) a: {
485
+ switch (type) {
486
+ case "accept":
487
+ case "didate":
488
+ case "takeup":
489
+ case "rtc-close":
490
+ case "rtc-accept":
491
+ case "rtc-didate":
492
+ break a;
493
+ }
494
+ if (!content) return;
267
495
  addToMsgList(this.msglist, [msg]);
268
496
  }
269
- data = encode62.packencode(data);
270
- cast(page, "send", data);
497
+ if (data.length > 2000) {
498
+ var count = Math.ceil(data.length / 2000);
499
+ var msgid = Date.now().toString().slice(-8) + "|" + count + "|";
500
+ for (var cx = 0, ci = 0, dx = data.length; cx < dx;) {
501
+ var d = data.slice(cx, cx += 2000);
502
+ send1("|" + msgid + ci++ + "|" + d, sendto);
503
+ }
504
+ }
505
+ else {
506
+ send1(data, sendto);
507
+ }
271
508
  this.body.lastElementChild.focus();
272
509
  this.text = '';
273
510
  }
@@ -166,6 +166,10 @@ msg {
166
166
  background-color: #77ddaa;
167
167
  color: #333;
168
168
  }
169
+
170
+ &[rtc] {
171
+ color: #0006;
172
+ }
169
173
  }
170
174
 
171
175
  msg[files] {
@@ -17,7 +17,6 @@ var getOffset = function (e) {
17
17
  };
18
18
 
19
19
  var getMouse = function (e) {
20
- console.log(e)
21
20
  return [e.clientX, e.clientY];
22
21
  };
23
22
  var z;
@@ -63,6 +62,7 @@ function drag(target, initialEvent, preventOverflow, isMovingSource) {
63
62
  var saved_height = target.outerHeight;
64
63
  }
65
64
  var extraClones;
65
+ var tgz = target.style?.zIndex;
66
66
  var mousemove = function (event) {
67
67
  if (+event.moveLocked === 1) return;
68
68
  if (/resize/i.test(getComputedStyle(document.body).cursor)) return;
@@ -76,10 +76,12 @@ function drag(target, initialEvent, preventOverflow, isMovingSource) {
76
76
  z = zIndex(0) + 1;
77
77
  addZIndex(clone);
78
78
  appendChild(document.body, clone);
79
+ tgz = null;
79
80
  } else {
80
81
  clone = target;
81
82
  extraTargets = [];
82
83
  if (target.style) css(target, { zIndex: z });
84
+ else tgz = null;
83
85
  }
84
86
  drag.shadow = clone;
85
87
  var [clone_left, clone_top] = getOffset(clone);
@@ -112,6 +114,7 @@ function drag(target, initialEvent, preventOverflow, isMovingSource) {
112
114
  if (clone !== target) remove(clone), css(target, { opacity: saved_opacity, filter: saved_filter });
113
115
  remove(extraClones);
114
116
  extraTargets.map((target, cx) => css(target, extraStyles[cx]));
117
+ if (tgz != null) css(target, { zIndex: tgz });
115
118
  if (saved_delta.ing) target.removeAttribute("dragging"), dispatch("dragend", target);
116
119
  drag.target = null;
117
120
  saved_delta = null;
@@ -151,9 +154,11 @@ drag.on = function (target, actionTarget = target.dragTarget) {
151
154
  var _mousedrag = mousedrag;
152
155
  var _touchdrag = touchdrag;
153
156
  }
154
- onmousedown(actionTarget || target, setZIndex);
155
- ontouchstart(actionTarget || target, setZIndex);
156
- on("drop")(actionTarget || target, setZIndex);
157
+ if (actionTarget !== false) {
158
+ onmousedown(actionTarget || target, setZIndex);
159
+ ontouchstart(actionTarget || target, setZIndex);
160
+ on("drop")(actionTarget || target, setZIndex);
161
+ }
157
162
  onmousedown(target, _mousedrag);
158
163
  ontouchstart(target, _touchdrag);
159
164
  };