Skip to content

Commit

Permalink
refactoring of async view
Browse files Browse the repository at this point in the history
  • Loading branch information
vintikzzz committed Sep 28, 2024
1 parent 537bac6 commit eb2d949
Show file tree
Hide file tree
Showing 21 changed files with 102 additions and 119 deletions.
5 changes: 2 additions & 3 deletions assets/src/js/app/action.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const target = document.currentScript.parentElement;
const av = (await import('../lib/asyncView')).initAsyncView;
av(target, 'action/post', async function() {
import av from '../lib/av';
av(async function() {
const self = this;
const progress = self.querySelector('form');
const el = document.createElement('div');
Expand Down
5 changes: 2 additions & 3 deletions assets/src/js/app/action/image.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
const target = document.currentScript.parentElement;
import av from '../../lib/av';

function ready() {
const event = new CustomEvent('player_ready');
window.dispatchEvent(event);
}


const av = (await import('../../lib/asyncView')).initAsyncView;
av(target, 'action/preview_image', () => {
av(() => {
ready();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const target = document.currentScript.parentElement;
import av from '../../lib/av';

function ready() {
const event = new CustomEvent('player_ready');
window.dispatchEvent(event);
}

const av = (await import('../../lib/asyncView')).initAsyncView;
av(target, 'action/stream_audio', async function() {
av(async function() {
const initPlayer = (await import('../../lib/mediaelement')).initPlayer;
initPlayer(this, ready);
}, async function() {
Expand Down
17 changes: 0 additions & 17 deletions assets/src/js/app/action/video.js

This file was deleted.

9 changes: 0 additions & 9 deletions assets/src/js/app/auth.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {init, refresh} from '../lib/supertokens';
const av = (await import('../lib/asyncView')).initAsyncView;

av(document.querySelector('nav'), 'index', async function() {
const self = this;
window.addEventListener('auth', function() {
self.reload();
}, { once: true });
});

try {
await init(window._CSRF);
} catch (err) {
Expand Down
7 changes: 3 additions & 4 deletions assets/src/js/app/auth/logout.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const target = document.currentScript.parentElement;
const av = (await import('../../lib/asyncView')).initAsyncView;
av(target, 'auth/logout', async function() {
import av from '../../lib/av';
av( async function() {
const initProgressLog = (await import('../../lib/progressLog')).initProgressLog;
const pl = initProgressLog(target.querySelector('.progress-alert'));
const pl = initProgressLog(this.querySelector('.progress-alert'));
pl.clear();
const e = pl.inProgress('logout', 'logging out');
const supertokens = (await import('../../lib/supertokens'));
Expand Down
7 changes: 3 additions & 4 deletions assets/src/js/app/auth/verify.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const target = document.currentScript.parentElement;
const av = (await import('../../lib/asyncView')).initAsyncView;
av(target, 'auth/verify', async function() {
import av from '../../lib/av';
av( async function() {
const initProgressLog = (await import('../../lib/progressLog')).initProgressLog;
const pl = initProgressLog(target.querySelector('.progress-alert'));
const pl = initProgressLog(this.querySelector('.progress-alert'));
pl.clear();
const e = pl.inProgress('verify', 'checking magic link');
const supertokens = (await import('../../lib/supertokens'));
Expand Down
7 changes: 3 additions & 4 deletions assets/src/js/app/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const target = document.currentScript.parentElement;
const av = (await import('../lib/asyncView')).initAsyncView;
av(target, 'index', async function() {
const dropzone = target.querySelector('.dropzone');
import av from '../lib/av';
av(async function() {
const dropzone = this.querySelector('.dropzone');
if (dropzone) {
const initDrop = (await import('../lib/drop')).initDrop;
initDrop(dropzone);
Expand Down
10 changes: 4 additions & 6 deletions assets/src/js/app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ window.progress = {
};

import {bindAsync} from '../lib/async';
const av = (await import('../lib/asyncView')).initAsyncView;
import themeSelector from "../lib/themeSelector";
import initAsyncView from '../lib/asyncView';
initAsyncView();

const initTheme = (await import('../lib/themeSelector')).initTheme;
function onLoad() {
themeSelector(document.querySelector('[data-toggle-theme]'));
av(document.querySelector('nav'), 'index', async function() {
themeSelector(document.querySelector('[data-toggle-theme]'));
});
initTheme(document.querySelector('[data-toggle-theme]'));
document.body.style.display = 'flex';
hideProgress();
bindAsync({
Expand Down
12 changes: 12 additions & 0 deletions assets/src/js/app/nav.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import av from '../lib/av';
av(async function() {
const self = this;
const themeSelector = (await import('../lib/themeSelector')).themeSelector;
themeSelector(this.querySelector('[data-toggle-theme]'));
window.addEventListener('auth', function() {
self.reload();
}, { once: true });
});

export {}

7 changes: 3 additions & 4 deletions assets/src/js/app/support.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const target = document.currentScript.parentElement;
const av = (await import('../lib/asyncView')).initAsyncView;
import av from '../lib/av';

function setRequied(input) {
if (input.getAttribute('data-required') !== null) {
Expand Down Expand Up @@ -29,8 +28,8 @@ function updateForm(select, inputs, submit) {
}
}

av(target, 'support/form', async function() {
const form = target.querySelector('form');
av(async function() {
const form = this.querySelector('form');
const select = form.querySelector('select');
const inputs = form.querySelectorAll('input, textarea');
const submit = form.querySelector('button');
Expand Down
4 changes: 1 addition & 3 deletions assets/src/js/lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ async function asyncFetch(url, targetSelector, fetchParams, params) {
}
const res = await fetchFunc(url, fetchParams);
const text = await res.text();
const template = res.headers.get('X-Template');
loadAsyncView(target, text, template, layout);
loadAsyncView(target, text, params);
return res;
}
async function async(selector, params = {}, scope = null) {
Expand Down Expand Up @@ -164,7 +163,6 @@ function asyncGet(p = {}) {
async('*[data-async-get]', params);
}


export function bindAsync(params = {}) {
asyncLinks(params);
asyncForms(params);
Expand Down
46 changes: 27 additions & 19 deletions assets/src/js/lib/asyncView.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import MD5 from "crypto-js/md5";
import {makeDebug} from './debug';
const debug = await makeDebug('webtor:embed:message');
export function initAsyncView(target, name, init, destroy) {
const layout = target.getAttribute('data-async-layout');
if (layout) {
name = name + '_' + MD5(layout).toString();
export default function init() {
if (window.av) {
for (const data of window.av) {
initAsyncView(...data);
}
}
const onLoad = function(e) {
debug(`webtor:async view loaded name=%o`, name);
if (e && e.detail && e.detail.target) {
target = e.detail.target;
window.av = {
push(data) {
initAsyncView(...data);
}
target.classList.add('async-view');
target.classList.add(`async-view-${name}`);
// In case if async binding has not been invoked
}
}
function initAsyncView(target, init, destroy) {
const scripts = target.getElementsByTagName('script');
const src = scripts[scripts.length-1].src;
const url = new URL(src);
const name = url.pathname.replace(/\.js$/, '');
target.setAttribute('data-async-view', name);
const onLoad = function(e) {
debug(`webtor:async view script loaded name=%o`, name);
const target = e.detail.target;
if (!target.reload) {
target.reload = function() {
return new Promise(function(resolve, _) {
Expand All @@ -24,7 +31,7 @@ export function initAsyncView(target, name, init, destroy) {
init.call(target);
}
const onDestroy = async (e) => {
debug(`webtor:async view destroyed name=%o`, name);
debug(`webtor:async view script destroyed name=%o`, name);
const event = new CustomEvent(`async:${name}_destroyed`);
if (destroy) {
let target = document;
Expand All @@ -34,16 +41,17 @@ export function initAsyncView(target, name, init, destroy) {
await destroy.call(target);
}
window.dispatchEvent(event);
}
let keySuffix = '';
if (init) keySuffix += init.toString();
if (destroy) keySuffix += destroy.toString();
let key = `__async${name}_loaded_${MD5(keySuffix)}`;
}
let key = `__async${name}_loaded`;
if (!window[key]) {
window.addEventListener(`async:${name}`, onLoad);
window.addEventListener(`async:${name}_destroy`, onDestroy);
window[key] = true;
onLoad();
onLoad({
detail: {
target,
},
});
}

}
5 changes: 5 additions & 0 deletions assets/src/js/lib/av.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function (init, destroy = null) {
const target = document.currentScript.parentElement;
window.av = window.av || [];
window.av.push([target, init, destroy]);
}
47 changes: 18 additions & 29 deletions assets/src/js/lib/loadAsyncView.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,40 @@
import executeScriptElements from "./executeScriptElements";
function loadAsyncView(target, body, template) {
const nodes = target.querySelectorAll('.async-view');
const els = [];
for (const n of nodes) {
els.push(n);
}
let counter = 0;
function loadAsyncView(target, body) {
const els = target.querySelectorAll('[data-async-view]');
for (const el of els) {
const t = el.getAttribute('async-template');
if (!t) continue;
const listener = () => {
counter++;
if (counter === els.length) {
renderBody(target, body, template);
}
}
window.addEventListener(`async:${t}_destroyed`, listener, { once: true });
const view = el.getAttribute('data-async-view');
const detail = {
target: el,
};
const event = new CustomEvent(`async:${t}_destroy`, { detail });
const event = new CustomEvent(`async:${view}_destroy`, { detail });
window.dispatchEvent(event);
}
if (els.length === 0) {
renderBody(target, body, template);
}
renderBody(target, body);
}
function renderBody(target, body, template) {
function renderBody(target, body) {
target.innerHTML = body;
target.classList.add('async-loaded');
target.setAttribute('async-template', template);

executeScriptElements(target);
const detail = {
target,
template,
};
// Update async elements
const event = new CustomEvent('async', { detail });
window.dispatchEvent(event);

// Process async views
if (template) {
const event = new CustomEvent('async:' + template, { detail });
const scripts = target.getElementsByTagName('script');
for (const script of scripts) {
if (script.src === "") continue;
const url = new URL(script.src);
const name = url.pathname.replace(/\.js$/, '');
const event = new CustomEvent('async:' + name, { detail });
window.dispatchEvent(event);
}
target.scrollIntoView();

// Process async views
const yOffset = -100;
const y = target.getBoundingClientRect().top + window.scrollY + yOffset;

window.scrollTo({ top: y });
}

export default loadAsyncView;
19 changes: 14 additions & 5 deletions assets/src/js/lib/themeSelector.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export default function(themeSelector) {
const [darkTheme, lightTheme] = themeSelector.getAttribute('data-toggle-theme').split(',').map((t) => t.trim());
let currentTheme = window.localStorage.getItem('theme');
const storageKey = 'theme';
function getThemes(themeSelector) {
return themeSelector.getAttribute('data-toggle-theme').split(',').map((t) => t.trim());
}
export function initTheme(themeSelector) {
const [darkTheme, lightTheme] = getThemes(themeSelector);
let currentTheme = window.localStorage.getItem(storageKey);
if (currentTheme === null) {
currentTheme = darkTheme;
if (window.matchMedia && !window.matchMedia('(prefers-color-scheme: dark)')) {
Expand All @@ -9,10 +13,15 @@ export default function(themeSelector) {
}
if (currentTheme === lightTheme) themeSelector.checked = true;
document.querySelector('html').setAttribute('data-theme', currentTheme);
window.localStorage.setItem('theme', currentTheme);
window.localStorage.setItem(storageKey, currentTheme);
}
export function themeSelector(themeSelector) {
const [darkTheme, lightTheme] = getThemes(themeSelector);
let currentTheme = window.localStorage.getItem(storageKey);
if (currentTheme === lightTheme) themeSelector.checked = true;
themeSelector.addEventListener('change', (e) => {
currentTheme = e.target.checked ? lightTheme : darkTheme;
document.querySelector('html').setAttribute('data-theme', currentTheme);
window.localStorage.setItem('theme', currentTheme);
window.localStorage.setItem(storageKey, currentTheme);
});
}
1 change: 0 additions & 1 deletion services/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,6 @@ func (s *Template) HTMLWithErr(err error, code int, c *gin.Context, obj any) {
panic(rerr)
}
}
c.Header("X-Template", name)
c.HTML(code, name, s.tm.contextWrapper(c, obj, err))
}

Expand Down
2 changes: 1 addition & 1 deletion templates/partials/nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
{{ if eq .Claims.Context.Tier.Name "free" }}donate{{ else }}{{ .Claims.Context.Tier.Name }}{{ end }}
{{ else }}donate{{ end }}
</a>

</div>
</div>
</div>
{{ "nav.js" | asset }}
{{ end }}
3 changes: 1 addition & 2 deletions templates/views/action/stream_audio.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<audio class="player"
crossorigin="anonymous"
preload="{{ .Preload }}"
{{ if .Poster }}poster="{{ .Poster }}" {{ end }}
{{ if $MediaProbe }}data-duration="{{ $MediaProbe | getDurationSec }}" {{ end }}
controls
autoplay
Expand All @@ -15,5 +14,5 @@
</audio>
{{ end }}
{{ "mediaelement.css" | asset }}
{{ "action/audio.js" | asset }}
{{ "action/stream.js" | asset }}
{{ end }}
Loading

0 comments on commit eb2d949

Please sign in to comment.