@@ -2696,6 +2696,92 @@ class ComponentRegistry {
26962696 }
26972697}
26982698
2699+ class AdvancedURLSearchParams extends URLSearchParams {
2700+ set ( name , value ) {
2701+ if ( typeof value !== 'object' ) {
2702+ super . set ( name , value ) ;
2703+ }
2704+ else {
2705+ this . delete ( name ) ;
2706+ if ( Array . isArray ( value ) ) {
2707+ value . forEach ( ( v ) => {
2708+ this . append ( `${ name } []` , v ) ;
2709+ } ) ;
2710+ }
2711+ else {
2712+ Object . entries ( value ) . forEach ( ( [ index , v ] ) => {
2713+ this . append ( `${ name } [${ index } ]` , v ) ;
2714+ } ) ;
2715+ }
2716+ }
2717+ }
2718+ delete ( name ) {
2719+ super . delete ( name ) ;
2720+ const pattern = new RegExp ( `^${ name } (\\[.*])?$` ) ;
2721+ for ( const key of Array . from ( this . keys ( ) ) ) {
2722+ if ( key . match ( pattern ) ) {
2723+ super . delete ( key ) ;
2724+ }
2725+ }
2726+ }
2727+ }
2728+ function setQueryParam ( param , value ) {
2729+ const queryParams = new AdvancedURLSearchParams ( window . location . search ) ;
2730+ queryParams . set ( param , value ) ;
2731+ const url = urlFromQueryParams ( queryParams ) ;
2732+ history . replaceState ( history . state , '' , url ) ;
2733+ }
2734+ function removeQueryParam ( param ) {
2735+ const queryParams = new AdvancedURLSearchParams ( window . location . search ) ;
2736+ queryParams . delete ( param ) ;
2737+ const url = urlFromQueryParams ( queryParams ) ;
2738+ history . replaceState ( history . state , '' , url ) ;
2739+ }
2740+ function urlFromQueryParams ( queryParams ) {
2741+ let queryString = '' ;
2742+ if ( Array . from ( queryParams . entries ( ) ) . length > 0 ) {
2743+ queryString += '?' + queryParams . toString ( ) ;
2744+ }
2745+ return window . location . origin + window . location . pathname + queryString + window . location . hash ;
2746+ }
2747+
2748+ class QueryStringPlugin {
2749+ constructor ( ) {
2750+ this . mapping = new Map ;
2751+ }
2752+ attachToComponent ( component ) {
2753+ this . element = component . element ;
2754+ this . registerBindings ( ) ;
2755+ component . on ( 'connect' , ( component ) => {
2756+ this . updateUrl ( component ) ;
2757+ } ) ;
2758+ component . on ( 'render:finished' , ( component ) => {
2759+ this . updateUrl ( component ) ;
2760+ } ) ;
2761+ }
2762+ registerBindings ( ) {
2763+ const rawQueryMapping = this . element . dataset . liveQueryMapping ;
2764+ if ( rawQueryMapping === undefined ) {
2765+ return ;
2766+ }
2767+ const mapping = JSON . parse ( rawQueryMapping ) ;
2768+ Object . entries ( mapping ) . forEach ( ( [ key , config ] ) => {
2769+ this . mapping . set ( key , config ) ;
2770+ } ) ;
2771+ }
2772+ updateUrl ( component ) {
2773+ this . mapping . forEach ( ( mapping , propName ) => {
2774+ const value = component . valueStore . get ( propName ) ;
2775+ if ( value === '' || value === null || value === undefined ) {
2776+ removeQueryParam ( mapping . name ) ;
2777+ }
2778+ else {
2779+ setQueryParam ( mapping . name , value ) ;
2780+ }
2781+ } ) ;
2782+ }
2783+ }
2784+
26992785const getComponent = ( element ) => LiveControllerDefault . componentRegistry . getComponent ( element ) ;
27002786class LiveControllerDefault extends Controller {
27012787 constructor ( ) {
@@ -2723,6 +2809,7 @@ class LiveControllerDefault extends Controller {
27232809 new PageUnloadingPlugin ( ) ,
27242810 new PollingPlugin ( ) ,
27252811 new SetValueOntoModelFieldsPlugin ( ) ,
2812+ new QueryStringPlugin ( ) ,
27262813 ] ;
27272814 plugins . forEach ( ( plugin ) => {
27282815 this . component . addPlugin ( plugin ) ;
0 commit comments