Niedawno jako eksperyment utworzyłem projekt ‟js-dom”. Jest to generator strony ‘www’ funkcjonalnie wzorowany na cudzym projekcie. Idea jest, by tworzyć klasy JavaScript obsługujące każdorazowo ·obiekt na stronie ‘www’· nie mający prostego odwzorowania w jakimś elemencie ‘html’ (np. “DIV”), ale klasa generuje fragment dokumentu ‘html’ dla bieżącego stanu obiektu.
Na przykład dla obiektu ‛lista przycisków‘ napisałem następującą klasę w JavaScript:
class H_js_dom_E_object_Q_button_list
{ constructor( direction
, class_name
, content
, object_function
, null_function
){ this.direction = direction;
this.class_name = class_name;
this.content = content;
this.object_function = object_function;
this.null_function = null_function;
this.button_path = [];
}
async html(
){ const html_list = document.createElement( "DIV" );
html_list.className = this.class_name;
html_list.style.display = "flex";
html_list.style.flexDirection = this.direction;
let content = this.content;
for( const i of this.button_path )
content = content[i].click;
let i = 0;
for( const item of content )
{ const html_item = document.createElement( "BUTTON" );
html_item.append( item.text );
if( typeof item.click === "function" )
html_item.addEventListener( "click", item.click );
else if( item.click === null )
html_item.addEventListener( "click", ((i) =>
{ return async () =>
{ await this.null_function( this, i );
};
})(i)
);
else if( typeof item.click === "object" )
{ html_item.addEventListener( "click", ((i) =>
{ return async () =>
{ this.button_path.push(i);
await this.object_function(this);
};
})(i)
);
}
html_list.append( html_item );
i++;
}
if( this.button_path.length )
{ const html_item = document.createElement( "BUTTON" );
html_item.append( "back" );
html_item.addEventListener( "click", async () =>
{ this.button_path.pop();
await this.object_function(this);
}
);
html_list.append( html_item );
}
return html_list;
}
}
Teraz wystarczy utworzyć w dokumencie ‘html’ obiekt na przykład ‛nawigacja’:
class H_js_dom_E_object_Q_nav
{ constructor(
){ const Z_text_N_filename = (text) =>
{ return text.replaceAll( " ", "_" ).replace( /[^_0-9a-z-]/gi, "" ).replace( /_{2,}/g, "_" );
};
this.objects =
[ new H_js_dom_E_object_Q_button_list( "column", "H_js_dom_E_object_Q_button_list"
, [ { text: "Button 1"
, click: null
}
, { text: "Button 2"
, click:
[ { text: "Button 1"
, click: null
}
, { text: "Button 2"
, click: null
}
, { text: "Button 3"
, click: null
}
]
}
, { text: "Button 3"
, click:
[ { text: "Button 1"
, click: null
}
, { text: "Button 2"
, click:
[ { text: "Button 1"
, click: null
}
, { text: "Button 2"
, click: null
}
, { text: "Button 3"
, click: null
}
, { text: "Button 4"
, click: null
}
]
}
]
}
, { text: "Button 4"
, click: async () =>
{
}
}
, { text: "Button 5"
, click: null
}
, { text: "Button 6"
, click: null
}
, { text: "Button 7"
, click: async () =>
{
}
}
]
, async (this_) =>
{ let s = "";
let content = this_.content;
for( const i of this_.button_path )
{ s += "/"+ Z_text_N_filename( content[i].text );
content = content[i].click;
}
s += "/"+ Z_text_N_filename( content[0].text );
await H_js_dom_E_object_Q_app_S.P_main( s.substring(1) );
}
, async ( this_
, i
) =>
{ let s = "";
let content = this_.content;
for( const i of this_.button_path )
{ s += "/"+ Z_text_N_filename( content[i].text );
content = content[i].click;
}
s += "/"+ Z_text_N_filename( content[i].text );
await H_js_dom_E_object_Q_app_S.P_main( s.substring(1) );
}
)
, new H_js_dom_E_object_Q_label( "29 05 2024", "H_js_dom_E_object_Q_nav_S_creation_date" )
];
}
async html(
){ const html_e = document.createElement( "DIV" );
html_e.id = "H_js_dom_E_object_Q_nav";
for( const object of this.objects )
html_e.append( await object.html() );
return html_e;
}
}
I dzięki procedurze
async function H_js_dom_E_html_I_overwrite(
){ const html_f = await H_js_dom_E_object_Q_app_S.html()
document.body.innerHTML = "";
document.body.append( html_f );
}
która wywołuje na drzewie (kompozycji) klas JavaScript metodę “html()”, jest utworzona lista przycisków nawigacji.
Ta lista po kliknięciu przycisku, który ma swoje podmenu, zmienia się w listę przycisków tego podmenu, a po kliknięciu “back” zmienia się w listę przycisków “menu” nadrzędnego. (Jest dowolna głębokość możliwych podmenu.)
⁂
Ten projekt nadaje się do tworzenia aplikacji na pojedynczej stronie ‘www’. Natomiast dotychczas tworzyłem własną witrynę ‘www’ samodzielnie napisanym generatorem stron statycznych, który opiera się o szablony XSL biorące też dane (gdy potrzeba) z plików XML.
Takie szablony XSL w porównaniu do projektu ‟js-dom” i jego obiektu listy przycisków nawigacji — generują pojedynczy stan nawigacji (konkretne menu z konkretnym wybranym bieżącym przyciskiem).
Jak natomiast w przypadku stron generowanych statycznie (na przykład z użyciem szablonów XSL) napisać w jednym miejscu obsługę obiektu takiej nawigacji, który miałby swoje odrębne wynikowe postacie ‘html’ we fragmencie ·odrębnych· plików stron ‘www’?
Myślałem wstępnie, by jakoś wstawiać ten obiekt do plików XSL i go wykonywać. Ale jak to zrobić? Poza tym mam do dyspozycji języki skryptowe dostępne w systemie Linux, których używam częściowo przy budowie witryny ‘www’.
Projekt ten nie został nigdzie opublikowany, by podać adres pełnych źródeł koniecznych do jego uruchomienia, ale jakoś funkcjonująca aplikacja ‘www’ znajduje się tymczasowo tutaj. Trzeba pamiętać, że jest to uproszczona kopia wizualna cudzej witryny, z innym zestawem kolorów i formatowaniem tekstu.
⁂
ChatGPT mi częściowo pomógł.
Można tworzyć definicje obiektów na stronie ‘www’ — w plikach ‘xsl’ i włączać je do plików ‘xsl’ stron ‘www’. Natomiast trzeba używać parametru “state”, którym może być nazwa pliku ‘xsl’ strony ‘www’.