This commit is contained in:
Saifeddine ALOUI 2025-04-09 11:37:32 +02:00
parent d634258df5
commit d5abcb1f1a
12 changed files with 247 additions and 110 deletions

@ -1 +1 @@
Subproject commit c940d0abf631dfcc8f00fcffe738758173b25cb1
Subproject commit 7bbc43f8c380818a95e7e3e32c0023f2822c624a

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{b as O,d as b,L as r,f as s,g as a,s as t,j as P,l as n,t as e}from"./index-DkMe9ry1.js";const S={__proto__:null,anyref:34,dataref:34,eqref:34,externref:34,i31ref:34,funcref:34,i8:34,i16:34,i32:34,i64:34,f32:34,f64:34},Q=r.deserialize({version:14,states:"!^Q]QPOOOqQPO'#CbOOQO'#Cd'#CdOOQO'#Cl'#ClOOQO'#Ch'#ChQ]QPOOOOQO,58|,58|OxQPO,58|OOQO-E6f-E6fOOQO1G.h1G.h",stateData:"!P~O_OSPOSQOS~OTPOVROXROYROZROaQO~OSUO~P]OSXO~P]O",goto:"xaPPPPPPbPbPPPhPPPrXROPTVQTOQVPTWTVXSOPTV",nodeNames:"⚠ LineComment BlockComment Module ) ( App Identifier Type Keyword Number String",maxTerm:17,nodeProps:[["isolate",-3,1,2,11,""],["openedBy",4,"("],["closedBy",5,")"],["group",-6,6,7,8,9,10,11,"Expression"]],skippedNodes:[0,1,2],repeatNodeCount:1,tokenData:"0o~R^XY}YZ}]^}pq}rs!Stu#pxy'Uyz(e{|(j}!O(j!Q!R(s!R![*p!]!^.^#T#o.{~!SO_~~!VVOr!Srs!ls#O!S#O#P!q#P;'S!S;'S;=`#j<%lO!S~!qOZ~~!tRO;'S!S;'S;=`!};=`O!S~#QWOr!Srs!ls#O!S#O#P!q#P;'S!S;'S;=`#j;=`<%l!S<%lO!S~#mP;=`<%l!S~#siqr%bst%btu%buv%bvw%bwx%bz{%b{|%b}!O%b!O!P%b!P!Q%b!Q![%b![!]%b!^!_%b!_!`%b!`!a%b!a!b%b!b!c%b!c!}%b#Q#R%b#R#S%b#S#T%b#T#o%b#p#q%b#r#s%b~%giV~qr%bst%btu%buv%bvw%bwx%bz{%b{|%b}!O%b!O!P%b!P!Q%b!Q![%b![!]%b!^!_%b!_!`%b!`!a%b!a!b%b!b!c%b!c!}%b#Q#R%b#R#S%b#S#T%b#T#o%b#p#q%b#r#s%b~'ZPT~!]!^'^~'aTO!]'^!]!^'p!^;'S'^;'S;=`(_<%lO'^~'sVOy'^yz(Yz!]'^!]!^'p!^;'S'^;'S;=`(_<%lO'^~(_OQ~~(bP;=`<%l'^~(jOS~~(mQ!Q!R(s!R![*p~(xUY~!O!P)[!Q![*p!g!h){#R#S+U#X#Y){#l#m+[~)aRY~!Q![)j!g!h){#X#Y){~)oSY~!Q![)j!g!h){#R#S*j#X#Y){~*OR{|*X}!O*X!Q![*_~*[P!Q![*_~*dQY~!Q![*_#R#S*X~*mP!Q![)j~*uTY~!O!P)[!Q![*p!g!h){#R#S+U#X#Y){~+XP!Q![*p~+_R!Q![+h!c!i+h#T#Z+h~+mVY~!O!P,S!Q![+h!c!i+h!r!s-P#R#S+[#T#Z+h#d#e-P~,XTY~!Q![,h!c!i,h!r!s-P#T#Z,h#d#e-P~,mUY~!Q![,h!c!i,h!r!s-P#R#S.Q#T#Z,h#d#e-P~-ST{|-c}!O-c!Q![-o!c!i-o#T#Z-o~-fR!Q![-o!c!i-o#T#Z-o~-tSY~!Q![-o!c!i-o#R#S-c#T#Z-o~.TR!Q![,h!c!i,h#T#Z,h~.aP!]!^.d~.iSP~OY.dZ;'S.d;'S;=`.u<%lO.d~.xP;=`<%l.d~/QiX~qr.{st.{tu.{uv.{vw.{wx.{z{.{{|.{}!O.{!O!P.{!P!Q.{!Q![.{![!].{!^!_.{!_!`.{!`!a.{!a!b.{!b!c.{!c!}.{#Q#R.{#R#S.{#S#T.{#T#o.{#p#q.{#r#s.{",tokenizers:[0],topRules:{Module:[0,3]},specialized:[{term:9,get:o=>S[o]||-1}],tokenPrec:0}),i=O.define({name:"wast",parser:Q.configure({props:[s.add({App:P({closing:")",align:!1})}),a.add({App:n,BlockComment(o){return{from:o.from+2,to:o.to-2}}}),t({Keyword:e.keyword,Type:e.typeName,Number:e.number,String:e.string,Identifier:e.variableName,LineComment:e.lineComment,BlockComment:e.blockComment,"( )":e.paren})]}),languageData:{commentTokens:{line:";;",block:{open:"(;",close:";)"}},closeBrackets:{brackets:["(",'"']}}});function p(){return new b(i)}export{p as wast,i as wastLanguage};
import{b as O,d as b,L as r,f as s,g as a,s as t,j as P,l as n,t as e}from"./index-C8VjSzoF.js";const S={__proto__:null,anyref:34,dataref:34,eqref:34,externref:34,i31ref:34,funcref:34,i8:34,i16:34,i32:34,i64:34,f32:34,f64:34},Q=r.deserialize({version:14,states:"!^Q]QPOOOqQPO'#CbOOQO'#Cd'#CdOOQO'#Cl'#ClOOQO'#Ch'#ChQ]QPOOOOQO,58|,58|OxQPO,58|OOQO-E6f-E6fOOQO1G.h1G.h",stateData:"!P~O_OSPOSQOS~OTPOVROXROYROZROaQO~OSUO~P]OSXO~P]O",goto:"xaPPPPPPbPbPPPhPPPrXROPTVQTOQVPTWTVXSOPTV",nodeNames:"⚠ LineComment BlockComment Module ) ( App Identifier Type Keyword Number String",maxTerm:17,nodeProps:[["isolate",-3,1,2,11,""],["openedBy",4,"("],["closedBy",5,")"],["group",-6,6,7,8,9,10,11,"Expression"]],skippedNodes:[0,1,2],repeatNodeCount:1,tokenData:"0o~R^XY}YZ}]^}pq}rs!Stu#pxy'Uyz(e{|(j}!O(j!Q!R(s!R![*p!]!^.^#T#o.{~!SO_~~!VVOr!Srs!ls#O!S#O#P!q#P;'S!S;'S;=`#j<%lO!S~!qOZ~~!tRO;'S!S;'S;=`!};=`O!S~#QWOr!Srs!ls#O!S#O#P!q#P;'S!S;'S;=`#j;=`<%l!S<%lO!S~#mP;=`<%l!S~#siqr%bst%btu%buv%bvw%bwx%bz{%b{|%b}!O%b!O!P%b!P!Q%b!Q![%b![!]%b!^!_%b!_!`%b!`!a%b!a!b%b!b!c%b!c!}%b#Q#R%b#R#S%b#S#T%b#T#o%b#p#q%b#r#s%b~%giV~qr%bst%btu%buv%bvw%bwx%bz{%b{|%b}!O%b!O!P%b!P!Q%b!Q![%b![!]%b!^!_%b!_!`%b!`!a%b!a!b%b!b!c%b!c!}%b#Q#R%b#R#S%b#S#T%b#T#o%b#p#q%b#r#s%b~'ZPT~!]!^'^~'aTO!]'^!]!^'p!^;'S'^;'S;=`(_<%lO'^~'sVOy'^yz(Yz!]'^!]!^'p!^;'S'^;'S;=`(_<%lO'^~(_OQ~~(bP;=`<%l'^~(jOS~~(mQ!Q!R(s!R![*p~(xUY~!O!P)[!Q![*p!g!h){#R#S+U#X#Y){#l#m+[~)aRY~!Q![)j!g!h){#X#Y){~)oSY~!Q![)j!g!h){#R#S*j#X#Y){~*OR{|*X}!O*X!Q![*_~*[P!Q![*_~*dQY~!Q![*_#R#S*X~*mP!Q![)j~*uTY~!O!P)[!Q![*p!g!h){#R#S+U#X#Y){~+XP!Q![*p~+_R!Q![+h!c!i+h#T#Z+h~+mVY~!O!P,S!Q![+h!c!i+h!r!s-P#R#S+[#T#Z+h#d#e-P~,XTY~!Q![,h!c!i,h!r!s-P#T#Z,h#d#e-P~,mUY~!Q![,h!c!i,h!r!s-P#R#S.Q#T#Z,h#d#e-P~-ST{|-c}!O-c!Q![-o!c!i-o#T#Z-o~-fR!Q![-o!c!i-o#T#Z-o~-tSY~!Q![-o!c!i-o#R#S-c#T#Z-o~.TR!Q![,h!c!i,h#T#Z,h~.aP!]!^.d~.iSP~OY.dZ;'S.d;'S;=`.u<%lO.d~.xP;=`<%l.d~/QiX~qr.{st.{tu.{uv.{vw.{wx.{z{.{{|.{}!O.{!O!P.{!P!Q.{!Q![.{![!].{!^!_.{!_!`.{!`!a.{!a!b.{!b!c.{!c!}.{#Q#R.{#R#S.{#S#T.{#T#o.{#p#q.{#r#s.{",tokenizers:[0],topRules:{Module:[0,3]},specialized:[{term:9,get:o=>S[o]||-1}],tokenPrec:0}),i=O.define({name:"wast",parser:Q.configure({props:[s.add({App:P({closing:")",align:!1})}),a.add({App:n,BlockComment(o){return{from:o.from+2,to:o.to-2}}}),t({Keyword:e.keyword,Type:e.typeName,Number:e.number,String:e.string,Identifier:e.variableName,LineComment:e.lineComment,BlockComment:e.blockComment,"( )":e.paren})]}),languageData:{commentTokens:{line:";;",block:{open:"(;",close:";)"}},closeBrackets:{brackets:["(",'"']}}});function p(){return new b(i)}export{p as wast,i as wastLanguage};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

26
web/dist/assets/index-GwzEAnMx.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
import{b as q,d as P,q as g,r as l,L as c,u as i,s as R,t as r,E as p}from"./index-DkMe9ry1.js";const b=1,$=33,m=34,v=35,x=36,d=new p(O=>{let e=O.pos;for(;;){if(O.next==10){O.advance();break}else if(O.next==123&&O.peek(1)==123||O.next<0)break;O.advance()}O.pos>e&&O.acceptToken(b)});function n(O,e,a){return new p(t=>{let u=t.pos;for(;t.next!=O&&t.next>=0&&(a||t.next!=38&&(t.next!=123||t.peek(1)!=123));)t.advance();t.pos>u&&t.acceptToken(e)})}const W=n(39,$,!1),C=n(34,m,!1),T=n(39,v,!0),f=n(34,x,!0),A=c.deserialize({version:14,states:"(jOVOqOOOeQpOOOvO!bO'#CaOOOP'#Cx'#CxQVOqOOO!OQpO'#CfO!WQpO'#ClO!]QpO'#CrO!bQpO'#CsOOQO'#Cv'#CvQ!gQpOOQ!lQpOOQ!qQpOOOOOV,58{,58{O!vOpO,58{OOOP-E6v-E6vO!{QpO,59QO#TQpO,59QOOQO,59W,59WO#YQpO,59^OOQO,59_,59_O#_QpOOO#_QpOOO#gQpOOOOOV1G.g1G.gO#oQpO'#CyO#tQpO1G.lOOQO1G.l1G.lO#|QpO1G.lOOQO1G.x1G.xO$UO`O'#DUO$ZOWO'#DUOOQO'#Co'#CoQOQpOOOOQO'#Cu'#CuO$`OtO'#CwO$qOrO'#CwOOQO,59e,59eOOQO-E6w-E6wOOQO7+$W7+$WO%SQpO7+$WO%[QpO7+$WOOOO'#Cp'#CpO%aOpO,59pOOOO'#Cq'#CqO%fOpO,59pOOOS'#Cz'#CzO%kOtO,59cOOQO,59c,59cOOOQ'#C{'#C{O%|OrO,59cO&_QpO<<GrOOQO<<Gr<<GrOOQO1G/[1G/[OOOS-E6x-E6xOOQO1G.}1G.}OOOQ-E6y-E6yOOQOAN=^AN=^",stateData:"&d~OvOS~OPROSQOVROWRO~OZTO[XO^VOaUOhWO~OR]OU^O~O[`O^aO~O[bO~O[cO~O[dO~ObeO~ObfO~ObgO~ORhO~O]kOwiO~O[lO~O_mO~OynOzoO~OysOztO~O[uO~O]wOwiO~O_yOwiO~OtzO~Os|O~OSQOV!OOW!OOr!OOy!QO~OSQOV!ROW!ROq!ROz!QO~O_!TOwiO~O]!UO~Oy!VO~Oz!VO~OSQOV!OOW!OOr!OOy!XO~OSQOV!ROW!ROq!ROz!XO~O]!ZO~O",goto:"#dyPPPPPzPPPP!WPPPPP!WPP!Z!^!a!d!dP!g!j!m!p!v#Q#WPPPPPPPP#^SROSS!Os!PT!Rt!SRYPRqeR{nR}oRZPRqfR[PRqgQSOR_SQj`SvjxRxlQ!PsR!W!PQ!StR!Y!SQpeRrf",nodeNames:"⚠ Text Content }} {{ Interpolation InterpolationContent Entity InvalidEntity Attribute BoundAttributeName [ Identifier ] ( ) ReferenceName # Is ExpressionAttributeValue AttributeInterpolation AttributeInterpolation EventName DirectiveName * StatementAttributeValue AttributeName AttributeValue",maxTerm:42,nodeProps:[["openedBy",3,"{{",15,"("],["closedBy",4,"}}",14,")"],["isolate",-4,5,19,25,27,""]],skippedNodes:[0],repeatNodeCount:4,tokenData:"0r~RyOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mqr#rrs%jst&Qtv#rvw&hwx)zxy*byz*xz{+`{}#r}!O+v!O!P-]!P!Q#r!Q![+v![!]+v!]!_#r!_!`-s!`!c#r!c!}+v!}#O.Z#O#P#r#P#Q.q#Q#R#r#R#S+v#S#T#r#T#o+v#o#p/X#p#q#r#q#r0Z#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vQ#wTUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rQ$ZSO#q#r#r;'S#r;'S;=`$g<%lO#rQ$jP;=`<%l#rR$t[UQvPOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mq#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR%qTyPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&XTaPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&oXUQWPOp'[pq#rq!]'[!]!^#r!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R'aXUQOp'[pq#rq!]'[!]!^'|!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R(TTVPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR(gXOp'[pq#rq!]'[!]!^'|!^#q'[#q#r)S#r;'S'[;'S;=`)t<%lO'[P)VUOp)Sq!])S!]!^)i!^;'S)S;'S;=`)n<%lO)SP)nOVPP)qP;=`<%l)SR)wP;=`<%l'[R*RTzPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR*iT^PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+PT_PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+gThPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+}b[PUQO}#r}!O+v!O!Q#r!Q![+v![!]+v!]!c#r!c!}+v!}#R#r#R#S+v#S#T#r#T#o+v#o#q#r#q#r$W#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vR-YP;=`<%l+vR-dTwPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR-zTUQbPO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.bTZPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.xT]PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/^VUQO#o#r#o#p/s#p#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/zTSPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#r~0^TO#q#r#q#r0m#r;'S#r;'S;=`$g<%lO#r~0rOR~",tokenizers:[d,W,C,T,f,0,1],topRules:{Content:[0,2],Attribute:[1,9]},tokenPrec:0}),V=i.parser.configure({top:"SingleExpression"}),Q=A.configure({props:[R({Text:r.content,Is:r.definitionOperator,AttributeName:r.attributeName,"AttributeValue ExpressionAttributeValue StatementAttributeValue":r.attributeValue,Entity:r.character,InvalidEntity:r.invalid,"BoundAttributeName/Identifier":r.attributeName,"EventName/Identifier":r.special(r.attributeName),"ReferenceName/Identifier":r.variableName,"DirectiveName/Identifier":r.keyword,"{{ }}":r.brace,"( )":r.paren,"[ ]":r.bracket,"# '*'":r.punctuation})]}),o={parser:V},w={parser:i.parser},U=Q.configure({wrap:l((O,e)=>O.name=="InterpolationContent"?o:null)}),y=Q.configure({wrap:l((O,e)=>{var a;return O.name=="InterpolationContent"?o:O.name!="AttributeInterpolation"?null:((a=O.node.parent)===null||a===void 0?void 0:a.name)=="StatementAttributeValue"?w:o}),top:"Attribute"}),E={parser:U},N={parser:y},s=g();function S(O){return O.configure({wrap:l(z)},"angular")}const k=S(s.language);function z(O,e){switch(O.name){case"Attribute":return/^[*#(\[]|\{\{/.test(e.read(O.from,O.to))?N:null;case"Text":return E}return null}function G(O={}){let e=s;if(O.base){if(O.base.language.name!="html"||!(O.base.language instanceof q))throw new RangeError("The base option must be the result of calling html(...)");e=O.base}return new P(e.language==s.language?k:S(e.language),[e.support,e.language.data.of({closeBrackets:{brackets:["[","{",'"']},indentOnInput:/^\s*[\}\]]$/})])}export{G as angular,k as angularLanguage};
import{b as q,d as P,q as g,r as l,L as c,u as i,s as R,t as r,E as p}from"./index-C8VjSzoF.js";const b=1,$=33,m=34,v=35,x=36,d=new p(O=>{let e=O.pos;for(;;){if(O.next==10){O.advance();break}else if(O.next==123&&O.peek(1)==123||O.next<0)break;O.advance()}O.pos>e&&O.acceptToken(b)});function n(O,e,a){return new p(t=>{let u=t.pos;for(;t.next!=O&&t.next>=0&&(a||t.next!=38&&(t.next!=123||t.peek(1)!=123));)t.advance();t.pos>u&&t.acceptToken(e)})}const W=n(39,$,!1),C=n(34,m,!1),T=n(39,v,!0),f=n(34,x,!0),A=c.deserialize({version:14,states:"(jOVOqOOOeQpOOOvO!bO'#CaOOOP'#Cx'#CxQVOqOOO!OQpO'#CfO!WQpO'#ClO!]QpO'#CrO!bQpO'#CsOOQO'#Cv'#CvQ!gQpOOQ!lQpOOQ!qQpOOOOOV,58{,58{O!vOpO,58{OOOP-E6v-E6vO!{QpO,59QO#TQpO,59QOOQO,59W,59WO#YQpO,59^OOQO,59_,59_O#_QpOOO#_QpOOO#gQpOOOOOV1G.g1G.gO#oQpO'#CyO#tQpO1G.lOOQO1G.l1G.lO#|QpO1G.lOOQO1G.x1G.xO$UO`O'#DUO$ZOWO'#DUOOQO'#Co'#CoQOQpOOOOQO'#Cu'#CuO$`OtO'#CwO$qOrO'#CwOOQO,59e,59eOOQO-E6w-E6wOOQO7+$W7+$WO%SQpO7+$WO%[QpO7+$WOOOO'#Cp'#CpO%aOpO,59pOOOO'#Cq'#CqO%fOpO,59pOOOS'#Cz'#CzO%kOtO,59cOOQO,59c,59cOOOQ'#C{'#C{O%|OrO,59cO&_QpO<<GrOOQO<<Gr<<GrOOQO1G/[1G/[OOOS-E6x-E6xOOQO1G.}1G.}OOOQ-E6y-E6yOOQOAN=^AN=^",stateData:"&d~OvOS~OPROSQOVROWRO~OZTO[XO^VOaUOhWO~OR]OU^O~O[`O^aO~O[bO~O[cO~O[dO~ObeO~ObfO~ObgO~ORhO~O]kOwiO~O[lO~O_mO~OynOzoO~OysOztO~O[uO~O]wOwiO~O_yOwiO~OtzO~Os|O~OSQOV!OOW!OOr!OOy!QO~OSQOV!ROW!ROq!ROz!QO~O_!TOwiO~O]!UO~Oy!VO~Oz!VO~OSQOV!OOW!OOr!OOy!XO~OSQOV!ROW!ROq!ROz!XO~O]!ZO~O",goto:"#dyPPPPPzPPPP!WPPPPP!WPP!Z!^!a!d!dP!g!j!m!p!v#Q#WPPPPPPPP#^SROSS!Os!PT!Rt!SRYPRqeR{nR}oRZPRqfR[PRqgQSOR_SQj`SvjxRxlQ!PsR!W!PQ!StR!Y!SQpeRrf",nodeNames:"⚠ Text Content }} {{ Interpolation InterpolationContent Entity InvalidEntity Attribute BoundAttributeName [ Identifier ] ( ) ReferenceName # Is ExpressionAttributeValue AttributeInterpolation AttributeInterpolation EventName DirectiveName * StatementAttributeValue AttributeName AttributeValue",maxTerm:42,nodeProps:[["openedBy",3,"{{",15,"("],["closedBy",4,"}}",14,")"],["isolate",-4,5,19,25,27,""]],skippedNodes:[0],repeatNodeCount:4,tokenData:"0r~RyOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mqr#rrs%jst&Qtv#rvw&hwx)zxy*byz*xz{+`{}#r}!O+v!O!P-]!P!Q#r!Q![+v![!]+v!]!_#r!_!`-s!`!c#r!c!}+v!}#O.Z#O#P#r#P#Q.q#Q#R#r#R#S+v#S#T#r#T#o+v#o#p/X#p#q#r#q#r0Z#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vQ#wTUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rQ$ZSO#q#r#r;'S#r;'S;=`$g<%lO#rQ$jP;=`<%l#rR$t[UQvPOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mq#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR%qTyPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&XTaPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&oXUQWPOp'[pq#rq!]'[!]!^#r!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R'aXUQOp'[pq#rq!]'[!]!^'|!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R(TTVPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR(gXOp'[pq#rq!]'[!]!^'|!^#q'[#q#r)S#r;'S'[;'S;=`)t<%lO'[P)VUOp)Sq!])S!]!^)i!^;'S)S;'S;=`)n<%lO)SP)nOVPP)qP;=`<%l)SR)wP;=`<%l'[R*RTzPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR*iT^PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+PT_PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+gThPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+}b[PUQO}#r}!O+v!O!Q#r!Q![+v![!]+v!]!c#r!c!}+v!}#R#r#R#S+v#S#T#r#T#o+v#o#q#r#q#r$W#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vR-YP;=`<%l+vR-dTwPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR-zTUQbPO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.bTZPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.xT]PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/^VUQO#o#r#o#p/s#p#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/zTSPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#r~0^TO#q#r#q#r0m#r;'S#r;'S;=`$g<%lO#r~0rOR~",tokenizers:[d,W,C,T,f,0,1],topRules:{Content:[0,2],Attribute:[1,9]},tokenPrec:0}),V=i.parser.configure({top:"SingleExpression"}),Q=A.configure({props:[R({Text:r.content,Is:r.definitionOperator,AttributeName:r.attributeName,"AttributeValue ExpressionAttributeValue StatementAttributeValue":r.attributeValue,Entity:r.character,InvalidEntity:r.invalid,"BoundAttributeName/Identifier":r.attributeName,"EventName/Identifier":r.special(r.attributeName),"ReferenceName/Identifier":r.variableName,"DirectiveName/Identifier":r.keyword,"{{ }}":r.brace,"( )":r.paren,"[ ]":r.bracket,"# '*'":r.punctuation})]}),o={parser:V},w={parser:i.parser},U=Q.configure({wrap:l((O,e)=>O.name=="InterpolationContent"?o:null)}),y=Q.configure({wrap:l((O,e)=>{var a;return O.name=="InterpolationContent"?o:O.name!="AttributeInterpolation"?null:((a=O.node.parent)===null||a===void 0?void 0:a.name)=="StatementAttributeValue"?w:o}),top:"Attribute"}),E={parser:U},N={parser:y},s=g();function S(O){return O.configure({wrap:l(z)},"angular")}const k=S(s.language);function z(O,e){switch(O.name){case"Attribute":return/^[*#(\[]|\{\{/.test(e.read(O.from,O.to))?N:null;case"Text":return E}return null}function G(O={}){let e=s;if(O.base){if(O.base.language.name!="html"||!(O.base.language instanceof q))throw new RangeError("The base option must be the result of calling html(...)");e=O.base}return new P(e.language==s.language?k:S(e.language),[e.support,e.language.data.of({closeBrackets:{brackets:["[","{",'"']},indentOnInput:/^\s*[\}\]]$/})])}export{G as angular,k as angularLanguage};

File diff suppressed because one or more lines are too long

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI</title>
<script type="module" crossorigin src="/assets/index-DkMe9ry1.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-jd0TJS39.css">
<script type="module" crossorigin src="/assets/index-C8VjSzoF.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-GwzEAnMx.css">
</head>
<body>
<div id="app"></div>

View File

@ -3,11 +3,22 @@
<!-- Container for dynamically injected HTML -->
<div ref="htmlContentContainer"></div>
<!-- Conditionally render the Vue ImageAlbumViewer component -->
<!-- Added extra log to see when Vue *tries* to render this based on the v-if condition -->
<ImageAlbumViewer
v-if="showAlbumViewer"
:images="albumImages"
:key="`album-${instanceId}`"
:key="`album-${instanceId}-${albumImages.length}`"
@hook:mounted="logAlbumViewerMounted"
/>
<!-- Debugging output -->
<pre style="background: #eee; padding: 10px; margin-top: 10px; font-size: 12px; border: 1px solid #ccc;">
DEBUG [{{ instanceId }}]:
showAlbumViewer: {{ showAlbumViewer }}
albumImages Count: {{ albumImages.length }}
albumImages: {{ JSON.stringify(albumImages) }}
</pre>
</div>
</template>
@ -19,7 +30,7 @@ import ImageAlbumViewer from './ImageAlbumViewer.vue'; // Adjust path if needed
export default {
name: 'DynamicUIRenderer',
components: {
ImageAlbumViewer, // Register the child component
ImageAlbumViewer,
},
props: {
ui: {
@ -33,194 +44,309 @@ export default {
},
data() {
return {
// containerId is computed, moved to computed section
albumImages: [], // Reactive state for album images
showAlbumViewer: false, // Reactive state to control v-if
injectedStyleElements: [], // Keep track of injected styles
albumImages: [],
showAlbumViewer: false,
injectedStyleElements: [],
// Added a simple counter to help distinguish render calls
renderCount: 0,
};
},
computed: {
...mapState(['clientId']), // Map client_id from Vuex store
// Compute containerId based on instanceId prop
...mapState(['clientId']),
containerId() {
// Added log
console.log(`[${this.instanceId}] Computed containerId: dynamic-ui-${this.instanceId}`);
return `dynamic-ui-${this.instanceId}`;
},
},
watch: {
ui: {
immediate: true, // Run on component mount
immediate: true,
handler(newValue, oldValue) {
// Only re-render if the UI actually changed or if the container is empty
// Use $refs here as they are available after the initial render (due to immediate: true)
this.renderCount++;
const currentRender = this.renderCount;
console.log(`[${this.instanceId}] Watcher triggered (Render #${currentRender}). UI changed: ${newValue !== oldValue}. New length: ${newValue?.length}, Old length: ${oldValue?.length}`);
const htmlContainer = this.$refs.htmlContentContainer;
if (newValue !== oldValue || !htmlContainer || htmlContainer.innerHTML === '') {
console.log(`UI prop changed for instance ${this.instanceId}`);
const needsRender = newValue !== oldValue || !htmlContainer || htmlContainer.innerHTML === '';
console.log(`[${this.instanceId}] Needs render evaluation (Render #${currentRender}): ${needsRender}`);
if (needsRender) {
console.log(`[${this.instanceId}] --- Starting Update Cycle (Render #${currentRender}) ---`);
// Cleanup must happen *before* rendering new content
this.cleanupDynamicContent();
this.cleanupDynamicContent(currentRender); // Pass render count for context
// Use $nextTick to ensure DOM is updated after cleanup before rendering
this.$nextTick(() => {
this.renderContent();
console.log(`[${this.instanceId}] $nextTick after cleanup (Render #${currentRender}): Starting renderContent.`);
this.renderContent(currentRender); // Pass render count for context
});
} else {
console.log(`[${this.instanceId}] Watcher triggered but skipping render (Render #${currentRender}). UI likely unchanged or container still populated.`);
}
}
}
},
beforeUnmount() {
this.cleanupDynamicContent(); // Ensure cleanup when component is destroyed
// No need to remove listener manually, Vue handles it on the root element
console.log(`[${this.instanceId}] Component beforeUnmount hook.`);
this.cleanupDynamicContent('beforeUnmount'); // Ensure cleanup when component is destroyed
},
methods: {
renderContent() {
console.log(`Rendering content for instance ${this.instanceId}...`);
const targetContainer = this.$refs.htmlContentContainer; // Access ref via this.$refs
logAlbumViewerMounted() {
console.log(`[${this.instanceId}] ImageAlbumViewer successfully MOUNTED.`);
},
renderContent(renderContext) {
console.log(`[${this.instanceId}] renderContent CALLED (Context: ${renderContext})`);
const targetContainer = this.$refs.htmlContentContainer;
if (!targetContainer) {
// This check might be less likely to fail here compared to setup,
// as refs are generally available in methods called after mount.
console.error(`HTML content container ref not found for instance ${this.instanceId}`);
console.error(`[${this.instanceId}] ERROR: htmlContentContainer ref NOT FOUND during renderContent (Context: ${renderContext})!`);
return;
}
// Clear previous content (already done in cleanup, but good practice)
// Ensure container is clean (belt-and-suspenders with cleanup)
targetContainer.innerHTML = '';
let imagesForAlbum = []; // Local variable for processing
this.showAlbumViewer = false; // Reset viewer flag
console.log(`[${this.instanceId}] Cleared targetContainer innerHTML (Context: ${renderContext})`);
let imagesForAlbum = []; // Local variable for processing
let localShowAlbumViewer = false; // Use a local flag during processing
const incomingUi = this.ui || ''; // Use local variable for safety
if (!incomingUi.trim()) {
console.warn(`[${this.instanceId}] No UI content provided (Context: ${renderContext}). Skipping parsing.`);
// Ensure state is reset if UI becomes empty
this.albumImages = [];
this.showAlbumViewer = false;
console.log(`[${this.instanceId}] Reset album state due to empty UI (Context: ${renderContext}). showAlbumViewer=${this.showAlbumViewer}`);
return;
}
console.log(`[${this.instanceId}] Parsing UI content (length: ${incomingUi.length}) (Context: ${renderContext})`);
const parser = new DOMParser();
// Use this.ui to access the prop
const doc = parser.parseFromString(this.ui || '', 'text/html');
const doc = parser.parseFromString(incomingUi, 'text/html');
// --- 1. Inject Scoped CSS ---
const styles = doc.head.getElementsByTagName('style');
Array.from(styles).forEach(style => this.injectScopedCss(style.textContent));
console.log(`[${this.instanceId}] Found ${styles.length} style tags in <head>.`);
Array.from(styles).forEach((style, index) => {
console.log(`[${this.instanceId}] Injecting head style #${index + 1}.`);
this.injectScopedCss(style.textContent, renderContext);
});
const bodyStyles = doc.body.getElementsByTagName('style');
Array.from(bodyStyles).forEach(style => this.injectScopedCss(style.textContent));
console.log(`[${this.instanceId}] Found ${bodyStyles.length} style tags in <body>.`);
Array.from(bodyStyles).forEach((style, index) => {
console.log(`[${this.instanceId}] Injecting body style #${index + 1}.`);
this.injectScopedCss(style.textContent, renderContext);
});
// --- 2. Process HTML Body ---
console.log(`[${this.instanceId}] Processing body childNodes (Context: ${renderContext})`);
const processedNodes = [];
let albumPlaceholderNeeded = false;
const nodesToProcess = Array.from(doc.body.childNodes);
console.log(`[${this.instanceId}] Found ${nodesToProcess.length} nodes in parsed body.`);
nodesToProcess.forEach(node => {
nodesToProcess.forEach((node, index) => {
if (node.nodeType === Node.ELEMENT_NODE) {
console.log(`[${this.instanceId}] Processing Node #${index + 1}: <${node.tagName}>, Classes: ${node.classList}`);
// --- Special Handling: Image Album ---
if (node.tagName === 'IMG' && node.classList.contains('album')) {
const src = node.getAttribute('src');
if (src) {
console.log(`[${this.instanceId}] -> Found 'img.album' with src: ${src}`);
imagesForAlbum.push(src); // Add to local list
albumPlaceholderNeeded = true;
} else {
console.warn(`[${this.instanceId}] -> Found 'img.album' but it has NO src attribute.`);
}
return; // Skip appending this node
return; // Skip appending this specific node
}
// --- Special Handling: Clickable Image POST ---
if (node.tagName === 'IMG' && node.classList.contains('clickable-post')) {
console.log(`[${this.instanceId}] -> Found 'img.clickable-post'. Ensuring data attributes.`);
if (!node.dataset.endpoint) node.dataset.endpoint = '/post_to_personality';
if (!node.dataset.payloadKey) node.dataset.payloadKey = 'img_path';
}
// --- Special Handling: Open Folder Link ---
if (node.tagName === 'A' && node.classList.contains('open-folder')) {
console.log(`[${this.instanceId}] -> Found 'a.open-folder'. Setting href='#'`);
node.setAttribute('href', '#'); // Prevent navigation
}
processedNodes.push(node); // Add node for standard appending
} else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
console.log(`[${this.instanceId}] Processing Node #${index + 1}: TextNode (non-empty)`);
processedNodes.push(node); // Add node for standard appending
} else {
console.log(`[${this.instanceId}] Skipping Node #${index + 1} (Type: ${node.nodeType})`);
}
processedNodes.push(node);
});
// --- 3. Append Processed Standard HTML Nodes ---
console.log(`[${this.instanceId}] Appending ${processedNodes.length} processed nodes to targetContainer (Context: ${renderContext})`);
processedNodes.forEach(node => {
// Use importNode to ensure the node can be appended to the current document
targetContainer.appendChild(document.importNode(node, true));
});
console.log(`[${this.instanceId}] Finished appending nodes. Current targetContainer innerHTML length: ${targetContainer.innerHTML.length}`);
// --- 4. Update State for Album Viewer ---
console.log(`[${this.instanceId}] Evaluating album state (Context: ${renderContext}). albumPlaceholderNeeded=${albumPlaceholderNeeded}, images found=${imagesForAlbum.length}`);
if (albumPlaceholderNeeded && imagesForAlbum.length > 0) {
this.albumImages = imagesForAlbum; // Update reactive data property
this.showAlbumViewer = true; // Update reactive data property
console.log(`Scheduled ImageAlbumViewer rendering for instance ${this.instanceId} with ${imagesForAlbum.length} images.`);
// Set the local flag first
localShowAlbumViewer = true;
console.log(`[${this.instanceId}] SETTING album state: images=`, JSON.stringify(imagesForAlbum));
// Update reactive data properties
this.albumImages = [...imagesForAlbum]; // Use spread to ensure reactivity change detection
this.showAlbumViewer = true;
console.log(`[${this.instanceId}] State AFTER update: showAlbumViewer=${this.showAlbumViewer}, albumImages count=${this.albumImages.length}`);
} else {
console.log(`[${this.instanceId}] RESETTING album state.`);
localShowAlbumViewer = false;
// Update reactive data properties
this.albumImages = [];
this.showAlbumViewer = false;
console.log(`[${this.instanceId}] State AFTER reset: showAlbumViewer=${this.showAlbumViewer}`);
}
// --- 5. Handle Original Scripts (Still use with caution!) ---
// const scripts = doc.body.getElementsByTagName('script');
// Array.from(scripts).forEach(script => { /* ... */ });
console.log(`Finished rendering for instance ${this.instanceId}.`);
console.log(`[${this.instanceId}] --- Finished renderContent (Context: ${renderContext}) ---`);
},
injectScopedCss(css) {
injectScopedCss(css, renderContext) {
console.log(`[${this.instanceId}] Injecting scoped CSS (Context: ${renderContext})`);
if (!css || !css.trim()) {
console.warn(`[${this.instanceId}] CSS content is empty, skipping injection.`);
return;
}
const scopedCss = this.scopeCSS(css); // Call helper method
const styleElement = document.createElement('style');
styleElement.textContent = scopedCss;
// Append to head for better standard compliance
document.head.appendChild(styleElement);
this.injectedStyleElements.push(styleElement); // Store ref in data property
console.log(`[${this.instanceId}] Injected style element. Total injected: ${this.injectedStyleElements.length}`);
},
scopeCSS(css) {
// Use computed containerId
return css.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, (match, selector, suffix) => {
const id = this.containerId; // Get it once
if (!id) {
console.error(`[${this.instanceId}] Cannot scope CSS: containerId is missing!`);
return css; // Return original CSS
}
const idSelector = `#${id}`;
// Improved regex to handle more cases, including direct descendant (>), adjacent sibling (+), general sibling (~), pseudo-classes/elements
return css.replace(/([^\r\n,{}\s][^{}]*)(?=\s*\{)/g, (match, selector) => {
selector = selector.trim();
if (selector.startsWith('@') || selector.startsWith(':') || selector.includes('#') || selector.includes('[')) {
return match;
// Avoid scoping @ rules, keyframes, font-faces, etc.
if (selector.startsWith('@') || selector.startsWith('%') || /^\d+%$/.test(selector)) {
return selector;
}
// Avoid scoping selectors that already seem specific (like IDs, maybe attribute selectors if needed)
// Simple check for now: don't re-scope if it already contains the ID prefix
if (selector.includes(idSelector)) {
return selector;
}
// Scope each part of a comma-separated list
const scopedSelector = selector.split(',')
.map(part => `#${this.containerId} ${part.trim()}`) // Scope relative to the main container ID
.map(part => {
part = part.trim();
// Handle cases like `html body .class` -> `#id .class` (avoiding `#id html body .class`)
// This is tricky, a simple prefix is often safer for dynamically injected content
// Option 1: Simple Prefix (Safest)
return `${idSelector} ${part}`;
// Option 2: More complex replacements (can break easily)
// e.g., if part starts with 'body' or 'html', replace it? -> Complex
})
.join(', ');
return `${scopedSelector}${suffix}`;
return scopedSelector;
});
},
handleContainerClick(event) {
const target = event.target;
console.log(`[${this.instanceId}] Container clicked. Target: <${target.tagName}>, Classes: ${target.classList}`);
// --- Handle Clickable Image Post ---
// Use closest to handle clicks on elements inside the intended target (e.g., if image is wrapped)
const clickablePost = target.closest('img.clickable-post');
if (clickablePost && clickablePost.dataset.endpoint) {
event.preventDefault();
event.preventDefault(); // Prevent default image drag behavior etc.
const endpoint = clickablePost.dataset.endpoint;
const payloadKey = clickablePost.dataset.payloadKey || 'img_path';
const src = clickablePost.getAttribute('src');
const payload = { [payloadKey]: src };
console.log(`Posting to ${endpoint} with payload:`, payload);
console.log(`[${this.instanceId}] Clickable POST triggered. Endpoint: ${endpoint}, Payload:`, payload);
axios.post(endpoint, payload)
.then(response => console.log('Post successful:', response.data))
.catch(error => console.error(`Error posting to ${endpoint}:`, error));
return;
.then(response => console.log(`[${this.instanceId}] Post to ${endpoint} successful:`, response.data))
.catch(error => console.error(`[${this.instanceId}] Error posting to ${endpoint}:`, error));
return; // Handled
}
// --- Handle Open Folder Link ---
const openFolderLink = target.closest('a.open-folder');
if (openFolderLink && openFolderLink.dataset.discussionId) {
event.preventDefault();
if (openFolderLink) { // Check dataset.discussionId inside
event.preventDefault(); // Prevent default link behavior (# navigation)
const discussionId = openFolderLink.dataset.discussionId;
if (!discussionId) {
console.warn(`[${this.instanceId}] 'a.open-folder' clicked, but missing 'data-discussion-id' attribute.`);
return;
}
console.log(`[${this.instanceId}] Open folder link clicked. Discussion ID: ${discussionId}`);
// Access clientId from computed properties (mapped from Vuex)
if (!this.clientId) {
console.error("Client ID not found in Vuex store.");
console.error(`[${this.instanceId}] ERROR: Client ID not found in Vuex store for open_discussion_folder!`);
alert("Error: Client information is missing.");
return;
}
console.log(`Posting to /open_discussion_folder with client_id: ${this.clientId}, discussion_id: ${discussionId}`);
console.log(`[${this.instanceId}] Posting to /open_discussion_folder with client_id: ${this.clientId}, discussion_id: ${discussionId}`);
axios.post('/open_discussion_folder', { client_id: this.clientId, discussion_id: discussionId })
.then(response => console.log('Open folder request successful:', response.data))
.catch(error => console.error('Error opening folder:', error));
return;
.then(response => console.log(`[${this.instanceId}] Open folder request successful:`, response.data))
.catch(error => console.error(`[${this.instanceId}] Error opening folder:`, error));
return; // Handled
}
console.log(`[${this.instanceId}] Click was not handled by specific handlers.`);
},
cleanupDynamicContent() {
console.log(`Cleaning up dynamic content for instance ${this.instanceId}`);
cleanupDynamicContent(cleanupContext) {
console.log(`[${this.instanceId}] cleanupDynamicContent CALLED (Context: ${cleanupContext})`);
// Reset reactive data - this hides the ImageAlbumViewer via v-if
this.showAlbumViewer = false;
this.albumImages = [];
// Important: Only reset if they are currently set, to avoid unnecessary reactive churn
let stateChanged = false;
if (this.showAlbumViewer) {
this.showAlbumViewer = false;
stateChanged = true;
}
if (this.albumImages.length > 0) {
this.albumImages = [];
stateChanged = true;
}
if (stateChanged) {
console.log(`[${this.instanceId}] Album state reset during cleanup. showAlbumViewer=${this.showAlbumViewer}`);
} else {
console.log(`[${this.instanceId}] Album state was already reset.`);
}
// Remove injected stylesheets
this.injectedStyleElements.forEach(styleElement => {
console.log(`[${this.instanceId}] Removing ${this.injectedStyleElements.length} injected style elements.`);
this.injectedStyleElements.forEach((styleElement, index) => {
if (styleElement && styleElement.parentNode) {
console.log(`[${this.instanceId}] Removing style element #${index + 1}`);
styleElement.parentNode.removeChild(styleElement);
} else {
console.warn(`[${this.instanceId}] Could not remove style element #${index + 1} (already removed or no parent).`);
}
});
this.injectedStyleElements = []; // Clear the tracking array
@ -228,9 +354,12 @@ export default {
// Clear dynamically injected HTML content
const htmlContainer = this.$refs.htmlContentContainer;
if (htmlContainer) {
console.log(`[${this.instanceId}] Clearing innerHTML of htmlContentContainer.`);
htmlContainer.innerHTML = '';
} else {
console.warn(`[${this.instanceId}] htmlContentContainer ref not found during cleanup (Context: ${cleanupContext}). Might be called before mount or after unmount.`);
}
console.log(`Finished cleanup for instance ${this.instanceId}.`);
console.log(`[${this.instanceId}] --- Finished cleanupDynamicContent (Context: ${cleanupContext}) ---`);
}
}
};
@ -238,4 +367,8 @@ export default {
<style scoped>
/* Add any styles specific to the main container itself, if needed */
/* Example: Add a min-height to prevent collapse when empty */
:deep(#dynamic-ui-root) { /* Using :deep to target potential root if needed, adjust selector */
min-height: 20px; /* Or whatever makes sense */
}
</style>