@jx3box/jx3box-editor 3.2.0 → 3.2.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jx3box/jx3box-editor",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "JX3BOX Article & Editor",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -3,62 +3,216 @@ import $ from "jquery";
3
3
  function renderItem(vm, selector = ".w-jx3-element") {
4
4
  let outer, inner;
5
5
  const pop_class = ".w-jx3-element-pop";
6
+ const scopeEl = vm && vm.$el ? vm.$el : document;
7
+ const $scope = $(scopeEl);
8
+ const uid = vm && vm._uid ? vm._uid : "default";
9
+ const ns = `.jx3boxElement_${uid}`;
10
+ let lastTappedElement = null;
11
+ const debugPop = false;
6
12
 
7
- // 触发时
8
- $(selector).on("mouseenter", function (e) {
9
- clearTimeout(outer);
13
+ const isMobile = () => {
14
+ if (typeof window === "undefined") return false;
15
+
16
+ const coarsePointer =
17
+ typeof window.matchMedia === "function" &&
18
+ window.matchMedia("(hover: none) and (pointer: coarse)").matches;
19
+ const hasTouchEvent = "ontouchstart" in window;
20
+ const mobileUA =
21
+ typeof navigator !== "undefined" &&
22
+ /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent || "");
23
+
24
+ return coarsePointer || (hasTouchEvent && mobileUA);
25
+ };
26
+
27
+ const cachedPop =
28
+ vm &&
29
+ vm.__jx3ElementPop &&
30
+ vm.__jx3ElementPop.length &&
31
+ document.documentElement.contains(vm.__jx3ElementPop[0])
32
+ ? vm.__jx3ElementPop
33
+ : null;
34
+ const $pop = cachedPop || $scope.find(pop_class).first();
35
+
36
+ if (!$pop.length) return;
37
+ if (isMobile() && vm) {
38
+ vm.__jx3ElementPop = $pop;
39
+ if ($pop.parent()[0] !== document.body) {
40
+ $pop.appendTo(document.body);
41
+ }
42
+ }
43
+
44
+ const getCurrentTarget = (el, e) => {
45
+ const $self = $(el).closest(selector);
46
+ if ($self.length) return $self;
47
+ return $(e.currentTarget || e.target).closest(selector);
48
+ };
49
+
50
+ const getDataTarget = ($target, e) => {
51
+ const $eventTarget = $(e?.target);
52
+ const $fromEvent = $eventTarget.closest("[data-type]");
53
+ if ($fromEvent.length && $target.has($fromEvent).length) return $fromEvent;
54
+ if ($target.attr("data-type")) return $target;
55
+
56
+ return $target.find("[data-type]").first();
57
+ };
10
58
 
11
- // 获取元素数据
12
- let type = $(e.target).attr("data-type");
13
- if (type == "item") {
14
- vm.item.id = $(e.target).attr("data-id");
15
- vm.item.client = $(e.target).attr("data-client") == "origin" ? 2 : 1;
59
+ const getHrefTarget = ($target) => {
60
+ if ($target.is("a[href]")) return $target;
61
+ return $target.closest("a[href]");
62
+ };
63
+
64
+ const syncElementData = ($dataTarget, $targetForFallback = null) => {
65
+ let type = $dataTarget.attr("data-type");
66
+ if (!type && $targetForFallback && $targetForFallback.length) {
67
+ const $fallback = $targetForFallback.attr("data-type")
68
+ ? $targetForFallback
69
+ : $targetForFallback.find("[data-type]").first();
70
+ type = $fallback.attr("data-type");
71
+ if ($fallback.length) $dataTarget = $fallback;
72
+ }
73
+ if (!type) return "";
74
+
75
+ if (type === "item") {
76
+ vm.item.id = $dataTarget.attr("data-id");
77
+ vm.item.client = $dataTarget.attr("data-client") == "origin" ? 2 : 1;
16
78
  } else if (type === "author") {
17
- vm.author.id = $(e.target).attr("data-id");
79
+ vm.author.id = $dataTarget.attr("data-id");
18
80
  } else if (type === "emotion") {
19
- vm.emotion.id = $(e.target).attr("data-id");
20
- } else {
21
- vm[type].client = $(e.target).attr("data-client");
22
- vm[type].id = $(e.target).attr("data-id");
23
- vm[type].level = $(e.target).attr("data-level");
81
+ vm.emotion.id = $dataTarget.attr("data-id");
82
+ } else if (vm[type]) {
83
+ vm[type].client = $dataTarget.attr("data-client");
84
+ vm[type].id = $dataTarget.attr("data-id");
85
+ vm[type].level = $dataTarget.attr("data-level");
24
86
  }
25
87
 
26
- // 显示浮层
27
- $(pop_class).fadeIn();
28
88
  vm.jx3_element.type = type;
89
+ return type;
90
+ };
91
+
92
+ const showPop = ($dataTarget, point = {}, $targetForRect = null) => {
93
+ clearTimeout(outer);
94
+ clearTimeout(inner);
95
+
96
+ const type = syncElementData($dataTarget, $targetForRect);
97
+ if (!type) return;
98
+
99
+ const fallbackRect = $targetForRect && $targetForRect.length ? $targetForRect[0].getBoundingClientRect() : null;
100
+ const fallbackX = fallbackRect ? fallbackRect.left + fallbackRect.width / 2 : 0;
101
+ const fallbackY = fallbackRect ? fallbackRect.top + fallbackRect.height / 2 : 0;
102
+ const clientX = Number(point.clientX ?? fallbackX ?? 0);
103
+ const clientY = Number(point.clientY ?? fallbackY ?? 0);
104
+
105
+ vm.jx3_element.style.display = "block";
106
+ vm.jx3_element.style.position = "fixed";
107
+ vm.jx3_element.style.zIndex = "99999";
108
+ $pop.stop(true, true).fadeIn(120);
29
109
 
30
- // 计算浮层位置
31
- let self_height = $(pop_class).height();
32
- let win_height = window.innerHeight;
33
- let current_y = e.clientY;
34
- let will_stay_y = e.clientY + 10;
110
+ const selfHeight = $pop.height();
111
+ const winHeight = window.innerHeight;
112
+ const currentY = clientY;
113
+ let willStayY = clientY + 10;
35
114
 
36
- if (self_height && win_height - current_y < self_height) {
37
- will_stay_y =
38
- current_y - (self_height - (win_height - current_y)) - 100;
115
+ if (selfHeight && winHeight - currentY < selfHeight) {
116
+ willStayY = currentY - (selfHeight - (winHeight - currentY)) - 100;
39
117
  }
40
- vm.jx3_element.style.left = e.clientX + 10 + "px";
41
- vm.jx3_element.style.top = will_stay_y + "px";
118
+
119
+ const maxLeft = Math.max(0, window.innerWidth - ($pop.outerWidth() || 0) - 12);
120
+ vm.jx3_element.style.left = Math.max(0, Math.min(clientX + 10, maxLeft)) + "px";
121
+ vm.jx3_element.style.top = Math.max(0, willStayY) + "px";
122
+
123
+ if (debugPop && isMobile()) {
124
+ vm.jx3_element.style.left = "50%";
125
+ vm.jx3_element.style.top = "52%";
126
+ vm.jx3_element.style.transform = "translate(-50%, -50%)";
127
+ vm.jx3_element.style.zIndex = "99999";
128
+ vm.jx3_element.style.background = "rgba(0,0,0,0.88)";
129
+ vm.jx3_element.style.outline = "2px solid #00e5ff";
130
+ vm.jx3_element.style.maxHeight = "72vh";
131
+ vm.jx3_element.style.overflow = "auto";
132
+ } else {
133
+ vm.jx3_element.style.transform = "";
134
+ vm.jx3_element.style.background = "";
135
+ vm.jx3_element.style.outline = "";
136
+ vm.jx3_element.style.maxHeight = "";
137
+ vm.jx3_element.style.overflow = "";
138
+ }
139
+ };
140
+
141
+ const hidePop = () => {
142
+ vm.jx3_element.style.display = "none";
143
+ $pop.stop(true, true).fadeOut(120);
144
+ };
145
+
146
+ // 触发时
147
+ $scope.off(ns);
148
+ $pop.off(ns);
149
+ $(document).off(ns);
150
+
151
+ $scope.on(`mouseenter${ns}`, selector, function (e) {
152
+ if (isMobile()) return;
153
+ const $target = getCurrentTarget(this, e);
154
+ const $dataTarget = getDataTarget($target, e);
155
+ showPop($dataTarget, e, $target);
42
156
  });
43
157
 
44
158
  // 移除时
45
- $(selector).on("mouseleave", function (e) {
159
+ $scope.on(`mouseleave${ns}`, selector, function () {
160
+ if (isMobile()) return;
46
161
  outer = setTimeout(() => {
47
- $(pop_class).fadeOut();
162
+ hidePop();
48
163
  }, 380);
49
164
  });
50
165
 
166
+ $scope.on(`click${ns}`, selector, function (e) {
167
+ if (!isMobile()) return;
168
+
169
+ const $target = getCurrentTarget(this, e);
170
+ const $dataTarget = getDataTarget($target, e);
171
+ if (!$dataTarget.length) return;
172
+
173
+ const $hrefTarget = getHrefTarget($target);
174
+ const href = String($hrefTarget.attr("href") || "");
175
+ const touch = e.originalEvent?.touches?.[0] || e.originalEvent?.changedTouches?.[0];
176
+ const point = touch || e;
177
+ const tappedElement = $target.get(0);
178
+
179
+ if (href && lastTappedElement === tappedElement) {
180
+ lastTappedElement = null;
181
+ hidePop();
182
+ return;
183
+ }
184
+
185
+ e.preventDefault();
186
+ lastTappedElement = tappedElement;
187
+ showPop($dataTarget, point, $target);
188
+ });
189
+
51
190
  // POP内停留
52
- $(pop_class).on("mouseenter", function (e) {
191
+ $pop.on(`mouseenter${ns}`, function () {
192
+ if (isMobile()) return;
53
193
  clearTimeout(outer);
54
- $(pop_class).fadeIn();
194
+ vm.jx3_element.style.display = "block";
195
+ $pop.stop(true, true).fadeIn(120);
55
196
  });
56
- $(pop_class).on("mouseleave", function (e) {
197
+ $pop.on(`mouseleave${ns}`, function () {
198
+ if (isMobile()) return;
57
199
  clearTimeout(inner);
58
200
  inner = setTimeout(() => {
59
- $(pop_class).fadeOut();
201
+ hidePop();
60
202
  }, 280);
61
203
  });
204
+
205
+ $(document).on(`click${ns}`, function (e) {
206
+ if (!isMobile()) return;
207
+ const $target = $(e.target);
208
+ const $trigger = $target.closest(selector);
209
+ const isCurrentTrigger = $trigger.length && ($trigger[0] === scopeEl || $scope.has($trigger[0]).length);
210
+
211
+ if (isCurrentTrigger || $target.closest(pop_class).length) return;
212
+
213
+ lastTappedElement = null;
214
+ hidePop();
215
+ });
62
216
  }
63
217
 
64
218
  export default renderItem;
@@ -4,9 +4,9 @@ function buildIframe(str) {
4
4
  let mode = _str.get("mode");
5
5
 
6
6
  if (mode == "vertical") {
7
- return `<div class="w-pz-iframe-wrap"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="750" height="3468" style="border:none;background:none;max-width:100%;overflow:hidden;"></iframe></div>`;
7
+ return `<div class="w-pz-iframe-wrap" style="width:100%;overflow:auto;"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="750" height="3468" style="border:none;background:none;max-width:none;"></iframe></div>`;
8
8
  } else {
9
- return `<div class="w-pz-iframe-wrap"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="1280" height="720" style="border:none;background:none;max-width:100%;overflow:hidden;"></iframe></div>`;
9
+ return `<div class="w-pz-iframe-wrap" style="width:100%;overflow:auto;"><iframe class="w-pz-iframe" src="${str}" scrolling="no" width="1280" height="720" style="border:none;background:none;max-width:none;"></iframe></div>`;
10
10
  }
11
11
  }
12
12