qumra-engine 2.0.89 → 2.0.91

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.
@@ -45,13 +45,26 @@ exports.default = new (class WidgetExtension {
45
45
  context: ctx.context,
46
46
  globals: ctx.globals,
47
47
  widget: {
48
- id: widget.id,
48
+ id: widget._id,
49
49
  type: widget.widget,
50
50
  data: widget.data,
51
51
  blocks: widget.blocks ?? [],
52
52
  },
53
53
  });
54
- renderedWidgets.push(html);
54
+ let isIframe = false;
55
+ if (env.getGlobal("isIframe")) {
56
+ isIframe = env.getGlobal("isIframe");
57
+ }
58
+ if (isIframe) {
59
+ renderedWidgets.push(`
60
+ <section content-type="widget" widget-id="${widget._id}" id="qumra-widget-id-${widget._id}">
61
+ ${html}
62
+ </section>
63
+ `);
64
+ }
65
+ else {
66
+ renderedWidgets.push(html);
67
+ }
55
68
  }
56
69
  catch (err) {
57
70
  renderedWidgets.push(`
@@ -2,6 +2,6 @@ import { runtime } from "nunjucks";
2
2
  declare const _default: {
3
3
  tags: string[];
4
4
  parse(parser: any, nodes: any): any;
5
- run({ env, ctx }: any): runtime.SafeString;
5
+ run({ env }: any): runtime.SafeString;
6
6
  };
7
7
  export default _default;
@@ -11,42 +11,126 @@ exports.default = new (class SeoExtension {
11
11
  parser.advanceAfterBlockEnd(tok.value);
12
12
  return new nodes.CallExtension(this, "run", null);
13
13
  }
14
- run({ env, ctx }) {
14
+ run({ env }) {
15
15
  const injectionCode = (0, globals_1.getGlobal)("injectionCode");
16
- let isIframe = false;
17
- if (env.getGlobal("isIframe")) {
18
- isIframe = env.getGlobal("isIframe");
19
- }
16
+ const isIframe = !!env.getGlobal("isIframe");
20
17
  let scripts = `
21
18
  ${injectionCode.body}
22
19
  `;
23
20
  if (isIframe) {
24
21
  scripts += `
22
+ <div id="selector-outline">
23
+ <div id="selector-toolbar">
24
+ <button class="control-btn btn-edit" title="تحرير" id="btn-edit">✏️</button>
25
+ <button class="control-btn btn-copy" title="نسخ" id="btn-copy">📋</button>
26
+ <button class="control-btn btn-settings" title="إعدادات" id="btn-settings">⚙️</button>
27
+ <button class="control-btn btn-delete" title="حذف" id="btn-delete">🗑️</button>
28
+ </div>
29
+ <div class="corner-dot top-left"></div>
30
+ <div class="corner-dot top-right"></div>
31
+ <div class="corner-dot bottom-left"></div>
32
+ <div class="corner-dot bottom-right"></div>
33
+ <div class="edge-line top"></div>
34
+ <div class="edge-line bottom"></div>
35
+ <div class="edge-line left"></div>
36
+ <div class="edge-line right"></div>
37
+ </div>
38
+
25
39
  <script>
26
- function attachIframeLinkListeners(root = document) {
27
- const links = root.querySelectorAll("a");
28
- links.forEach(link => {
29
- if (link.dataset._iframeHandled) return;
30
- link.dataset._iframeHandled = "true";
31
-
32
- link.addEventListener("click", function (e) {
33
- const href = link.getAttribute("href");
34
- if (!href || href === "#") return;
35
-
36
- e.preventDefault();
37
- e.stopPropagation();
40
+ document.addEventListener("DOMContentLoaded", () => {
41
+ const outline = document.getElementById('selector-outline');
42
+ const btnEdit = document.getElementById('btn-edit');
43
+ const btnDelete = document.getElementById('btn-delete');
44
+ const btnCopy = document.getElementById('btn-copy');
45
+ const btnSettings = document.getElementById('btn-settings');
46
+ let selectedElement = null;
47
+ let hoverTimeout = null;
48
+
49
+ const widgets = document.querySelectorAll('[widget-id]');
50
+
51
+ function showSelector(element) {
52
+ selectedElement = element;
53
+ const rect = element.getBoundingClientRect();
54
+ outline.style.display = 'block';
55
+ outline.style.top = \`\${rect.top + window.scrollY - 4}px\`;
56
+ outline.style.left = \`\${rect.left + window.scrollX - 4}px\`;
57
+ outline.style.width = \`\${rect.width + 8}px\`;
58
+ outline.style.height = \`\${rect.height + 8}px\`;
59
+ }
60
+
61
+ function hideSelector() {
62
+ outline.style.display = 'none';
63
+ selectedElement = null;
64
+ }
38
65
 
39
- window.parent.postMessage(
40
- { type: "iframeLinkClick", href },
41
- "*"
42
- );
66
+ widgets.forEach(el => {
67
+ el.addEventListener('mouseenter', () => {
68
+ clearTimeout(hoverTimeout);
69
+ showSelector(el);
70
+ });
71
+
72
+ el.addEventListener('mouseleave', () => {
73
+ hoverTimeout = setTimeout(() => {
74
+ const hovered = document.querySelector(':hover');
75
+ if (!outline.contains(hovered) && hovered !== el) hideSelector();
76
+ }, 50);
43
77
  });
44
78
  });
45
- }
46
79
 
47
- document.addEventListener("DOMContentLoaded", function () {
48
- attachIframeLinkListeners();
80
+ outline.addEventListener('mouseenter', () => clearTimeout(hoverTimeout));
81
+ outline.addEventListener('mouseleave', () => {
82
+ hoverTimeout = setTimeout(hideSelector, 50);
83
+ });
84
+
85
+ // أزرار التحكم
86
+ const btnActions = {
87
+ 'btn-edit': el => alert(\`تحرير العنصر: \${el.getAttribute('widget-id')}\`),
88
+ 'btn-copy': el => alert(\`نسخ العنصر: \${el.getAttribute('widget-id')}\`),
89
+ 'btn-settings': el => alert(\`إعدادات العنصر: \${el.getAttribute('widget-id')}\`),
90
+ 'btn-delete': el => {
91
+ if (confirm('هل أنت متأكد من حذف هذا العنصر؟')) {
92
+ el.remove();
93
+ hideSelector();
94
+ }
95
+ }
96
+ };
49
97
 
98
+ Object.entries(btnActions).forEach(([id, fn]) => {
99
+ const btn = document.getElementById(id);
100
+ btn?.addEventListener('click', e => {
101
+ e.stopPropagation();
102
+ if (selectedElement) fn(selectedElement);
103
+ });
104
+ });
105
+
106
+ // تحديث موقع outline عند scroll
107
+ window.addEventListener('scroll', () => {
108
+ if (!selectedElement || outline.style.display === 'none') return;
109
+ const rect = selectedElement.getBoundingClientRect();
110
+ outline.style.top = \`\${rect.top + window.scrollY - 4}px\`;
111
+ outline.style.left = \`\${rect.left + window.scrollX - 4}px\`;
112
+ outline.style.width = \`\${rect.width + 8}px\`;
113
+ outline.style.height = \`\${rect.height + 8}px\`;
114
+ });
115
+
116
+ // التعامل مع روابط iframe
117
+ function attachIframeLinkListeners(root = document) {
118
+ const links = root.querySelectorAll("a");
119
+ links.forEach(link => {
120
+ if (link.dataset._iframeHandled) return;
121
+ link.dataset._iframeHandled = "true";
122
+
123
+ link.addEventListener("click", function (e) {
124
+ const href = link.getAttribute("href");
125
+ if (!href || href === "#") return;
126
+ e.preventDefault();
127
+ e.stopPropagation();
128
+ window.parent.postMessage({ type: "iframeLinkClick", href }, "*");
129
+ });
130
+ });
131
+ }
132
+
133
+ attachIframeLinkListeners();
50
134
  const observer = new MutationObserver(() => attachIframeLinkListeners());
51
135
  observer.observe(document.body, { childList: true, subtree: true });
52
136
  });
@@ -18,7 +18,7 @@ exports.default = new (class WidgetExtension {
18
18
  run({ ctx, env }, templateKey) {
19
19
  const widgetPreview = env.getGlobal("widget");
20
20
  if (widgetPreview) {
21
- return '';
21
+ return "";
22
22
  }
23
23
  if (templateKey === "main") {
24
24
  return new nunjucks_1.default.runtime.SafeString(`
@@ -45,13 +45,26 @@ exports.default = new (class WidgetExtension {
45
45
  context: ctx.context,
46
46
  globals: ctx.globals,
47
47
  widget: {
48
- id: widget.id,
48
+ id: widget._id,
49
49
  type: widget.widget,
50
50
  data: widget.data,
51
51
  blocks: widget.blocks ?? [],
52
52
  },
53
53
  });
54
- renderedWidgets.push(html);
54
+ let isIframe = false;
55
+ if (env.getGlobal("isIframe")) {
56
+ isIframe = env.getGlobal("isIframe");
57
+ }
58
+ if (isIframe) {
59
+ renderedWidgets.push(`
60
+ <section widget-id="${widget._id}" id="qumra-widget-id-${widget._id}">
61
+ ${html}
62
+ </section>
63
+ `);
64
+ }
65
+ else {
66
+ renderedWidgets.push(html);
67
+ }
55
68
  }
56
69
  catch (err) {
57
70
  renderedWidgets.push(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qumra-engine",
3
- "version": "2.0.89",
3
+ "version": "2.0.91",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {