Split js into separate files
This commit is contained in:
56
js/gallery-thumbnails.js
Normal file
56
js/gallery-thumbnails.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/* global window, document */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Luxtools = window.Luxtools || (window.Luxtools = {});
|
||||
|
||||
// ============================================================
|
||||
// Gallery Thumbnails Module
|
||||
// ============================================================
|
||||
Luxtools.GalleryThumbnails = (function () {
|
||||
function loadThumb(img) {
|
||||
var src = img.getAttribute('data-thumb-src') || '';
|
||||
if (!src) return;
|
||||
if (img.getAttribute('data-thumb-loading') === '1') return;
|
||||
img.setAttribute('data-thumb-loading', '1');
|
||||
|
||||
var pre = new window.Image();
|
||||
pre.onload = function () {
|
||||
img.src = src;
|
||||
img.removeAttribute('data-thumb-src');
|
||||
img.removeAttribute('data-thumb-loading');
|
||||
};
|
||||
pre.onerror = function () {
|
||||
img.removeAttribute('data-thumb-loading');
|
||||
};
|
||||
pre.src = src;
|
||||
}
|
||||
|
||||
function init() {
|
||||
var imgs = document.querySelectorAll('div.luxtools-gallery img[data-thumb-src]');
|
||||
if (!imgs || !imgs.length) return;
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
var io = new window.IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
loadThumb(entry.target);
|
||||
io.unobserve(entry.target);
|
||||
});
|
||||
}, { rootMargin: '200px' });
|
||||
|
||||
imgs.forEach(function (img) { io.observe(img); });
|
||||
} else {
|
||||
// Fallback: load soon after initial render
|
||||
window.setTimeout(function () {
|
||||
imgs.forEach(loadThumb);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
})();
|
||||
})();
|
||||
265
js/lightbox.js
Normal file
265
js/lightbox.js
Normal file
@@ -0,0 +1,265 @@
|
||||
/* global window, document */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Luxtools = window.Luxtools || (window.Luxtools = {});
|
||||
|
||||
// ============================================================
|
||||
// Lightbox Module
|
||||
// ============================================================
|
||||
Luxtools.Lightbox = (function () {
|
||||
var lb = null;
|
||||
var img = null;
|
||||
var cap = null;
|
||||
var items = [];
|
||||
var index = 0;
|
||||
|
||||
// Zoom/pan state
|
||||
var scale = 1;
|
||||
var panX = 0;
|
||||
var panY = 0;
|
||||
var minScale = 1;
|
||||
var maxScale = 5;
|
||||
var isPanning = false;
|
||||
var panStartX = 0;
|
||||
var panStartY = 0;
|
||||
|
||||
// History state
|
||||
var pushedHistory = false;
|
||||
var closingFromPopstate = false;
|
||||
|
||||
function ensureElement() {
|
||||
if (lb) return;
|
||||
|
||||
lb = document.createElement('div');
|
||||
lb.className = 'luxtools-lightbox';
|
||||
lb.setAttribute('role', 'dialog');
|
||||
lb.setAttribute('aria-modal', 'true');
|
||||
lb.setAttribute('aria-hidden', 'true');
|
||||
|
||||
lb.innerHTML =
|
||||
'<div class="luxtools-lightbox-backdrop" data-luxtools-action="close"></div>' +
|
||||
'<div class="luxtools-lightbox-stage">' +
|
||||
'<button type="button" class="luxtools-lightbox-close" data-luxtools-action="close" aria-label="Close">×</button>' +
|
||||
'<button type="button" class="luxtools-lightbox-zone luxtools-lightbox-zone-prev" data-luxtools-action="prev" aria-label="Previous"></button>' +
|
||||
'<button type="button" class="luxtools-lightbox-zone luxtools-lightbox-zone-next" data-luxtools-action="next" aria-label="Next"></button>' +
|
||||
'<div class="luxtools-lightbox-media">' +
|
||||
'<img class="luxtools-lightbox-img" alt="" />' +
|
||||
'</div>' +
|
||||
'<div class="luxtools-lightbox-caption"></div>' +
|
||||
'</div>';
|
||||
|
||||
document.body.appendChild(lb);
|
||||
img = lb.querySelector('img.luxtools-lightbox-img');
|
||||
cap = lb.querySelector('.luxtools-lightbox-caption');
|
||||
|
||||
lb.addEventListener('click', onClick);
|
||||
}
|
||||
|
||||
function clampIndex(n) {
|
||||
if (n < 0) return items.length - 1;
|
||||
if (n >= items.length) return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
function applyTransform() {
|
||||
if (scale <= 1 && panX === 0 && panY === 0) {
|
||||
img.style.transform = '';
|
||||
} else {
|
||||
img.style.transform = 'scale(' + scale + ') translate(' + panX + 'px, ' + panY + 'px)';
|
||||
}
|
||||
img.style.cursor = scale > 1 ? 'grab' : '';
|
||||
}
|
||||
|
||||
function resetZoom() {
|
||||
scale = 1;
|
||||
panX = 0;
|
||||
panY = 0;
|
||||
applyTransform();
|
||||
}
|
||||
|
||||
function render() {
|
||||
var it = items[index];
|
||||
img.src = it.full;
|
||||
img.setAttribute('data-luxtools-index', String(index));
|
||||
if (cap) cap.textContent = (it.name || '').trim();
|
||||
resetZoom();
|
||||
}
|
||||
|
||||
function next() {
|
||||
index = clampIndex(index + 1);
|
||||
render();
|
||||
}
|
||||
|
||||
function prev() {
|
||||
index = clampIndex(index - 1);
|
||||
render();
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
function onWheel(e) {
|
||||
e.preventDefault();
|
||||
var delta = e.deltaY > 0 ? -0.15 : 0.15;
|
||||
scale = Math.max(minScale, Math.min(maxScale, scale + delta));
|
||||
if (scale <= 1) { panX = 0; panY = 0; }
|
||||
applyTransform();
|
||||
}
|
||||
|
||||
function onDblClick(e) {
|
||||
e.preventDefault();
|
||||
if (scale > 1) {
|
||||
scale = 1;
|
||||
panX = 0;
|
||||
panY = 0;
|
||||
} else {
|
||||
scale = 2.5;
|
||||
}
|
||||
applyTransform();
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
if (scale > 1 && e.button === 0) {
|
||||
isPanning = true;
|
||||
panStartX = e.clientX - panX * scale;
|
||||
panStartY = e.clientY - panY * scale;
|
||||
img.style.cursor = 'grabbing';
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
if (isPanning && scale > 1) {
|
||||
panX = (e.clientX - panStartX) / scale;
|
||||
panY = (e.clientY - panStartY) / scale;
|
||||
applyTransform();
|
||||
img.style.cursor = 'grabbing';
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp() {
|
||||
isPanning = false;
|
||||
img.style.cursor = scale > 1 ? 'grab' : '';
|
||||
}
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (!lb || !lb.classList.contains('is-open')) return;
|
||||
var key = e.key || '';
|
||||
if (key === 'Escape') {
|
||||
e.preventDefault();
|
||||
close();
|
||||
} else if (key === 'ArrowRight') {
|
||||
e.preventDefault();
|
||||
next();
|
||||
} else if (key === 'ArrowLeft') {
|
||||
e.preventDefault();
|
||||
prev();
|
||||
}
|
||||
}
|
||||
|
||||
function onPopState() {
|
||||
if (!lb || !lb.classList.contains('is-open')) return;
|
||||
closingFromPopstate = true;
|
||||
try { close(); } finally { closingFromPopstate = false; }
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
var t = e.target;
|
||||
if (!t || !t.getAttribute) return;
|
||||
var action = t.getAttribute('data-luxtools-action') || '';
|
||||
if (action === 'close') { e.preventDefault(); close(); return; }
|
||||
if (action === 'next') { e.preventDefault(); next(); return; }
|
||||
if (action === 'prev') { e.preventDefault(); prev(); return; }
|
||||
|
||||
if (t.closest && t.closest('button.luxtools-lightbox-zone')) return;
|
||||
if (t.closest && t.closest('img.luxtools-lightbox-img')) return;
|
||||
e.preventDefault();
|
||||
close();
|
||||
}
|
||||
|
||||
function attachListeners() {
|
||||
document.addEventListener('keydown', onKeyDown, true);
|
||||
window.addEventListener('popstate', onPopState, true);
|
||||
img.addEventListener('wheel', onWheel, { passive: false });
|
||||
img.addEventListener('dblclick', onDblClick);
|
||||
img.addEventListener('mousedown', onMouseDown);
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
function detachListeners() {
|
||||
document.removeEventListener('keydown', onKeyDown, true);
|
||||
window.removeEventListener('popstate', onPopState, true);
|
||||
img.removeEventListener('wheel', onWheel);
|
||||
img.removeEventListener('dblclick', onDblClick);
|
||||
img.removeEventListener('mousedown', onMouseDown);
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
function open(galleryEl, startEl) {
|
||||
var links = galleryEl.querySelectorAll('a.luxtools-gallery-item[data-luxtools-full]');
|
||||
items = [];
|
||||
links.forEach(function (a) {
|
||||
var full = a.getAttribute('data-luxtools-full') || a.getAttribute('href') || '';
|
||||
var name = a.getAttribute('data-luxtools-name') || a.getAttribute('title') || '';
|
||||
if (!full) return;
|
||||
items.push({ el: a, full: full, name: name });
|
||||
});
|
||||
if (!items.length) return;
|
||||
|
||||
index = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].el === startEl) { index = i; break; }
|
||||
}
|
||||
|
||||
ensureElement();
|
||||
pushedHistory = false;
|
||||
closingFromPopstate = false;
|
||||
|
||||
lb.classList.add('is-open');
|
||||
lb.setAttribute('aria-hidden', 'false');
|
||||
try { document.documentElement.classList.add('luxtools-noscroll'); } catch (e) {}
|
||||
try { document.body.style.overflow = 'hidden'; } catch (e) {}
|
||||
|
||||
attachListeners();
|
||||
|
||||
try {
|
||||
if (window.history && window.history.pushState) {
|
||||
window.history.pushState({ luxtoolsLightbox: 1 }, '', window.location.href);
|
||||
pushedHistory = true;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (!lb) return;
|
||||
|
||||
lb.classList.remove('is-open');
|
||||
lb.setAttribute('aria-hidden', 'true');
|
||||
try { document.documentElement.classList.remove('luxtools-noscroll'); } catch (e) {}
|
||||
try { document.body.style.overflow = ''; } catch (e) {}
|
||||
img.src = '';
|
||||
resetZoom();
|
||||
|
||||
detachListeners();
|
||||
|
||||
if (pushedHistory && !closingFromPopstate) {
|
||||
try {
|
||||
if (window.history && window.history.state && window.history.state.luxtoolsLightbox === 1) {
|
||||
window.history.back();
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
items = [];
|
||||
}
|
||||
|
||||
return {
|
||||
open: open,
|
||||
close: close
|
||||
};
|
||||
})();
|
||||
})();
|
||||
92
js/main.js
Normal file
92
js/main.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/* global window, document */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Luxtools = window.Luxtools || (window.Luxtools = {});
|
||||
var Lightbox = Luxtools.Lightbox;
|
||||
var OpenService = Luxtools.OpenService;
|
||||
var GalleryThumbnails = Luxtools.GalleryThumbnails;
|
||||
var Scratchpads = Luxtools.Scratchpads;
|
||||
|
||||
// ============================================================
|
||||
// Click Handlers
|
||||
// ============================================================
|
||||
function findOpenElement(target) {
|
||||
var el = target;
|
||||
while (el && el !== document) {
|
||||
if (el.classList && el.classList.contains('luxtools-open')) return el;
|
||||
el = el.parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findGalleryItem(target) {
|
||||
var el = target;
|
||||
while (el && el !== document) {
|
||||
if (el.classList && el.classList.contains('luxtools-gallery-item')) return el;
|
||||
el = el.parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function onClick(event) {
|
||||
// Image gallery lightbox: intercept clicks so we don't navigate away.
|
||||
var galleryItem = findGalleryItem(event.target);
|
||||
if (galleryItem && Lightbox && Lightbox.open) {
|
||||
var gallery = galleryItem.closest ? galleryItem.closest('div.luxtools-gallery[data-luxtools-gallery="1"]') : null;
|
||||
if (gallery) {
|
||||
event.preventDefault();
|
||||
Lightbox.open(gallery, galleryItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var el = findOpenElement(event.target);
|
||||
if (!el) return;
|
||||
|
||||
// {{open>...}} renders as a link; avoid jumping to '#'.
|
||||
if (el.tagName && el.tagName.toLowerCase() === 'a') {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
var raw = el.getAttribute('data-path') || '';
|
||||
if (!raw) return;
|
||||
if (!OpenService || !OpenService.openViaService) return;
|
||||
|
||||
// Prefer local client service.
|
||||
OpenService.openViaService(el, raw)
|
||||
.catch(function (err) {
|
||||
// If the browser blocks the request before it reaches localhost (mixed-content,
|
||||
// extensions, stricter CORS handling), fall back to a no-CORS GET ping.
|
||||
if (OpenService && OpenService.pingOpenViaImage) {
|
||||
OpenService.pingOpenViaImage(el, raw);
|
||||
}
|
||||
|
||||
// Fallback to old behavior (often blocked in modern browsers).
|
||||
var url = OpenService && OpenService.normalizeToFileUrl ? OpenService.normalizeToFileUrl(raw) : '';
|
||||
if (!url) return;
|
||||
console.warn('Local client service failed, falling back to file:// navigation:', err);
|
||||
try {
|
||||
window.open(url, '_blank', 'noopener');
|
||||
} catch (e) {
|
||||
try {
|
||||
window.location.href = url;
|
||||
} catch (e2) {
|
||||
console.error('Failed to open file URL:', e2);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Initialize
|
||||
// ============================================================
|
||||
document.addEventListener('click', onClick, false);
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (GalleryThumbnails && GalleryThumbnails.init) GalleryThumbnails.init();
|
||||
}, false);
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (Scratchpads && Scratchpads.init) Scratchpads.init();
|
||||
}, false);
|
||||
})();
|
||||
94
js/open-service.js
Normal file
94
js/open-service.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/* global window */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Luxtools = window.Luxtools || (window.Luxtools = {});
|
||||
|
||||
// ============================================================
|
||||
// Open Service Module (file:// links)
|
||||
// ============================================================
|
||||
Luxtools.OpenService = (function () {
|
||||
function getServiceUrl(el) {
|
||||
var url = el.getAttribute('data-service-url') || '';
|
||||
url = (url || '').trim();
|
||||
if (!url) return '';
|
||||
// strip trailing slashes
|
||||
return url.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function pingOpenViaImage(el, rawPath) {
|
||||
var baseUrl = getServiceUrl(el);
|
||||
if (!baseUrl) return;
|
||||
var url = baseUrl + '/open?path=' + encodeURIComponent(rawPath);
|
||||
|
||||
// Fire-and-forget without CORS.
|
||||
try {
|
||||
var img = new window.Image();
|
||||
img.src = url;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
function openViaService(el, rawPath) {
|
||||
var baseUrl = getServiceUrl(el);
|
||||
if (!baseUrl) return Promise.reject(new Error('No client service configured'));
|
||||
|
||||
var headers = {
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
return window.fetch(baseUrl + '/open', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
credentials: 'omit',
|
||||
headers: headers,
|
||||
body: JSON.stringify({ path: rawPath })
|
||||
}).then(function (res) {
|
||||
if (!res.ok) {
|
||||
return res.json().catch(function () { return null; }).then(function (body) {
|
||||
var msg = (body && body.message) ? body.message : ('HTTP ' + res.status);
|
||||
throw new Error(msg);
|
||||
});
|
||||
}
|
||||
return res.json().catch(function () { return { ok: true }; });
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeToFileUrl(path) {
|
||||
if (!path) return '';
|
||||
|
||||
// already a file URL
|
||||
if (/^file:\/\//i.test(path)) return path;
|
||||
|
||||
// UNC path: \\server\share\path
|
||||
if (/^\\\\/.test(path)) {
|
||||
var p = path.replace(/^\\\\/, '');
|
||||
p = p.replace(/\\/g, '/');
|
||||
return 'file://///' + p;
|
||||
}
|
||||
|
||||
// Windows drive: C:\path\to\file
|
||||
if (/^[a-zA-Z]:\\/.test(path)) {
|
||||
var drive = path[0].toUpperCase();
|
||||
var rest = path.slice(2).replace(/\\/g, '/');
|
||||
return 'file:///' + drive + ':' + rest;
|
||||
}
|
||||
|
||||
// POSIX absolute: /home/user/file
|
||||
if (path[0] === '/') {
|
||||
return 'file://' + path;
|
||||
}
|
||||
|
||||
// Fall back to using the provided string.
|
||||
return path;
|
||||
}
|
||||
|
||||
return {
|
||||
openViaService: openViaService,
|
||||
pingOpenViaImage: pingOpenViaImage,
|
||||
normalizeToFileUrl: normalizeToFileUrl
|
||||
};
|
||||
})();
|
||||
})();
|
||||
187
js/scratchpads.js
Normal file
187
js/scratchpads.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/* global window, document */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Luxtools = window.Luxtools || (window.Luxtools = {});
|
||||
|
||||
// ============================================================
|
||||
// Scratchpads Module
|
||||
// ============================================================
|
||||
Luxtools.Scratchpads = (function () {
|
||||
function setEditMode(root, isEditing) {
|
||||
if (!root || !root.classList) return;
|
||||
|
||||
var view = root.querySelector('.luxtools-scratchpad-view');
|
||||
var editor = root.querySelector('.luxtools-scratchpad-editor');
|
||||
|
||||
if (isEditing) {
|
||||
root.classList.add('is-editing');
|
||||
if (view) view.hidden = true;
|
||||
if (editor) editor.hidden = false;
|
||||
} else {
|
||||
root.classList.remove('is-editing');
|
||||
if (view) view.hidden = false;
|
||||
if (editor) editor.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setStatus(root, msg) {
|
||||
var el = root.querySelector('.luxtools-scratchpad-status');
|
||||
if (!el) return;
|
||||
el.textContent = msg || '';
|
||||
}
|
||||
|
||||
function getSectok(root) {
|
||||
// Prefer a token embedded with the rendered scratchpad.
|
||||
try {
|
||||
if (root && root.getAttribute) {
|
||||
var t = String(root.getAttribute('data-sectok') || '').trim();
|
||||
if (t) return t;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Fall back to DokuWiki's global JSINFO.
|
||||
try {
|
||||
if (window.JSINFO && window.JSINFO.sectok) return String(window.JSINFO.sectok);
|
||||
} catch (e) {}
|
||||
|
||||
// Last resort: find any security token input on the page.
|
||||
try {
|
||||
var inp = document.querySelector('input[name="sectok"], input[name="securitytoken"]');
|
||||
if (inp && inp.value) return String(inp.value);
|
||||
} catch (e2) {}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function loadPad(root) {
|
||||
var endpoint = (root.getAttribute('data-endpoint') || '').trim();
|
||||
var pad = (root.getAttribute('data-pad') || '').trim();
|
||||
var pageId = (root.getAttribute('data-pageid') || '').trim();
|
||||
if (!endpoint || !pad || !pageId) return Promise.reject(new Error('missing params'));
|
||||
|
||||
var url = endpoint + '?cmd=load&pad=' + encodeURIComponent(pad) + '&id=' + encodeURIComponent(pageId);
|
||||
return window.fetch(url, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin'
|
||||
}).then(function (res) {
|
||||
return res.json().catch(function () { return null; }).then(function (body) {
|
||||
if (!res.ok || !body || body.ok !== true) {
|
||||
var msg = (body && body.error) ? body.error : ('HTTP ' + res.status);
|
||||
throw new Error(msg);
|
||||
}
|
||||
return body.text || '';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function savePad(root, text) {
|
||||
var endpoint = (root.getAttribute('data-endpoint') || '').trim();
|
||||
var pad = (root.getAttribute('data-pad') || '').trim();
|
||||
var pageId = (root.getAttribute('data-pageid') || '').trim();
|
||||
if (!endpoint || !pad || !pageId) return Promise.reject(new Error('missing params'));
|
||||
|
||||
var params = new window.URLSearchParams();
|
||||
params.set('cmd', 'save');
|
||||
params.set('pad', pad);
|
||||
params.set('id', pageId);
|
||||
params.set('text', text || '');
|
||||
params.set('sectok', getSectok(root));
|
||||
|
||||
return window.fetch(endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
body: params.toString()
|
||||
}).then(function (res) {
|
||||
return res.json().catch(function () { return null; }).then(function (body) {
|
||||
if (!res.ok || !body || body.ok !== true) {
|
||||
var msg = (body && body.error) ? body.error : ('HTTP ' + res.status);
|
||||
throw new Error(msg);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openEditor(root) {
|
||||
var editor = root.querySelector('.luxtools-scratchpad-editor');
|
||||
var textarea = root.querySelector('textarea.luxtools-scratchpad-text');
|
||||
if (!editor || !textarea) return;
|
||||
|
||||
setEditMode(root, true);
|
||||
setStatus(root, 'Loading…');
|
||||
textarea.disabled = true;
|
||||
|
||||
loadPad(root).then(function (text) {
|
||||
textarea.value = text;
|
||||
textarea.disabled = false;
|
||||
setStatus(root, '');
|
||||
textarea.focus();
|
||||
}).catch(function (e) {
|
||||
textarea.disabled = false;
|
||||
setStatus(root, 'Load failed: ' + (e && e.message ? e.message : 'error'));
|
||||
});
|
||||
}
|
||||
|
||||
function closeEditor(root) {
|
||||
var editor = root.querySelector('.luxtools-scratchpad-editor');
|
||||
if (!editor) return;
|
||||
|
||||
setEditMode(root, false);
|
||||
setStatus(root, '');
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
var t = e.target;
|
||||
if (!t) return;
|
||||
|
||||
var edit = t.closest ? t.closest('a.luxtools-scratchpad-edit') : null;
|
||||
if (edit) {
|
||||
var root = edit.closest('div.luxtools-scratchpad');
|
||||
if (!root) return;
|
||||
e.preventDefault();
|
||||
openEditor(root);
|
||||
return;
|
||||
}
|
||||
|
||||
var save = t.closest ? t.closest('button.luxtools-scratchpad-save') : null;
|
||||
if (save) {
|
||||
var rootS = save.closest('div.luxtools-scratchpad');
|
||||
if (!rootS) return;
|
||||
e.preventDefault();
|
||||
var textareaS = rootS.querySelector('textarea.luxtools-scratchpad-text');
|
||||
if (!textareaS) return;
|
||||
textareaS.disabled = true;
|
||||
setStatus(rootS, 'Saving…');
|
||||
savePad(rootS, textareaS.value).then(function () {
|
||||
setStatus(rootS, 'Saved. Reloading…');
|
||||
try { window.location.reload(); } catch (err) {}
|
||||
}).catch(function (err) {
|
||||
textareaS.disabled = false;
|
||||
setStatus(rootS, 'Save failed: ' + (err && err.message ? err.message : 'error'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var cancel = t.closest ? t.closest('button.luxtools-scratchpad-cancel') : null;
|
||||
if (cancel) {
|
||||
var rootC = cancel.closest('div.luxtools-scratchpad');
|
||||
if (!rootC) return;
|
||||
e.preventDefault();
|
||||
closeEditor(rootC);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
var pads = document.querySelectorAll('div.luxtools-scratchpad[data-luxtools-scratchpad="1"]');
|
||||
if (!pads || !pads.length) return;
|
||||
document.addEventListener('click', onClick, true);
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
})();
|
||||
})();
|
||||
Reference in New Issue
Block a user