Skip to content

Commit 647e4b1

Browse files
authored
Merge pull request #1 from dotpipe/everything-working-
"inline" added
2 parents 07f7631 + 54215f6 commit 647e4b1

16 files changed

Lines changed: 13787 additions & 91 deletions

File tree

API/dotpipe.js

Lines changed: 169 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*
66
* All custom tags MUST include a unique 'id' attribute.
77
* Most attributes/classes can be combined for powerful UI behaviors.
8-
* See below for supported elements, attributes, and their usage.
8+
* Inline macros can be used via the 'inline' attribute for dynamic, per-element logic.
9+
* See below for supported elements, attributes, and inline macro usage.
910
*
1011
* ──────────────────────────────────────────────────────────────
1112
* CUSTOM TAGS
@@ -30,6 +31,8 @@
3031
* UNIVERSAL ATTRIBUTES
3132
*
3233
* id REQUIRED for all custom tags. Must be unique.
34+
* inline Optional inline macro string to define dynamic logic per element.
35+
* Supports operators: |, |!, |$, |$id:varName, nop:varName, |@id.prop:varName, |#varName:id.prop, |%funcName:[args]
3336
* ajax Fetch remote resource (HTML, JSON, etc.) for tag.
3437
* insert Target ID to render AJAX response.
3538
* query Key-value pairs for AJAX requests, e.g. "key:value&"
@@ -76,6 +79,31 @@
7679
* lazy-load For <csv>; enable/disable lazy loading (default true).
7780
*
7881
* ──────────────────────────────────────────────────────────────
82+
* INLINE MACROS
83+
*
84+
* The 'inline' attribute allows per-element dynamic logic using dotPipe pipe operators:
85+
*
86+
* Operators:
87+
* | Self-retained (current element context passes forward)
88+
* |! Pass previous return value forward
89+
* |$id Inject current value into element by ID
90+
* |$id:varName Inject stored variable into element by ID
91+
* nop:varName Store current value in dpVars for later use
92+
* |@id.prop:varName Write stored variable into target element property
93+
* |#varName:id.prop Read element property into variable
94+
* |%funcName:[args] Execute function with arguments (supports #varName and @id.prop)
95+
*
96+
* Example usage:
97+
* <div id="fa" inline="ajax:/api/new:GET|!nop:newData|$resultsDiv:newData"></div>
98+
* <div id="fb" inline="ajax:/api/list:GET|!nop:list|%processData:[#list,@outputDiv.innerText]|@outputDiv.innerText:list"></div>
99+
*
100+
* Inline macros can be automatically executed on DOMContentLoaded or triggered manually via:
101+
* dotPipe.runInline('fa');
102+
*
103+
* Variables used in inline macros are scoped per element in a dpVars object.
104+
* Functions called with |% can be native, plugin-registered, or globally available.
105+
*
106+
* ──────────────────────────────────────────────────────────────
79107
* SUPPORT CLASSES
80108
*
81109
* download Enables file download behavior.
@@ -123,8 +151,9 @@
123151
* <item id="gadget-2" name="Gadget" price="14.99"></item>
124152
* </cart>
125153
*
126-
* <!-- Search box for filtering content -->
127-
* <search id="search" use-id="product-list;order-list" placeholder="Find products..."></search>
154+
* <!-- Inline macros -->
155+
* <div id="fa" inline="ajax:/api/new:GET|!nop:newData|$resultsDiv:newData"></div>
156+
* <div id="fb" inline="ajax:/api/list:GET|!nop:list|%processData:[#list,@outputDiv.innerText]|@outputDiv.innerText:list"></div>
128157
*
129158
* <!-- Carousel slider -->
130159
* <carousel id="image-carousel" sources="img1.jpg;img2.jpg;img3.jpg" delay="3000" boxes="1"></carousel>
@@ -135,15 +164,15 @@
135164
* ──────────────────────────────────────────────────────────────
136165
* SYSTEM FLOW:
137166
* - On DOMContentLoaded, dotPipe processes all supported custom tags.
138-
* - pipes() manages all custom tag logic, triggers AJAX, updates DOM, and runs callbacks.
167+
* - pipes() manages all custom tag logic, triggers AJAX, updates DOM, runs callbacks, and executes inline macros.
168+
* - Inline macros are parsed via regex, support all pipe operators, and store variables per element in dpVars.
139169
* - navigate() performs AJAX requests and inserts responses.
140170
* - modala() loads and renders JSON templates for modals and complex UIs.
141171
*
142-
* For advanced usage, refer to the full documentation or source code.
143-
*
144172
* (c) dotPipe.js – https://github.com/dotpipe/dotPipe
145173
*/
146174

175+
147176
document.addEventListener("DOMContentLoaded", function () {
148177
try {
149178
if (document.body != null && JSON.parse(document.body.textContent)) {
@@ -178,6 +207,136 @@ document.addEventListener("DOMContentLoaded", function () {
178207
});
179208
});
180209

210+
const dotPipe = {
211+
matrix: {},
212+
213+
// Register all elements with inline macros
214+
register: function(selector = '[inline]') {
215+
const elements = document.querySelectorAll(selector);
216+
elements.forEach(el => {
217+
const key = el.id || el.getAttribute('pipe') || Symbol();
218+
this.matrix[key] = {
219+
element: el,
220+
inlineMacro: el.getAttribute('inline'),
221+
dpVars: {} // plain storage; no auto-run
222+
};
223+
});
224+
},
225+
226+
// Run inline macro for a given element manually
227+
runInline: async function(key) {
228+
const entry = this.matrix[key];
229+
if (!entry || !entry.inlineMacro) return;
230+
231+
let currentValue = null;
232+
const segments = entry.inlineMacro.split('|').filter(s => s.trim() !== '');
233+
234+
for (let seg of segments) {
235+
seg = seg.trim();
236+
let m;
237+
238+
// |&varName:value → store literal
239+
if (m = /^\&([a-zA-Z0-9_]+):(.+)$/.exec(seg)) {
240+
const varName = m[1];
241+
const value = m[2];
242+
entry.dpVars[varName] = value;
243+
currentValue = value;
244+
continue;
245+
}
246+
247+
// nop:varName → store current value
248+
if (m = /^nop:([a-zA-Z0-9_]+)$/.exec(seg)) {
249+
const varName = m[1];
250+
entry.dpVars[varName] = currentValue;
251+
continue;
252+
}
253+
254+
// $id or $id:varName → inject value into element
255+
if (m = /^\$([a-zA-Z0-9_-]+)(?::([a-zA-Z0-9_!]+))?$/.exec(seg)) {
256+
const targetId = m[1];
257+
const varName = m[2];
258+
const targetEl = document.getElementById(targetId);
259+
if (targetEl) {
260+
let value;
261+
if (!varName) value = currentValue;
262+
else if (varName.startsWith('!')) value = entry.dpVars[varName.slice(1)];
263+
else value = entry.dpVars[varName];
264+
targetEl.innerHTML = value;
265+
}
266+
continue;
267+
}
268+
269+
// @id.prop:varName → set element property
270+
if (m = /^@([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_]+):([a-zA-Z0-9_!]+)$/.exec(seg)) {
271+
const targetEl = document.getElementById(m[1]);
272+
const prop = m[2];
273+
const varName = m[3];
274+
if (targetEl) {
275+
let value = varName.startsWith('!') ? entry.dpVars[varName.slice(1)] : entry.dpVars[varName];
276+
targetEl[prop] = value;
277+
}
278+
continue;
279+
}
280+
281+
// #varName:id.prop → read element property
282+
if (m = /^#([a-zA-Z0-9_]+):([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_]+)$/.exec(seg)) {
283+
const varName = m[1];
284+
const targetEl = document.getElementById(m[2]);
285+
const prop = m[3];
286+
if (targetEl) {
287+
entry.dpVars[varName] = targetEl[prop];
288+
currentValue = entry.dpVars[varName];
289+
}
290+
continue;
291+
}
292+
293+
// %funcName:[args] → call function
294+
if (m = /^\%([a-zA-Z0-9_]+):\[(.+)\]$/.exec(seg)) {
295+
const funcName = m[1];
296+
let args = m[2].split(',').map(a => a.trim()).map(arg => {
297+
if (arg.startsWith('!')) return entry.dpVars[arg.slice(1)];
298+
if (arg.startsWith('#')) return entry.dpVars[arg.slice(1)];
299+
if (arg.startsWith('@')) {
300+
const [elId, prop] = arg.slice(1).split('.');
301+
const targetEl = document.getElementById(elId);
302+
return targetEl ? targetEl[prop] : undefined;
303+
}
304+
return arg;
305+
});
306+
if (typeof window[funcName] === 'function') {
307+
currentValue = await window[funcName](...args);
308+
}
309+
continue;
310+
}
311+
312+
// Standard verb: e.g., ajax:url:GET
313+
if (m = /^([a-zA-Z0-9_]+):?(.*)$/.exec(seg)) {
314+
const verb = m[1];
315+
const params = m[2] ? m[2].split(':') : [];
316+
if (typeof this.verbs[verb] === 'function') {
317+
currentValue = await this.verbs[verb](...params);
318+
}
319+
continue;
320+
}
321+
322+
console.warn('Unknown pipe segment:', seg);
323+
}
324+
},
325+
326+
// Built-in verbs (AJAX, log, etc.)
327+
verbs: {
328+
async ajax(url, method = 'GET') {
329+
const res = await fetch(url, { method });
330+
const text = await res.text();
331+
return text;
332+
},
333+
log(value) {
334+
console.log(value);
335+
return value;
336+
}
337+
}
338+
};
339+
181340
let domContentLoad = (again = false) => {
182341
doc_set = document.getElementsByTagName("pipe");
183342
if (again == false) {
@@ -220,7 +379,7 @@ let domContentLoad = (again = false) => {
220379
processCartTags();
221380
processOrderConfirmationTags();
222381
processColumnsTags();
223-
382+
dotPipe.register();
224383

225384
let elements_Carousel = document.getElementsByTagName("carousel");
226385
Array.from(elements_Carousel).forEach(function (elem) {
@@ -5172,6 +5331,9 @@ function pipes(elem, stop = false) {
51725331
if (elem.id === null)
51735332
return;
51745333

5334+
if (elem.hasAttribute("inline"))
5335+
dotPipe.runInline(elem.id);
5336+
51755337
if (elem.hasAttribute("callback") && typeof window[elem.getAttribute("callback")] === "function") {
51765338
var params = [];
51775339
const calls = sortNodesByName("." + elem.getAttribute("callback-class"));

0 commit comments

Comments
 (0)