Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Machy8 committed Nov 7, 2023
1 parent 285c6e0 commit a2e060b
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 80 deletions.
60 changes: 52 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,31 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta snippet="spa-cache-control" name="spa-cache-control" content="cache">
<title snippet="title">Index page</title>
<!-- <script type="module" src="http://localhost:5173/@vite/client"></script> -->
<script type="module">
<!-- <script type="module">
import Signalize from 'signalizejs';
import directives from 'signalizejs/directives';
const $ = new Signalize({
plugins: [ directives ]
const { bind, select, signal } = new Signalize({
plugins: [ ]
});
</script>
const smallerNumber = signal(0);
const largerNumber = signal(0);
smallerNumber.watch(({ newValue, oldValue }) => {
return {
value: newValue >= largerNumber() ? largerNumber() - 1 : newValue,
}
}, { execution: 'beforeSet' });
smallerNumber.watch(({ newValue, oldValue }) => {
console.log(newValue, oldValue);
});
bind(select('#smaller'), { value: smallerNumber });
bind(select('#larger'), { value: largerNumber });
bind(select('#sum'), { text: [smallerNumber, largerNumber, () => largerNumber + smallerNumber]})
</script> -->
</head>

<body>
Expand All @@ -25,8 +41,36 @@
}
</style>

<form $items="[]" $value="" @submit="() => {
$event.preventDefault();
items.set([...new Set([...items(), value()])]);
value.set('');
}">
<!-- Shortcuts for attribute binding -->
<input {value} placeholder="Type something" required>
<button>Add</button>
<br>
<!-- Native for of/in loops -->
<template :for="item of items">
<!-- Iterator feature: count, first, last, odd, even -->
<div :text="item + (iterator.last ? '' : ', ')" :style="iterator.odd ? 'color:red': 'color:blue'"></div>
</template>
</form>
<script type="module">
import Signalize from 'signalizejs';
import directives from 'signalizejs/directives';

// Use the directives plugin
new Signalize({ plugins: [directives()] })
</script>

<!-- <input id="smaller" type="number">
<input id="larger" type="number">
<div id="sum"></div>
-->
<!-- Conditional loop for large amount of elements -->
<!-- <div $text="'Hello World!'" $count="10">
<div $text="'Hello World!'" $count="10">
<input :value="text">
<button @click="count.set(count() + 1)">Přidej<span :text="count"></span></button>
<button @click="count.set(count() - 1)">Odeber<span :text="count"></span></button><br>
Expand All @@ -42,7 +86,7 @@
</li>
</template>
</ul>
</div> -->
</div>

<!-- <div $text="">
<input :value="text">
Expand Down Expand Up @@ -104,7 +148,7 @@
<!-- <template :for="i in 1100">
<div :text="i"></div>
</template> -->
<!-- <button $count="0" @click="count.set(count() + 1)">Count <span :text="count"></span></button>
<!-- <button $count="0" @click="count.set(count() + 1)">Count <span :text="count"></span></button>
-->
<!-- <div $text="'Longer'">
<template :if="text().length < 2">
Expand Down
130 changes: 81 additions & 49 deletions packages/signalizejs/directives/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface RegisteredDirective extends Directive {
interface ProcessDirectiveOptions {
root?: Element
directiveName?: string
reinit?: boolean
}

interface CreateFunctionOptions {
Expand All @@ -52,7 +53,7 @@ interface PluginOptions {
export default (options?: PluginOptions): SignalizePlugin => {

return ($: Signalize) => {
const { bind, on, Signal, scope, signal, globals, attributePrefix, attributeSeparator } = $;
const { bind, on, scope, signal, globals, attributePrefix, attributeSeparator } = $;
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
const directives: Record<string, RegisteredDirective> = {};
const directivesAttribute = `${attributePrefix}directives`;
Expand All @@ -62,7 +63,11 @@ export default (options?: PluginOptions): SignalizePlugin => {
const renderedTemplateEndComment = options?.renderedBlockEnd ?? '/template';
let inited = false;

const processElement = async (element: Element, directivesToProcess?: string[]): Promise<Element> => {
const processElement = async (options?: ProcessElementOptions): Promise<Element> => {
const element: Element = options.element;
const directivesToProcess = options.directives ?? [];
const reinit = options.reinit ?? false;

const elementClosestScope = element.closest(`[${$.scopeAttribute}]`);
let scopeInitPromise = null;

Expand All @@ -80,6 +85,14 @@ export default (options?: PluginOptions): SignalizePlugin => {
await scopeInitPromise;
}

const elementScope = scope(element, (elementScope) => {
if (!('directives' in elementScope)) {
elementScope.directives = new Map();
}
});

const compiledDirectives = elementScope.directives;

let directivesQueue = [...directivesToProcess ?? Object.keys(directives)];
const customDirectivesOrder = element.getAttribute(orderAttribute) ?? '';

Expand All @@ -90,15 +103,13 @@ export default (options?: PluginOptions): SignalizePlugin => {
])]
}

if (directivesQueue.length > 0) {
let countdown = element.attributes.length;
const processDirectiveFromQueue = async (directiveName: string): Promise<void> => {
if (directiveName === undefined) {
return;
}
directivesQueue = directivesQueue.filter((item) => !compiledDirectives.has(item));

if (directivesQueue.length > 0) {
while (directivesQueue.length) {
const directiveName = directivesQueue.shift();
const matcher = directives[directiveName]?.matcher
let directivesPromises = [];

for (const attribute of element.attributes) {
const matcherReturn = matcher({ element, attribute });

Expand All @@ -112,46 +123,54 @@ export default (options?: PluginOptions): SignalizePlugin => {
}

const directive = directives[directiveName];
const elementScope = scope(element, (elementScope) => {
if (!('directives' in elementScope)) {
elementScope.directives = new Set();
}

elementScope.directives.add(directiveName);
scope(element, (elementScope) => {
elementScope.directives.set(
directiveName,
[
...elementScope.directives.get(directiveName) ?? [],
(elementScope) => {
return directive.callback({
...elementScope,
data: elementScope.data,
matches,
attribute
})
}
]
);
});

countdown--;
directivesPromises.push(
directive.callback({
...elementScope,
data: elementScope.data,
matches,
attribute
})
)
}
}
}

if (directivesPromises.length > 0) {
await Promise.all(directivesPromises);
}
const directivesToRun = [...elementScope.directives.keys()]

if (countdown === 0) {
return;
}
const runDirective = async (name: string): Promise<void> => {
const promises = [];

return processDirectiveFromQueue(directivesQueue.shift());
for (const directiveFunction of elementScope.directives.get(name)) {
promises.push(directiveFunction(elementScope));
}

await processDirectiveFromQueue(directivesQueue.shift());
await Promise.all(promises);

if (directivesToRun.length > 0) {
await runDirective(directivesToRun.shift());
}
}

element.removeAttribute($.cloakAttribute);
if (directivesToRun.length > 0) {
await runDirective(directivesToRun.shift());
}

element.removeAttribute($.cloakAttribute);

return element;
};

const processDirectives = async (options: ProcessDirectiveOptions = { root: $.root }): Promise<Element | Document | DocumentFragment> => {
let { root, directiveName } = options;
// TODO reinit
let { root, directiveName, reinit = false } = options;
const directivesToProcess = directiveName === undefined ? Object.keys(directives) : [directiveName];

const processElements = async (root): Promise<void> => {
Expand All @@ -162,7 +181,10 @@ export default (options?: PluginOptions): SignalizePlugin => {
}

if (rootIsElement) {
await processElement(root, directivesToProcess);
await processElement({
element: root,
directives: directivesToprocess
});
}

const elementsProcessingPromises = []
Expand Down Expand Up @@ -292,7 +314,7 @@ export default (options?: PluginOptions): SignalizePlugin => {
data[key] = value;
}
});
directivesProcessingPromises.push(processElement(child));
directivesProcessingPromises.push(processElement({ element: child }));
}
}

Expand Down Expand Up @@ -327,11 +349,13 @@ export default (options?: PluginOptions): SignalizePlugin => {
iterator: {
count: counter,
first: counter === 0,
last: counter === totalCount,
last: counter === totalCount - 1,
odd: counter % 2 !== 0,
even: counter % 2 === 0
}
});

counter++;
}

if (argumentsMatch[2] === 'in') {
Expand All @@ -346,7 +370,6 @@ export default (options?: PluginOptions): SignalizePlugin => {

const currentState = [];
let nextElementSibling = element.nextElementSibling;

while (nextElementSibling !== null) {
if (scope(nextElementSibling)?.template !== element) {
break;
Expand All @@ -362,23 +385,25 @@ export default (options?: PluginOptions): SignalizePlugin => {
const fragments = await Promise.all(directivesProcessingPromises);

const reinitDirectives = (element) => {
const elementScope = scope(element);
processDirectives({
root: element,
reinit: true
})
/* const elementScope = scope(element);
if (elementScope !== undefined && elementScope?.directives !== undefined) {
elementScope.cleanup();
const directivesQueue = elementScope.directives;
elementScope.directives.clear();
processElement(element, directivesQueue);
processElement(element);
}
for (const child of element.children) {
reinitDirectives(child);
}
} */
}

const fragmentsLength = fragments.length;
while (fragments.length > 0) {
const root = fragments.shift();
scope(root, (rootScope) => {
const rootScope = scope(root, (rootScope) => {
rootScope.template = element;
});
const rootKey = root.getAttribute('key')
Expand Down Expand Up @@ -407,13 +432,21 @@ export default (options?: PluginOptions): SignalizePlugin => {
currentState[i] = existingItem
currentState[existingItemIndex] = tmp;
}
} else {
const existingItemScope = scope(existingItem);

for (const [key, value] of Object.entries(rootScope.data)) {
existingItemScope.data[key] = value;
}

reinitDirectives(existingItem);
}
} else if (i >= currentState.length) {
lastInsertPoint.after(root);
lastInsertPoint = root;
for (const child of root.children) {
scope(child, ({ data }) => {
data = scope(root).data
data = rootScope.data
});

processDirectives({ root: child });
Expand All @@ -425,7 +458,7 @@ export default (options?: PluginOptions): SignalizePlugin => {
} else if (currentState.length > 0 && i < currentState.length) {
const fragmentScope = scope(currentState[i]);

for (const [key, value] of Object.entries(scope(root).data)) {
for (const [key, value] of Object.entries(rootScope.data)) {
fragmentScope.data[key] = value;
}

Expand All @@ -437,7 +470,7 @@ export default (options?: PluginOptions): SignalizePlugin => {
lastInsertPoint = root;
for (const child of root.children) {
scope(child, ({ data }) => {
data = scope(root).data
data = rootScope.data
});

processDirectives({ root: child });
Expand Down Expand Up @@ -466,7 +499,6 @@ export default (options?: PluginOptions): SignalizePlugin => {
}

await process();

unwatchSignalCallbacks = [];
for (const signalToWatch of signalsToWatch) {
unwatchSignalCallbacks.push(signalToWatch.watch(process))
Expand Down
2 changes: 1 addition & 1 deletion packages/signalizejs/src/Signalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface SignalizeOptions {
attributeSeparator: string
attributePrefix: string
globals?: SignalizeGlobals
plugins?: SignalizePlugin
plugins?: SignalizePlugin[]
}

export type SignalizePlugin = (signalize: Signalize) => void
Expand Down
Loading

0 comments on commit a2e060b

Please sign in to comment.