Skip to main content

max / makenotwork

7.0 KB · 191 lines History Blame Raw
1 // actions-tabs.js
2 // Delegated handler functions extracted from inline on* attributes in
3 // templates/partials/tabs/**, for CSP compliance (no script-src 'unsafe-inline').
4 // The dispatcher in the core module invokes each named function with `this` === the
5 // dispatching element and args drawn from data-arg / data-arg2. Bodies are the
6 // verbatim former inline handlers, adjusted only to read args from the element.
7
8 // --- item_overview.html ---
9 window.openInNewTab = function (url) {
10 window.open(url, '_blank');
11 };
12
13 window.copyItemLink = function (path) {
14 navigator.clipboard.writeText(window.location.origin + path).then(() => this.textContent = 'Copied!').catch(() => this.textContent = 'Failed');
15 };
16
17 window.openEmbedSection = function () {
18 var d = document.querySelector('details.content-section'); if (d) { d.open = true; d.scrollIntoView({ behavior: 'smooth' }); }
19 };
20
21 // --- item_embed.html ---
22 window.copyEmbedBtn = function () {
23 copyEmbed(this);
24 };
25
26 // --- project_settings.html ---
27 window.submitProjectInfo = function () {
28 saveProjectInfo({ preventDefault: function () {} }, this.getAttribute('data-project-id'));
29 };
30
31 window.submitProjectPricing = function () {
32 saveProjectPricing({ preventDefault: function () {} }, this.getAttribute('data-project-id'));
33 };
34
35 // --- item_pricing.html ---
36 window.togglePwywSettings = function () {
37 document.getElementById('pwyw-settings').classList.toggle('hidden', !this.checked);
38 };
39
40 window.toggleCustomLicense = function () {
41 document.getElementById('dash-custom-license').classList.toggle('hidden', this.value !== 'custom');
42 };
43
44 window.toggleLicenseKeys = function () {
45 document.getElementById('license-keys-section').classList.toggle('hidden', !this.checked);
46 };
47
48 // --- project_synckit.html / user_synckit.html ---
49 window.syncKitShowSlugFromBtn = function (appId) {
50 syncKitShowSlugForm(appId, this.dataset.slug);
51 };
52
53 window.syncKitDeleteFromBtn = function (appId) {
54 syncKitDeleteApp(appId, this.dataset.name);
55 };
56
57 // --- project_promotions.html ---
58 window.onPromoTypeChange = function () {
59 togglePromoFields(this.value);
60 };
61
62 window.syncTrialDays = function () {
63 document.getElementById('pc-trial-days').value = this.value;
64 };
65
66 // --- user_payments.html ---
67 window.submitOwnForm = function () {
68 this.form.requestSubmit();
69 };
70
71 // --- project_content.html ---
72 window.deselectAll = function () {
73 toggleSelectAll(false);
74 };
75
76 window.toggleSelectAllFromEl = function () {
77 toggleSelectAll(this.checked);
78 };
79
80 window.sortContent = function (colIndex, sortType) {
81 sortContentTable(parseInt(colIndex, 10), sortType);
82 };
83
84 // --- library_collections.html ---
85 window.slugifyCollName = function () {
86 document.getElementById('new-coll-slug').value = this.value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
87 };
88
89 // --- library_purchases.html ---
90 window.filterLibraryRows = function () {
91 (function (q) { var rows = document.querySelectorAll('#library-table tbody tr'); q = q.toLowerCase(); rows.forEach(function (r) { r.classList.toggle('hidden', r.textContent.toLowerCase().indexOf(q) === -1); }); })(this.value);
92 };
93
94 window.copyKeyCode = function (code) {
95 window.copyWithFeedback(this, code, 'Copied!', 1500);
96 };
97
98 window.toggleContextMenuBtn = function (itemId) {
99 toggleContextMenu({ stopPropagation: function () {} }, itemId);
100 };
101
102 window.openCollectionPickerBtn = function (itemId) {
103 openCollectionPicker(itemId, this);
104 };
105
106 // --- user_profile.html ---
107 // The link row's five wrappers are gone: user_profile.html includes
108 // partials/link_row.html rather than respelling it, so the row's one set of
109 // verbs (onMoveLink/onEditLink/onSaveLink/onCancelLink, in actions-partials.js)
110 // serves both the loop and the HTMX-inserted fragment.
111 window.copyElementText = function (id) {
112 window.copyWithFeedback(this, document.getElementById(id).textContent, 'Copied', 1500);
113 };
114
115 // 2000ms here rather than the 1500 every other copy button uses. Preserved as
116 // found: which of the two is right is a question for the semantic-timing work,
117 // not for a consolidation pass.
118 window.copyFeedUrl = function () {
119 window.copyWithFeedback(this, document.getElementById('feed-url').value, 'Copied!', 2000);
120 };
121
122 // --- user_media.html ---
123 window.onMediaFilesChange = function () {
124 mediaUploadFiles(this.files);
125 };
126
127 window.mediaFilterAll = function () {
128 mediaFilterFolder(null, this);
129 };
130
131 window.mediaFilterFolderBtn = function (folder) {
132 mediaFilterFolder(folder, this);
133 };
134
135 window.mediaDeleteFileBtn = function (id) {
136 mediaDeleteFile(id, this.dataset.filename);
137 };
138
139 // --- item_details.html ---
140 window.onSearchTagsInput = function () {
141 searchTags(this.value);
142 };
143
144 window.syncItemHiddenFields = function () {
145 document.getElementById('hidden-title').value = document.getElementById('item-name').value; document.getElementById('hidden-desc').value = document.getElementById('item-description').value; document.getElementById('hidden-ai-tier').value = document.getElementById('ai_tier').value; document.getElementById('hidden-ai-disclosure').value = document.getElementById('ai_disclosure').value;
146 };
147
148 // --- user_creator.html ---
149 window.toggleTrialDetails = function () {
150 document.getElementById('trial-details').classList.toggle('hidden', !this.checked);
151 };
152
153 // --- Non-dispatcher delegated listeners ---
154 // The the core module dispatcher only covers click/change/input/submit. The handlers
155 // below cover drag-and-drop (user_media) and conditional submit (user_account),
156 // keyed on data attributes so the inline handlers can be removed.
157
158 // Media upload drop zone (user_media.html): former ondragover/ondragleave/ondrop.
159 document.addEventListener('dragover', function (e) {
160 var el = e.target.closest('[data-media-dropzone]');
161 if (!el) return;
162 e.preventDefault(); el.classList.add('user-media-upload--dragover');
163 });
164 document.addEventListener('dragleave', function (e) {
165 var el = e.target.closest('[data-media-dropzone]');
166 if (!el) return;
167 el.classList.remove('user-media-upload--dragover');
168 });
169 document.addEventListener('drop', function (e) {
170 var el = e.target.closest('[data-media-dropzone]');
171 if (!el) return;
172 mediaHandleDrop(e); el.classList.remove('user-media-upload--dragover');
173 });
174
175 // Conditional submit guard (user_account.html): a former onsubmit that returned
176 // false to block submission. Runs in capture phase so a false result can stop
177 // propagation before htmx's submit handler sees the event.
178 document.addEventListener('submit', function (e) {
179 var el = e.target.closest('[data-check-submit]');
180 if (!el) return;
181 var fn = window[el.getAttribute('data-check-submit')];
182 if (typeof fn === 'function') {
183 var r = fn.call(el, e);
184 if (r === false) { e.preventDefault(); e.stopPropagation(); }
185 }
186 }, true);
187
188 window.checkPasswordMatch = function () {
189 var np = document.getElementById('new-password').value, cp = document.getElementById('confirm-password').value; if (np !== cp) { var s = document.getElementById('password-status'); s.textContent = 'Passwords do not match'; s.classList.add('danger-text'); return false; }
190 };
191