@dinoreic/fez 0.3.0 → 0.4.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.
- package/README.md +49 -5
- package/dist/fez.js +43 -17
- package/dist/fez.js.map +4 -4
- package/package.json +2 -2
- package/src/fez/compile.js +4 -7
- package/src/fez/connect.js +50 -77
- package/src/fez/defaults.js +36 -1
- package/src/fez/instance.js +100 -21
- package/src/fez/root.js +13 -187
- package/src/fez/utility.js +210 -1
- package/src/fez/utils/css_mixin.js +25 -0
- package/src/fez/utils/dump.js +240 -0
- package/src/fez/utils/highlight_all.js +98 -0
- package/src/svelte-cde-adapter.coffee +122 -0
- package/dist/log.js +0 -5
- package/dist/log.js.map +0 -7
- package/src/log.js +0 -154
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# get node attributes
|
|
2
|
+
getAttributes = (node) ->
|
|
3
|
+
attrs = {}
|
|
4
|
+
|
|
5
|
+
for el in node.attributes
|
|
6
|
+
if el.name.startsWith('on') && el.value[0] == '('
|
|
7
|
+
el.value = new Function('arg1, arg2', "(#{el.value})(arg1, arg2)")
|
|
8
|
+
if el.name.startsWith(':')
|
|
9
|
+
el.value = new Function("return (#{el.value})").bind(node)()
|
|
10
|
+
el.name = el.name.replace(':', '')
|
|
11
|
+
attrs[el.name] = el.value
|
|
12
|
+
|
|
13
|
+
if attrs['data-props']
|
|
14
|
+
attrs = JSON.parse(attrs['data-props'])
|
|
15
|
+
|
|
16
|
+
# pass props as json template
|
|
17
|
+
# <script type="text/template">{...}</script>
|
|
18
|
+
# <foo-bar data-json-template="true"></foo-bar>
|
|
19
|
+
if attrs['data-json-template']
|
|
20
|
+
prev = node.previousSibling
|
|
21
|
+
if prev?.textContent
|
|
22
|
+
attrs = JSON.parse(prev.textContent)
|
|
23
|
+
prev.remove()
|
|
24
|
+
|
|
25
|
+
# data = node.previousSibling?.textContent
|
|
26
|
+
# if data
|
|
27
|
+
# attrs = JSON.parse(data)
|
|
28
|
+
|
|
29
|
+
attrs
|
|
30
|
+
|
|
31
|
+
# passes root, use `Svelte(this.root.id)` or `this.root.svelte` to get node pointer
|
|
32
|
+
# export onMount(instance, list, node) if you want to do stuff on mount
|
|
33
|
+
# connect DOM node to Svelte class instance
|
|
34
|
+
connect = (node, name, klass) ->
|
|
35
|
+
return unless node.isConnected
|
|
36
|
+
|
|
37
|
+
# TODO: get node name
|
|
38
|
+
# (new klass(target: document.createElement('div'))).nodeName
|
|
39
|
+
exported = Object.getOwnPropertyNames(klass.prototype)
|
|
40
|
+
newNode = document.createElement(if exported.includes('nodeNameSpan') then 'span' else 'div')
|
|
41
|
+
newNode.classList.add('svelte')
|
|
42
|
+
newNode.classList.add("svelte-#{name}")
|
|
43
|
+
newNode.id = node.id || "svelte_#{++Svelte.count}"
|
|
44
|
+
|
|
45
|
+
# get attributes
|
|
46
|
+
props = getAttributes(node)
|
|
47
|
+
props.root ||= newNode
|
|
48
|
+
props.oldRoot ||= node
|
|
49
|
+
props.html ||= node.innerHTML
|
|
50
|
+
|
|
51
|
+
# has to come after getAttributes
|
|
52
|
+
node.parentNode.replaceChild(newNode, node);
|
|
53
|
+
|
|
54
|
+
# bind node and pass all props as single props attribute
|
|
55
|
+
exported = Reflect.ownKeys klass.prototype
|
|
56
|
+
svelteProps = {}
|
|
57
|
+
svelteProps.fast = true if exported.includes('fast') || exported.includes('FAST')
|
|
58
|
+
svelteProps.props = props if exported.includes('props')
|
|
59
|
+
svelteProps.root = newNode if exported.includes('root')
|
|
60
|
+
svelteProps.self = "Svelte('#{newNode.id}')" if exported.includes('self')
|
|
61
|
+
|
|
62
|
+
instance = newNode.svelte = new klass({target: newNode, props: svelteProps})
|
|
63
|
+
instance.svelteName = name
|
|
64
|
+
|
|
65
|
+
# fill slots
|
|
66
|
+
# slot has to be named sslot (not slot)
|
|
67
|
+
if slot = newNode.querySelector('sslot')
|
|
68
|
+
while node.firstChild
|
|
69
|
+
slot.parentNode.insertBefore(node.lastChild, slot.nextSibling);
|
|
70
|
+
slot.parentNode.removeChild(slot)
|
|
71
|
+
|
|
72
|
+
# in the end, call onmount
|
|
73
|
+
if instance.onMount
|
|
74
|
+
list = Array.from node.querySelectorAll(':scope > *')
|
|
75
|
+
instance.onMount(instance, list, node)
|
|
76
|
+
|
|
77
|
+
# # #
|
|
78
|
+
|
|
79
|
+
# passes root, use `Svelte(this.root.id)` or `this.root.svelte` to get node pointer
|
|
80
|
+
# export onMount(instance, list, node) if you want to do stuff on mount
|
|
81
|
+
# Svelte(node || node_id).toogle()
|
|
82
|
+
Svelte = (name, func) ->
|
|
83
|
+
if name.nodeName
|
|
84
|
+
# Svelte(this).close() -> return first parent svelte node
|
|
85
|
+
while name = name.parentNode
|
|
86
|
+
return name.svelte if name.svelte
|
|
87
|
+
else
|
|
88
|
+
name = '#' + name if name[0] != '#' && name[0] != '.'
|
|
89
|
+
document.querySelector(name)?.svelte
|
|
90
|
+
|
|
91
|
+
Svelte.count = 0
|
|
92
|
+
|
|
93
|
+
# Creates custom DOM element
|
|
94
|
+
Svelte.connect = (name, klass) ->
|
|
95
|
+
customElements.define name, class extends HTMLElement
|
|
96
|
+
connectedCallback: ->
|
|
97
|
+
# no not optimize requestAnimationFrame (try to avoid it)
|
|
98
|
+
# because events in nested components are sometimes not propagated at all
|
|
99
|
+
# export let fast
|
|
100
|
+
# %s-menu-vertical{ fast_connect: true }
|
|
101
|
+
|
|
102
|
+
# connect @, name, klass
|
|
103
|
+
# if @firstChild && (klass.prototype.hasOwnProperty('fast') || @getAttribute('fast_connect') || @getAttribute('data-props') || @getAttribute('data-json-template'))
|
|
104
|
+
# connect @, name, klass
|
|
105
|
+
# else
|
|
106
|
+
# requestAnimationFrame =>
|
|
107
|
+
# connect @, name, klass
|
|
108
|
+
|
|
109
|
+
if document.readyState == 'loading'
|
|
110
|
+
document.addEventListener 'DOMContentLoaded',
|
|
111
|
+
=> connect(@, name, klass)
|
|
112
|
+
, once: true
|
|
113
|
+
else
|
|
114
|
+
connect(@, name, klass)
|
|
115
|
+
|
|
116
|
+
# Creates HTML tag
|
|
117
|
+
Svelte.tag = (tag, opts = {}, html = '') ->
|
|
118
|
+
json = JSON.stringify(opts).replaceAll("'", ''')
|
|
119
|
+
"<#{tag} data-props='#{json}'>#{html}</#{tag}>"
|
|
120
|
+
|
|
121
|
+
Svelte.bind = Svelte.connect
|
|
122
|
+
window.Svelte = Svelte
|
package/dist/log.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
(()=>{var u=o=>{let a=o.split(/(<\/?[^>]+>)/g).map(i=>i.trim()).filter(i=>i),n=0,t=[];for(let i=0;i<a.length;i++){let e=a[i],s=a[i+1],p=a[i+2];if(e.startsWith("<"))if(!e.startsWith("</")&&!e.endsWith("/>")&&s&&!s.startsWith("<")&&p&&p.startsWith("</")){let r=Math.max(0,n);t.push(" ".repeat(r)+e+s+p),i+=2}else if(e.startsWith("</")){n--;let r=Math.max(0,n);t.push(" ".repeat(r)+e)}else if(e.endsWith("/>")||e.includes(" />")){let r=Math.max(0,n);t.push(" ".repeat(r)+e)}else{let r=Math.max(0,n);t.push(" ".repeat(r)+e),n++}else if(e){let r=Math.max(0,n);t.push(" ".repeat(r)+e)}}return t.join(`
|
|
2
|
-
`)},c=(()=>{let o=[],a=[],n=0;return t=>{if(!document.body){window.requestAnimationFrame(()=>c(t));return}t instanceof Node&&(t=u(t.outerHTML));let i=typeof t;t===void 0&&(t="undefined"),t===null&&(t="null"),Array.isArray(t)?i="array":typeof t=="object"&&t!==null&&(i="object"),typeof t!="string"&&(t=JSON.stringify(t,(r,l)=>typeof l=="function"?String(l):l,2).replaceAll("<","<")),t=t.trim(),o.push(t+`
|
|
3
|
-
|
|
4
|
-
type: ${i}`),a.push(i);let e=document.getElementById("dump-dialog");e||(e=document.body.appendChild(document.createElement("div")),e.id="dump-dialog",e.style.cssText="position:fixed;top:30px;left:30px;right:50px;bottom:50px;background:#fff;border:1px solid#333;box-shadow:0 0 10px rgba(0,0,0,0.5);padding:20px;overflow:auto;z-index:9999;font:13px/1.4 monospace;white-space:pre");let s=parseInt(localStorage.getItem("_LOG_INDEX"));!isNaN(s)&&s>=0&&s<o.length?n=s:n=o.length-1;let p=()=>{let r=o.map((l,d)=>{let f="#f0f0f0";return d!==n&&(a[d]==="object"?f="#d6e3ef":a[d]==="array"&&(f="#d8d5ef")),`<button style="padding:4px 8px;margin:0;cursor:pointer;background:${d===n?"#333":f};color:${d===n?"#fff":"#000"}" data-index="${d}">${d+1}</button>`}).join("");e.innerHTML='<div style="display:flex;flex-direction:column;height:100%"><div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px"><div style="display:flex;flex-wrap:wrap;gap:4px;flex:1;margin-right:10px">'+r+'</div><button style="padding:4px 8px;cursor:pointer;flex-shrink:0">×</button></div><xmp style="flex:1;overflow:auto;margin:0;padding:0;color:#000;background:#fff;font-size:14px;line-height:22px">'+o[n]+"</xmp></div>",e.querySelector('button[style*="flex-shrink:0"]').onclick=()=>e.remove(),e.querySelectorAll("button[data-index]").forEach(l=>{l.onclick=()=>{n=parseInt(l.dataset.index),localStorage.setItem("_LOG_INDEX",n),p()}})};p()}})();typeof window<"u"&&(window.LOG=c,window.LOG_PP=u);var x=c;})();
|
|
5
|
-
//# sourceMappingURL=log.js.map
|
package/dist/log.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/log.js"],
|
|
4
|
-
"sourcesContent": ["// pretty print HTML\nconst LOG_PP = (html) => {\n const parts = html\n .split(/(<\\/?[^>]+>)/g)\n .map(p => p.trim())\n .filter(p => p);\n\n let indent = 0;\n const lines = [];\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n const nextNextPart = parts[i + 2];\n\n // Check if it's a tag\n if (part.startsWith('<')) {\n // Check if this is an opening tag followed by text and then its closing tag\n if (!part.startsWith('</') && !part.endsWith('/>') && nextPart && !nextPart.startsWith('<') && nextNextPart && nextNextPart.startsWith('</')) {\n // Combine them on one line\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part + nextPart + nextNextPart);\n i += 2; // Skip the next two parts\n }\n // Closing tag\n else if (part.startsWith('</')) {\n indent--;\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n // Self-closing tag\n else if (part.endsWith('/>') || part.includes(' />')) {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n // Opening tag\n else {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n indent++;\n }\n }\n // Text node\n else if (part) {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n }\n\n return lines.join('\\n');\n}\n\nconst LOG = (() => {\n const logs = [];\n const logTypes = []; // Track the original type of each log\n let currentIndex = 0;\n\n return o => {\n if (!document.body) {\n window.requestAnimationFrame( () => LOG(o) )\n return\n }\n\n if (o instanceof Node) {\n o = LOG_PP(o.outerHTML)\n }\n\n // Store the original type\n let originalType = typeof o;\n\n if (o === undefined) { o = 'undefined' }\n if (o === null) { o = 'null' }\n\n if (Array.isArray(o)) {\n originalType = 'array';\n } else if (typeof o === 'object' && o !== null) {\n originalType = 'object';\n }\n\n if (typeof o != 'string') {\n o = JSON.stringify(o, (key, value) => {\n if (typeof value === 'function') {\n return String(value);\n }\n return value;\n }, 2).replaceAll('<', '<')\n }\n\n o = o.trim()\n\n logs.push(o + `\\n\\ntype: ${originalType}`);\n logTypes.push(originalType);\n\n let d = document.getElementById('dump-dialog');\n if (!d) {\n d = document.body.appendChild(document.createElement('div'));\n d.id = 'dump-dialog';\n d.style.cssText =\n 'position:fixed;top:30px;left:30px;right:50px;bottom:50px;' +\n 'background:#fff;border:1px solid#333;box-shadow:0 0 10px rgba(0,0,0,0.5);' +\n 'padding:20px;overflow:auto;z-index:9999;font:13px/1.4 monospace;white-space:pre';\n }\n\n // Check if we have a saved index and it's still valid\n const savedIndex = parseInt(localStorage.getItem('_LOG_INDEX'));\n if (!isNaN(savedIndex) && savedIndex >= 0 && savedIndex < logs.length) {\n currentIndex = savedIndex;\n } else {\n currentIndex = logs.length - 1;\n }\n\n const renderContent = () => {\n const buttons = logs.map((_, i) => {\n let bgColor = '#f0f0f0'; // default\n if (i !== currentIndex) {\n if (logTypes[i] === 'object') {\n bgColor = '#d6e3ef'; // super light blue\n } else if (logTypes[i] === 'array') {\n bgColor = '#d8d5ef'; // super light indigo\n }\n }\n return `<button style=\"padding:4px 8px;margin:0;cursor:pointer;background:${i === currentIndex ? '#333' : bgColor};color:${i === currentIndex ? '#fff' : '#000'}\" data-index=\"${i}\">${i + 1}</button>`\n }).join('');\n\n d.innerHTML =\n '<div style=\"display:flex;flex-direction:column;height:100%\">' +\n '<div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px\">' +\n '<div style=\"display:flex;flex-wrap:wrap;gap:4px;flex:1;margin-right:10px\">' + buttons + '</div>' +\n '<button style=\"padding:4px 8px;cursor:pointer;flex-shrink:0\">×</button>' +\n '</div>' +\n '<xmp style=\"flex:1;overflow:auto;margin:0;padding:0;color:#000;background:#fff;font-size:14px;line-height:22px\">' + logs[currentIndex] + '</xmp>' +\n '</div>';\n\n d.querySelector('button[style*=\"flex-shrink:0\"]').onclick = () => d.remove();\n\n d.querySelectorAll('button[data-index]').forEach(btn => {\n btn.onclick = () => {\n currentIndex = parseInt(btn.dataset.index);\n localStorage.setItem('_LOG_INDEX', currentIndex);\n renderContent();\n };\n });\n };\n\n renderContent();\n };\n})();\n\nif (typeof window !== 'undefined') {\n window.LOG = LOG\n window.LOG_PP = LOG_PP\n}\n\nexport default LOG\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["LOG_PP", "html", "parts", "p", "indent", "lines", "part", "nextPart", "nextNextPart", "actualIndent", "LOG", "logs", "logTypes", "currentIndex", "o", "originalType", "key", "value", "d", "savedIndex", "renderContent", "buttons", "_", "i", "bgColor", "btn", "log_default"]
|
|
7
|
-
}
|
package/src/log.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// pretty print HTML
|
|
2
|
-
const LOG_PP = (html) => {
|
|
3
|
-
const parts = html
|
|
4
|
-
.split(/(<\/?[^>]+>)/g)
|
|
5
|
-
.map(p => p.trim())
|
|
6
|
-
.filter(p => p);
|
|
7
|
-
|
|
8
|
-
let indent = 0;
|
|
9
|
-
const lines = [];
|
|
10
|
-
|
|
11
|
-
for (let i = 0; i < parts.length; i++) {
|
|
12
|
-
const part = parts[i];
|
|
13
|
-
const nextPart = parts[i + 1];
|
|
14
|
-
const nextNextPart = parts[i + 2];
|
|
15
|
-
|
|
16
|
-
// Check if it's a tag
|
|
17
|
-
if (part.startsWith('<')) {
|
|
18
|
-
// Check if this is an opening tag followed by text and then its closing tag
|
|
19
|
-
if (!part.startsWith('</') && !part.endsWith('/>') && nextPart && !nextPart.startsWith('<') && nextNextPart && nextNextPart.startsWith('</')) {
|
|
20
|
-
// Combine them on one line
|
|
21
|
-
const actualIndent = Math.max(0, indent);
|
|
22
|
-
lines.push(' '.repeat(actualIndent) + part + nextPart + nextNextPart);
|
|
23
|
-
i += 2; // Skip the next two parts
|
|
24
|
-
}
|
|
25
|
-
// Closing tag
|
|
26
|
-
else if (part.startsWith('</')) {
|
|
27
|
-
indent--;
|
|
28
|
-
const actualIndent = Math.max(0, indent);
|
|
29
|
-
lines.push(' '.repeat(actualIndent) + part);
|
|
30
|
-
}
|
|
31
|
-
// Self-closing tag
|
|
32
|
-
else if (part.endsWith('/>') || part.includes(' />')) {
|
|
33
|
-
const actualIndent = Math.max(0, indent);
|
|
34
|
-
lines.push(' '.repeat(actualIndent) + part);
|
|
35
|
-
}
|
|
36
|
-
// Opening tag
|
|
37
|
-
else {
|
|
38
|
-
const actualIndent = Math.max(0, indent);
|
|
39
|
-
lines.push(' '.repeat(actualIndent) + part);
|
|
40
|
-
indent++;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
// Text node
|
|
44
|
-
else if (part) {
|
|
45
|
-
const actualIndent = Math.max(0, indent);
|
|
46
|
-
lines.push(' '.repeat(actualIndent) + part);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return lines.join('\n');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const LOG = (() => {
|
|
54
|
-
const logs = [];
|
|
55
|
-
const logTypes = []; // Track the original type of each log
|
|
56
|
-
let currentIndex = 0;
|
|
57
|
-
|
|
58
|
-
return o => {
|
|
59
|
-
if (!document.body) {
|
|
60
|
-
window.requestAnimationFrame( () => LOG(o) )
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (o instanceof Node) {
|
|
65
|
-
o = LOG_PP(o.outerHTML)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Store the original type
|
|
69
|
-
let originalType = typeof o;
|
|
70
|
-
|
|
71
|
-
if (o === undefined) { o = 'undefined' }
|
|
72
|
-
if (o === null) { o = 'null' }
|
|
73
|
-
|
|
74
|
-
if (Array.isArray(o)) {
|
|
75
|
-
originalType = 'array';
|
|
76
|
-
} else if (typeof o === 'object' && o !== null) {
|
|
77
|
-
originalType = 'object';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (typeof o != 'string') {
|
|
81
|
-
o = JSON.stringify(o, (key, value) => {
|
|
82
|
-
if (typeof value === 'function') {
|
|
83
|
-
return String(value);
|
|
84
|
-
}
|
|
85
|
-
return value;
|
|
86
|
-
}, 2).replaceAll('<', '<')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
o = o.trim()
|
|
90
|
-
|
|
91
|
-
logs.push(o + `\n\ntype: ${originalType}`);
|
|
92
|
-
logTypes.push(originalType);
|
|
93
|
-
|
|
94
|
-
let d = document.getElementById('dump-dialog');
|
|
95
|
-
if (!d) {
|
|
96
|
-
d = document.body.appendChild(document.createElement('div'));
|
|
97
|
-
d.id = 'dump-dialog';
|
|
98
|
-
d.style.cssText =
|
|
99
|
-
'position:fixed;top:30px;left:30px;right:50px;bottom:50px;' +
|
|
100
|
-
'background:#fff;border:1px solid#333;box-shadow:0 0 10px rgba(0,0,0,0.5);' +
|
|
101
|
-
'padding:20px;overflow:auto;z-index:9999;font:13px/1.4 monospace;white-space:pre';
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Check if we have a saved index and it's still valid
|
|
105
|
-
const savedIndex = parseInt(localStorage.getItem('_LOG_INDEX'));
|
|
106
|
-
if (!isNaN(savedIndex) && savedIndex >= 0 && savedIndex < logs.length) {
|
|
107
|
-
currentIndex = savedIndex;
|
|
108
|
-
} else {
|
|
109
|
-
currentIndex = logs.length - 1;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const renderContent = () => {
|
|
113
|
-
const buttons = logs.map((_, i) => {
|
|
114
|
-
let bgColor = '#f0f0f0'; // default
|
|
115
|
-
if (i !== currentIndex) {
|
|
116
|
-
if (logTypes[i] === 'object') {
|
|
117
|
-
bgColor = '#d6e3ef'; // super light blue
|
|
118
|
-
} else if (logTypes[i] === 'array') {
|
|
119
|
-
bgColor = '#d8d5ef'; // super light indigo
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return `<button style="padding:4px 8px;margin:0;cursor:pointer;background:${i === currentIndex ? '#333' : bgColor};color:${i === currentIndex ? '#fff' : '#000'}" data-index="${i}">${i + 1}</button>`
|
|
123
|
-
}).join('');
|
|
124
|
-
|
|
125
|
-
d.innerHTML =
|
|
126
|
-
'<div style="display:flex;flex-direction:column;height:100%">' +
|
|
127
|
-
'<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px">' +
|
|
128
|
-
'<div style="display:flex;flex-wrap:wrap;gap:4px;flex:1;margin-right:10px">' + buttons + '</div>' +
|
|
129
|
-
'<button style="padding:4px 8px;cursor:pointer;flex-shrink:0">×</button>' +
|
|
130
|
-
'</div>' +
|
|
131
|
-
'<xmp style="flex:1;overflow:auto;margin:0;padding:0;color:#000;background:#fff;font-size:14px;line-height:22px">' + logs[currentIndex] + '</xmp>' +
|
|
132
|
-
'</div>';
|
|
133
|
-
|
|
134
|
-
d.querySelector('button[style*="flex-shrink:0"]').onclick = () => d.remove();
|
|
135
|
-
|
|
136
|
-
d.querySelectorAll('button[data-index]').forEach(btn => {
|
|
137
|
-
btn.onclick = () => {
|
|
138
|
-
currentIndex = parseInt(btn.dataset.index);
|
|
139
|
-
localStorage.setItem('_LOG_INDEX', currentIndex);
|
|
140
|
-
renderContent();
|
|
141
|
-
};
|
|
142
|
-
});
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
renderContent();
|
|
146
|
-
};
|
|
147
|
-
})();
|
|
148
|
-
|
|
149
|
-
if (typeof window !== 'undefined') {
|
|
150
|
-
window.LOG = LOG
|
|
151
|
-
window.LOG_PP = LOG_PP
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export default LOG
|