efront 3.26.8 → 3.26.14

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 (66) hide show
  1. package/apps/index.jsp +2 -2
  2. package/apps/pivot/dht/list.js +53 -0
  3. package/apps/pivot/index.html +3 -1
  4. package/apps/pivot/main.js +1 -0
  5. package/apps/pivot/main.less +3 -0
  6. package/apps/pivot/wow/root.js +138 -104
  7. package/apps/pivot/wow/root.less +1 -62
  8. package/coms/basic/Task.js +51 -0
  9. package/coms/basic/cross_.js +8 -0
  10. package/coms/basic/keys.js +3 -4
  11. package/coms/basic/loader.js +42 -17
  12. package/coms/basic/submit_.js +6 -3
  13. package/coms/explorer/Explorer.js +85 -0
  14. package/coms/explorer/context.js +205 -0
  15. package/coms/explorer/deepcp.js +48 -0
  16. package/{apps/pivot/wow → coms/explorer}/edit.html +1 -1
  17. package/{apps/pivot/wow → coms/explorer}/edit.js +17 -9
  18. package/coms/explorer/fileitem.html +8 -0
  19. package/coms/explorer/fileitem.js +34 -0
  20. package/coms/explorer/fileitem.less +65 -0
  21. package/coms/explorer/filetip.js +10 -0
  22. package/coms/explorer/filetip.less +5 -0
  23. package/coms/explorer/main.html +8 -0
  24. package/coms/explorer/main.js +215 -0
  25. package/coms/explorer/main.less +78 -0
  26. package/coms/frame/route.js +1 -1
  27. package/coms/shapes/file.html +9 -0
  28. package/coms/shapes/folder.html +7 -0
  29. package/coms/zimoli/Cleanup.js +9 -8
  30. package/coms/zimoli/arriswise.js +5 -4
  31. package/coms/zimoli/attr.js +2 -0
  32. package/coms/zimoli/bindGlobalkey.js +37 -0
  33. package/coms/zimoli/confirm.js +8 -8
  34. package/coms/zimoli/confirm.less +6 -80
  35. package/coms/zimoli/container.js +19 -6
  36. package/coms/zimoli/contextmenu.js +35 -15
  37. package/coms/zimoli/drag.js +7 -3
  38. package/coms/zimoli/field.html +1 -1
  39. package/coms/zimoli/field.js +8 -2
  40. package/coms/zimoli/field.less +0 -1
  41. package/coms/zimoli/getChanges.js +1 -0
  42. package/coms/zimoli/list.js +44 -33
  43. package/coms/zimoli/menu.js +1 -24
  44. package/coms/zimoli/menuItem.html +4 -1
  45. package/coms/zimoli/menuList.js +54 -104
  46. package/coms/zimoli/menuList.less +1 -0
  47. package/coms/zimoli/moveupon.js +2 -2
  48. package/coms/zimoli/overpos.js +7 -0
  49. package/coms/zimoli/popup.js +22 -27
  50. package/coms/zimoli/prompt.js +43 -5
  51. package/coms/zimoli/prompt.less +23 -0
  52. package/coms/zimoli/render.js +149 -107
  53. package/coms/zimoli/resize.js +12 -5
  54. package/coms/zimoli/rootElements.js +15 -1
  55. package/coms/zimoli/view.js +33 -0
  56. package/coms/zimoli/view.less +8 -8
  57. package/coms/zimoli/yousure.js +53 -0
  58. package/coms/zimoli/yousure.less +4 -0
  59. package/coms/zimoli/zimoli.js +10 -6
  60. package/package.json +1 -1
  61. package/public/efront.js +1 -1
  62. package/apps/pivot/wow/root.html +0 -10
  63. package/coms/zimoli/explorer.html +0 -5
  64. package/coms/zimoli/explorer.js +0 -8
  65. package/coms/zimoli/explorer.less +0 -18
  66. package/coms/zimoli/explorer_test.js +0 -4
@@ -0,0 +1,85 @@
1
+ class Explorer {
2
+ pathlist = [];
3
+ selected = [];
4
+ data = [];
5
+ get copyed() { return copyed; };
6
+ }
7
+ var copyed = [];
8
+ var e = Explorer.prototype;
9
+ e.fileitem = explorer$fileitem;
10
+ e.hasName = function (name) {
11
+ for (var d of this.data) if (d.name === name && !d.cut) return true;
12
+ return false;
13
+ }
14
+ e.load = function (p) { return [] }
15
+ e.open = async function (p) {
16
+ if (p) {
17
+ if (!p.isfolder) return;
18
+ this.pathlist.push(p.name);
19
+ }
20
+ p = "/" + this.pathlist.join("/").replace(/^\/+|\/+$/g, '');
21
+ var cutedMap = Object.create(null);
22
+ var selected = Object.create(null);
23
+ for (var s of this.selected) selected[s.url] = true;
24
+ for (var s of this.copyed) cutedMap[s.url] = s.cut;
25
+ var files = await this.load(p);
26
+ for (var f of files) {
27
+ if (cutedMap[f.url]) f.cut = true;
28
+ if (selected[f.url]) f.selected = true;
29
+ }
30
+ if (files) this.data = files.sort(function (a, b) {
31
+ return sortname(a.name, b.name);
32
+ }).sort(function (a, b) {
33
+ return b.isfolder - a.isfolder;
34
+ });
35
+ this.selected = files.filter(f => f.selected);
36
+ }
37
+ e.delete = function () { alert("无法删除!") }
38
+ e.mov = function () { alert("无法移动!") }
39
+ e.copy = function () { alert("无法复制!") }
40
+ e.read = function () { alert("无法读取文件内容!") }
41
+ e.rename = function () { alert("无法重命名!") }
42
+ e.upload = function () { alert("添加失败!") }
43
+ e.getToken = function () { }
44
+ e.uploadAll = async function (files) {
45
+ var $scope = this;
46
+ var dist = $scope.pathlist.join("/");
47
+ dist = dist.replace(/^\/+|\/+$/, '') + "/";
48
+ await queue.call(files, function (f) {
49
+ return $scope.upload(f, dist);
50
+ });
51
+ $scope.open();
52
+ }
53
+
54
+ e.toActive = function (e) {
55
+ var plattice = this.listview;
56
+ return getTargetIn(e => e.parentNode && e.parentNode.parentNode === plattice, e.target);
57
+ }
58
+ e.unsetActive = function (event, file) {
59
+ if (onclick.preventClick) return;
60
+ var e = this.toActive(event);
61
+ if (!e) return;
62
+ if (file.selected === 1) {
63
+ file.selected = true;
64
+ return;
65
+ }
66
+ for (var s of this.selected) {
67
+ s.selected = s === file;
68
+ }
69
+ this.selected = [file];
70
+ }
71
+ e.setActive = function (event, file) {
72
+ var e = this.toActive(event);
73
+ if (!e || !file.selected) {
74
+ if (!event.ctrlKey) {
75
+ for (var s of this.selected) {
76
+ s.selected = false;
77
+ }
78
+ this.selected = [];
79
+ }
80
+ }
81
+ if (e && !file.selected) {
82
+ file.selected = 1;
83
+ if (this.selected.indexOf(file) < 0) this.selected.push(file);
84
+ }
85
+ };
@@ -0,0 +1,205 @@
1
+ var getActive = e => {
2
+ var s = e.currentTarget.$scope;
3
+ return s.toActive(e);
4
+ };
5
+ var notGetActive = e => !getActive(e);
6
+ var getStable = e => {
7
+ var a = getActive(e);
8
+ if (!a) return;
9
+ return !a.$scope.d.pending;
10
+ };
11
+ var getSelected = function (d) {
12
+ var p = getPageScope(d);
13
+ return p.selected;
14
+ }
15
+ var getPageScope = function (d) {
16
+ var $scope = d.$scope.d ? d.$parentScopes[d.$parentScopes.length - 1] : d.$scope;
17
+ return $scope;
18
+ };
19
+ var never = function () { return false };
20
+ var popupEdit = function (d) {
21
+ var $scope = getPageScope(d);
22
+ var selected = $scope.selected;
23
+ var active;
24
+ if (d.$scope === $scope) {
25
+ if (selected.length !== 1) return;
26
+ active = selected[0];
27
+ }
28
+ else {
29
+ active = d.$scope.d;
30
+ }
31
+ if (d === $scope)
32
+ if (d.$scope.pending) return;
33
+ var params = {
34
+ path: $scope.pathlist.join('/'),
35
+ hasName: $scope.hasName.bind($scope),
36
+ rename: $scope.rename,
37
+ add: $scope.add,
38
+ name: active ? active.name : '',
39
+ };
40
+
41
+ zimoli.prepare('explorer$edit', function () {
42
+ var p = popup("#explorer$edit", params);
43
+ on('submited')(p, function () {
44
+ $scope.open();
45
+ remove(p);
46
+ });
47
+ })
48
+
49
+ };
50
+ return extend([
51
+ {
52
+ name: "返回(O)",
53
+ hotkey: "backspace",
54
+ when: never,
55
+ do() {
56
+ history.back();
57
+ }
58
+ },
59
+ {
60
+ name: "打开(O)",
61
+ hotkey: "Enter",
62
+ when: never,
63
+ do(d) {
64
+ var scope = getPageScope(d);
65
+ if (scope.selected.length !== 1) return d;
66
+ scope.open(scope.selected[0]);
67
+ }
68
+ },
69
+ {
70
+ name: "剪切(C)",
71
+ hotkey: "Ctrl+X",
72
+ when: getStable,
73
+ do(d) {
74
+ var copyed = getPageScope(d).copyed;
75
+ for (var c of copyed.splice(0, copyed.length)) c.cut = false;
76
+ for (var c of getSelected(d)) c.cut = true, copyed.push(c);
77
+ }
78
+ },
79
+ {
80
+ name: "复制(R)",
81
+ hotkey: "Ctrl+C",
82
+ when: getStable,
83
+ do(d) {
84
+ var copyed = getPageScope(d).copyed;
85
+ if (copyed) for (var c of copyed.splice(0, copyed.length)) c.cut = false;
86
+ for (var c of getSelected(d)) c.cut = false, copyed.push(c);
87
+ }
88
+ },
89
+ {
90
+ name: "全选(A)",
91
+ hotkey: "Ctrl+A",
92
+ when: never,
93
+ do(d) {
94
+ var scope = getPageScope(d);
95
+ scope.selected = scope.data.filter(a => !a.pending);
96
+ for (var s of scope.selected) s.selected = true;
97
+ }
98
+ },
99
+ {
100
+ name: "替换(R)",
101
+ when: never,
102
+ },
103
+ {
104
+ name: "粘贴(V)",
105
+ hotkey: "Ctrl+V",
106
+ when(e) {
107
+ var copyed = getPageScope(e.target).copyed;
108
+ if (!copyed.length) return false;
109
+ return !getActive(e);
110
+ },
111
+ async do(d) {
112
+ var copyed = getPageScope(d).copyed;
113
+ if (!copyed.length) return;
114
+ var cp = copyed.splice(0, copyed.length);
115
+ var $scope = getPageScope(d);
116
+ var pathbase = "/" + $scope.pathlist.join("/").replace(/^\/+|\/+$/g, '');
117
+ for (var c of cp) {
118
+ if (pathbase.indexOf(c.fullpath.replace(/^\/+|\/+$/g, '')) >= 0) {
119
+ return alert.warn("不能移入子文件夹");
120
+ }
121
+ }
122
+ var token = await $scope.getToken();
123
+ for (var c of cp) {
124
+ var newname = c.name;
125
+ if ($scope.hasName(c.name)) {
126
+ newname = prompt(`请输入新的${cp.isfolder ? '文件夹' : "文件"}名:`, function (a) {
127
+ if (isEmpty(a)) return false;
128
+ if ($scope.hasName(a)) return "命名冲突"
129
+ return explorer$filetip(a);
130
+ });
131
+ newname.querySelector("input,textarea").value = c.name.replace(/\/$/, '');
132
+ newname = await newname;
133
+ }
134
+ if (c.cut) await $scope.mov(c, pathbase + "/" + newname);
135
+ else {
136
+ var offunload = on("beforeunload")(window, function (event) {
137
+ event.preventDefault();
138
+ alert("有文件正在复制!");
139
+ return false;
140
+ });
141
+ var task = explorer$deepcp($scope, c, pathbase + "/" + newname);
142
+ task.token = token;
143
+ try {
144
+ await task;
145
+ } catch { };
146
+ offunload();
147
+ }
148
+ c.cut = false;
149
+ }
150
+ $scope.open();
151
+ }
152
+ },
153
+ {
154
+ name: "新建文件夹(D)",
155
+ when: notGetActive,
156
+ do: popupEdit
157
+ },
158
+ {
159
+ name: "添加文件(F)",
160
+ when: notGetActive,
161
+ async do(d) {
162
+ var $scope = getPageScope(d);
163
+ return $scope.uploadAll(await chooseFile());
164
+ }
165
+ },
166
+ {
167
+ hotkey: "F2",
168
+ name: '重命名(R)',
169
+ when: getStable,
170
+ do: popupEdit
171
+ },
172
+ {
173
+ get name() {
174
+ return this.confirm ? "确认删除(D)" : "删除(D)";
175
+ },
176
+ hotkey: "Shift+Del",
177
+ confirm: false,
178
+ when(e) {
179
+ this.confirm = null;
180
+ return getActive(e);
181
+ },
182
+ type: "danger",
183
+ async do(e, global) {
184
+ var selected = getSelected(e);
185
+ if (global) {
186
+ var elem = div();
187
+ elem.innerHTML = `<fileitem -repeat="d in selected"></fileitem>`;
188
+ render(elem, { fileitem: explorer$fileitem, selected });
189
+ await yousure(`确认要删除如下 ${selected.length} 项吗?`, elem);
190
+ }
191
+ else if (this.confirm === null) {
192
+ this.confirm = e;
193
+ setTimeout(_ => {
194
+ this.confirm = false;
195
+ render.refresh();
196
+ }, 2000);
197
+ return false;
198
+ }
199
+ this.confirm = false;
200
+ var $scope = getPageScope(e);
201
+ for (var s of $scope.selected) s.abort(), await $scope.delete("/" + $scope.pathlist.concat(s.name).join("/"));
202
+ $scope.open();
203
+ }
204
+ }
205
+ ])
@@ -0,0 +1,48 @@
1
+ function read(from, start, end) {
2
+ var xhr = cross("get", from.fullpath);
3
+ xhr.setRequestHeader("range", `bytes=${start}-${end}`);
4
+ return xhr;
5
+ }
6
+ async function cp([from, dist]) {
7
+ var rest = this.rest;
8
+ var scope = this.scope;
9
+ if (from.isfolder) {
10
+ await scope.add(dist);
11
+ var files = await scope.load(from.fullpath);
12
+ for (var f of files) rest.push([f, dist + '/' + f.name]);
13
+ }
14
+ else {
15
+ var inc = 0, step = 64 * 1024, total = 1;
16
+ this.percent = 0;
17
+ while (inc < total) {
18
+ /**
19
+ * @type {XMLHttpRequest}
20
+ */
21
+ var xhr = scope.read(from, inc, step);
22
+ xhr = await xhr;
23
+ var contentrange = xhr.getResponseHeader("Content-Range");
24
+ var size = +xhr.getResponseHeader("Content-Length") || xhr.response.length;
25
+ if (contentrange) total = +contentrange.split("/")[1];
26
+ else total = size;
27
+ await scope.upload({
28
+ data: xhr.response,
29
+ start: inc,
30
+ total,
31
+ name: from.name,
32
+ size
33
+ }, dist, this.token);
34
+ this.percent = inc / total;
35
+ inc += step;
36
+ }
37
+ }
38
+ };
39
+ function deepcp(scope, from, dist) {
40
+ var task = new Task();
41
+ if (from.isfolder) task.title = "复制文件夹";
42
+ else task.title = "复制文件";
43
+ task.open('copy', cp);
44
+ task.scope = scope;
45
+ dist = dist.replace(/^\/+|\/+$/g, '');
46
+ task.send([from, dist]);
47
+ return awaitable(task);
48
+ }
@@ -6,5 +6,5 @@
6
6
  </div>
7
7
  <div foot>
8
8
  <btn @click="remove()" class="white">取消</btn>
9
- <button type="submit">保存</button>
9
+ <button type="submit" disabled_="!data.name||fields[1].valid(data.name)!==undefined">保存</button>
10
10
  </div>
@@ -1,8 +1,16 @@
1
- var fields = refilm`
2
- &原始名称/origin read
3
- 输入新名称/name input
4
- `;
5
- function main({ path: root, name }) {
1
+
2
+
3
+ function main({ path: root, rename, add, name, hasName }) {
4
+ var fields = refilm`
5
+ &原始名称/origin read
6
+ 输入新名称/name input
7
+ `;
8
+ fields[1].valid = function (name) {
9
+ if (!name) return '';
10
+ if (name === origin) return "";
11
+ if (hasName(name)) return "命名冲突";
12
+ return explorer$filetip(name);
13
+ };
6
14
  var a = view();
7
15
  a.innerHTML = edit;
8
16
  drag.on(a.firstChild, a);
@@ -11,6 +19,7 @@ function main({ path: root, name }) {
11
19
  fields,
12
20
  pathlist: root,
13
21
  origin,
22
+ page: a,
14
23
  isFolder: /\/$/.test(name),
15
24
  data: { name: origin, origin },
16
25
  remove() {
@@ -19,14 +28,13 @@ function main({ path: root, name }) {
19
28
  });
20
29
  on('submit')(a, async function (e) {
21
30
  e.preventDefault();
22
- var path = root.concat(a.$scope.data.name).join('/');
23
- path = encode62.timeencode(path);
31
+ var path = root + "/" + a.$scope.data.name;
24
32
  if (origin) {
25
33
  var to = path;
26
34
  path = origin;
27
- path = encode62.timeencode(path);
28
35
  }
29
- await data.from("folder", { opt: origin ? 'mov' : 'add', path, to }).loading_promise;
36
+ if (origin) await rename(path, to);
37
+ else await add(path)
30
38
  dispatch(this, 'submited');
31
39
  });
32
40
  on("append")(a, lazy(function () {
@@ -0,0 +1,8 @@
1
+ <fileitem type_="d.type" @mouseenter="startMarquee(sp)" @mouseleave="stopMarquee(sp)" @touchstart="startMarquee(sp)"
2
+ @touchend="stopMarquee(sp)">
3
+ <template -src="d.isfolder?icons.folder:icons.file"></template>
4
+ <span #sp ng-text=d.name></span>
5
+ <p -if="d.pending" keep >
6
+ <r -style="{width:(d.percent*100).toFixed(4)+'%'}"></r>
7
+ </p>
8
+ </fileitem>
@@ -0,0 +1,34 @@
1
+ var icons = {
2
+ file: shapes$file,
3
+ folder: shapes$folder,
4
+ };
5
+ class Fileitem {
6
+ icons = icons;
7
+ }
8
+ var e = Fileitem.prototype;
9
+ e.startMarquee = function (sp) {
10
+ if (sp.scrollWidth <= sp.clientWidth) return;
11
+ sp.mq = setInterval(function () {
12
+ clearInterval(sp.mq);
13
+ sp.mq = setInterval(function () {
14
+ var scrollLeft = sp.scrollLeft;
15
+ sp.scrollLeft += 1;
16
+ if (sp.scrollLeft === scrollLeft) sp.scrollLeft = 0;
17
+ }, 16);
18
+ }, 400);
19
+ sp.setAttribute("marquee", '');
20
+ sp.scrollLeft = sp.clientWidth;
21
+ };
22
+ e.stopMarquee = function (sp) {
23
+ clearInterval(sp.mq);
24
+ sp.removeAttribute("marquee");
25
+ sp.scrollLeft = 0;
26
+ };
27
+
28
+ function fileitem(elem) {
29
+ elem.innerHTML = template;
30
+ var e = elem.children[0];
31
+ e.$scope = new Fileitem;
32
+ extend(e.$scope, elem.$scope);
33
+ return e;
34
+ }
@@ -0,0 +1,65 @@
1
+ & {
2
+ position: relative;
3
+ display: block;
4
+ padding: 10px 20px 10px 44px;
5
+ white-space: nowrap;
6
+ line-height: 28px;
7
+ background: #fff9;
8
+ }
9
+ &[cut] {
10
+ opacity: .4;
11
+ }
12
+
13
+
14
+ >svg {
15
+ width: 28px;
16
+ height: 28px;
17
+ display: inline-block;
18
+ vertical-align: top;
19
+ margin: 0 6px 0 -34px;
20
+ }
21
+
22
+ >span {
23
+ box-sizing: border-box;
24
+ width: 100%;
25
+ overflow: hidden;
26
+ position: relative;
27
+ text-overflow: ellipsis;
28
+ display: inline-block;
29
+ vertical-align: top;
30
+
31
+ }
32
+
33
+ &:not([dragclone]) [marquee] {
34
+ text-overflow: clip;
35
+
36
+ &:after,
37
+ &:before {
38
+ width: 100%;
39
+ content: "";
40
+ display: inline-block;
41
+ }
42
+ }
43
+
44
+ >a {
45
+ vertical-align: top;
46
+ }
47
+
48
+ >[op] {
49
+ left: 6px;
50
+ margin-left: 6px;
51
+ }
52
+ p{
53
+ display: block;
54
+ margin: 0;
55
+ position: relative;
56
+ height: 4px;
57
+ background: #29c2;
58
+ border-radius: 2px;
59
+ >r{
60
+ height: 100%;
61
+ display: block;
62
+ background: #29c;
63
+ border-radius: inherit;
64
+ }
65
+ }
@@ -0,0 +1,10 @@
1
+ var prevents = "\\/:*?\"<>|";
2
+ var preventreg = new RegExp(`[${prevents.replace(/./g, '\\$&')}]`);
3
+ var perventtxt = prevents.split("").map(a => `<b>${a}</b>`).join("");
4
+ function filetip(text) {
5
+ if (preventreg.test(text)) {
6
+ var pre = document.createElement('pre');
7
+ pre.innerHTML = `不能包含下列字符:\r\n${perventtxt}`;
8
+ return pre;
9
+ }
10
+ }
@@ -0,0 +1,5 @@
1
+ & {
2
+ margin: 0;
3
+ display: inline-block;
4
+ text-align: center;
5
+ }
@@ -0,0 +1,8 @@
1
+ <div class="address">
2
+ <input _value="pathlist.join('/')" />
3
+ </div>
4
+ <lattice tabindex="0" #listview ng-src="d in data" @click="unsetActive(event,d)" @pointerdown="setActive(event,d)">
5
+ <padding>
6
+ <fileitem @dblclick="open(d)" -class="{focused:d.selected}" cut_="d.cut"></fileitem>
7
+ </padding>
8
+ </lattice>