@@ -1030,7 +1030,9 @@ class ValueStore {
1030
1030
}
1031
1031
set ( name , value ) {
1032
1032
const normalizedName = normalizeModelName ( name ) ;
1033
- this . updatedModels . push ( normalizedName ) ;
1033
+ if ( ! this . updatedModels . includes ( normalizedName ) ) {
1034
+ this . updatedModels . push ( normalizedName ) ;
1035
+ }
1034
1036
this . controller . dataValue = setDeepData ( this . controller . dataValue , normalizedName , value ) ;
1035
1037
}
1036
1038
hasAtTopLevel ( name ) {
@@ -1043,6 +1045,9 @@ class ValueStore {
1043
1045
all ( ) {
1044
1046
return this . controller . dataValue ;
1045
1047
}
1048
+ areAnyModelsUpdated ( targetedModels ) {
1049
+ return ( this . updatedModels . filter ( modelName => targetedModels . includes ( modelName ) ) ) . length > 0 ;
1050
+ }
1046
1051
}
1047
1052
1048
1053
function getValueFromElement ( element , valueStore ) {
@@ -1298,32 +1303,35 @@ class default_1 extends Controller {
1298
1303
args : directive . named
1299
1304
} ) ;
1300
1305
let handled = false ;
1306
+ const validModifiers = new Map ( ) ;
1307
+ validModifiers . set ( 'prevent' , ( ) => {
1308
+ event . preventDefault ( ) ;
1309
+ } ) ;
1310
+ validModifiers . set ( 'stop' , ( ) => {
1311
+ event . stopPropagation ( ) ;
1312
+ } ) ;
1313
+ validModifiers . set ( 'self' , ( ) => {
1314
+ if ( event . target !== event . currentTarget ) {
1315
+ return ;
1316
+ }
1317
+ } ) ;
1318
+ validModifiers . set ( 'debounce' , ( modifier ) => {
1319
+ const length = modifier . value ? parseInt ( modifier . value ) : this . getDefaultDebounce ( ) ;
1320
+ __classPrivateFieldGet ( this , _instances , "m" , _clearRequestDebounceTimeout ) . call ( this ) ;
1321
+ this . requestDebounceTimeout = window . setTimeout ( ( ) => {
1322
+ this . requestDebounceTimeout = null ;
1323
+ __classPrivateFieldGet ( this , _instances , "m" , _startPendingRequest ) . call ( this ) ;
1324
+ } , length ) ;
1325
+ handled = true ;
1326
+ } ) ;
1301
1327
directive . modifiers . forEach ( ( modifier ) => {
1302
- switch ( modifier . name ) {
1303
- case 'prevent' :
1304
- event . preventDefault ( ) ;
1305
- break ;
1306
- case 'stop' :
1307
- event . stopPropagation ( ) ;
1308
- break ;
1309
- case 'self' :
1310
- if ( event . target !== event . currentTarget ) {
1311
- return ;
1312
- }
1313
- break ;
1314
- case 'debounce' : {
1315
- const length = modifier . value ? parseInt ( modifier . value ) : this . getDefaultDebounce ( ) ;
1316
- __classPrivateFieldGet ( this , _instances , "m" , _clearRequestDebounceTimeout ) . call ( this ) ;
1317
- this . requestDebounceTimeout = window . setTimeout ( ( ) => {
1318
- this . requestDebounceTimeout = null ;
1319
- __classPrivateFieldGet ( this , _instances , "m" , _startPendingRequest ) . call ( this ) ;
1320
- } , length ) ;
1321
- handled = true ;
1322
- break ;
1323
- }
1324
- default :
1325
- console . warn ( `Unknown modifier ${ modifier . name } in action ${ rawAction } ` ) ;
1328
+ var _a ;
1329
+ if ( validModifiers . has ( modifier . name ) ) {
1330
+ const callable = ( _a = validModifiers . get ( modifier . name ) ) !== null && _a !== void 0 ? _a : ( ( ) => { } ) ;
1331
+ callable ( modifier ) ;
1332
+ return ;
1326
1333
}
1334
+ console . warn ( `Unknown modifier ${ modifier . name } in action "${ rawAction } ". Available modifiers are: ${ Array . from ( validModifiers . keys ( ) ) . join ( ', ' ) } .` ) ;
1327
1335
} ) ;
1328
1336
if ( ! handled ) {
1329
1337
if ( getModelDirectiveFromElement ( event . currentTarget , false ) ) {
@@ -1436,11 +1444,17 @@ class default_1 extends Controller {
1436
1444
_onLoadingStart ( ) {
1437
1445
this . _handleLoadingToggle ( true ) ;
1438
1446
}
1439
- _onLoadingFinish ( ) {
1440
- this . _handleLoadingToggle ( false ) ;
1447
+ _onLoadingFinish ( targetElement = null ) {
1448
+ this . _handleLoadingToggle ( false , targetElement ) ;
1441
1449
}
1442
- _handleLoadingToggle ( isLoading ) {
1443
- this . _getLoadingDirectives ( ) . forEach ( ( { element, directives } ) => {
1450
+ _handleLoadingToggle ( isLoading , targetElement = null ) {
1451
+ if ( isLoading ) {
1452
+ this . _addAttributes ( this . element , [ 'busy' ] ) ;
1453
+ }
1454
+ else {
1455
+ this . _removeAttributes ( this . element , [ 'busy' ] ) ;
1456
+ }
1457
+ this . _getLoadingDirectives ( targetElement ) . forEach ( ( { element, directives } ) => {
1444
1458
if ( isLoading ) {
1445
1459
this . _addAttributes ( element , [ 'data-live-is-loading' ] ) ;
1446
1460
}
@@ -1454,6 +1468,43 @@ class default_1 extends Controller {
1454
1468
}
1455
1469
_handleLoadingDirective ( element , isLoading , directive ) {
1456
1470
const finalAction = parseLoadingAction ( directive . action , isLoading ) ;
1471
+ const targetedActions = [ ] ;
1472
+ const targetedModels = [ ] ;
1473
+ let delay = 0 ;
1474
+ const validModifiers = new Map ( ) ;
1475
+ validModifiers . set ( 'delay' , ( modifier ) => {
1476
+ if ( ! isLoading ) {
1477
+ return ;
1478
+ }
1479
+ delay = modifier . value ? parseInt ( modifier . value ) : 200 ;
1480
+ } ) ;
1481
+ validModifiers . set ( 'action' , ( modifier ) => {
1482
+ if ( ! modifier . value ) {
1483
+ throw new Error ( `The "action" in data-loading must have an action name - e.g. action(foo). It's missing for "${ directive . getString ( ) } "` ) ;
1484
+ }
1485
+ targetedActions . push ( modifier . value ) ;
1486
+ } ) ;
1487
+ validModifiers . set ( 'model' , ( modifier ) => {
1488
+ if ( ! modifier . value ) {
1489
+ throw new Error ( `The "model" in data-loading must have an action name - e.g. model(foo). It's missing for "${ directive . getString ( ) } "` ) ;
1490
+ }
1491
+ targetedModels . push ( modifier . value ) ;
1492
+ } ) ;
1493
+ directive . modifiers . forEach ( ( modifier ) => {
1494
+ var _a ;
1495
+ if ( validModifiers . has ( modifier . name ) ) {
1496
+ const callable = ( _a = validModifiers . get ( modifier . name ) ) !== null && _a !== void 0 ? _a : ( ( ) => { } ) ;
1497
+ callable ( modifier ) ;
1498
+ return ;
1499
+ }
1500
+ throw new Error ( `Unknown modifier "${ modifier . name } " used in data-loading="${ directive . getString ( ) } ". Available modifiers are: ${ Array . from ( validModifiers . keys ( ) ) . join ( ', ' ) } .` ) ;
1501
+ } ) ;
1502
+ if ( isLoading && targetedActions . length > 0 && this . backendRequest && ! this . backendRequest . containsOneOfActions ( targetedActions ) ) {
1503
+ return ;
1504
+ }
1505
+ if ( isLoading && targetedModels . length > 0 && ! this . valueStore . areAnyModelsUpdated ( targetedModels ) ) {
1506
+ return ;
1507
+ }
1457
1508
let loadingDirective ;
1458
1509
switch ( finalAction ) {
1459
1510
case 'show' :
@@ -1479,33 +1530,20 @@ class default_1 extends Controller {
1479
1530
default :
1480
1531
throw new Error ( `Unknown data-loading action "${ finalAction } "` ) ;
1481
1532
}
1482
- let isHandled = false ;
1483
- directive . modifiers . forEach ( ( modifier => {
1484
- switch ( modifier . name ) {
1485
- case 'delay' : {
1486
- if ( ! isLoading ) {
1487
- break ;
1488
- }
1489
- const delayLength = modifier . value ? parseInt ( modifier . value ) : 200 ;
1490
- window . setTimeout ( ( ) => {
1491
- if ( element . hasAttribute ( 'data-live-is-loading' ) ) {
1492
- loadingDirective ( ) ;
1493
- }
1494
- } , delayLength ) ;
1495
- isHandled = true ;
1496
- break ;
1533
+ if ( delay ) {
1534
+ window . setTimeout ( ( ) => {
1535
+ if ( this . isRequestActive ( ) ) {
1536
+ loadingDirective ( ) ;
1497
1537
}
1498
- default :
1499
- throw new Error ( `Unknown modifier ${ modifier . name } used in the loading directive ${ directive . getString ( ) } ` ) ;
1500
- }
1501
- } ) ) ;
1502
- if ( ! isHandled ) {
1503
- loadingDirective ( ) ;
1538
+ } , delay ) ;
1539
+ return ;
1504
1540
}
1541
+ loadingDirective ( ) ;
1505
1542
}
1506
- _getLoadingDirectives ( ) {
1543
+ _getLoadingDirectives ( targetElement = null ) {
1507
1544
const loadingDirectives = [ ] ;
1508
- this . element . querySelectorAll ( '[data-loading]' ) . forEach ( ( element => {
1545
+ const element = targetElement || this . element ;
1546
+ element . querySelectorAll ( '[data-loading]' ) . forEach ( ( element => {
1509
1547
if ( ! ( element instanceof HTMLElement ) && ! ( element instanceof SVGElement ) ) {
1510
1548
throw new Error ( 'Invalid Element Type' ) ;
1511
1549
}
@@ -1548,6 +1586,7 @@ class default_1 extends Controller {
1548
1586
}
1549
1587
_executeMorphdom ( newHtml , modifiedElements ) {
1550
1588
const newElement = htmlToElement ( newHtml ) ;
1589
+ this . _onLoadingFinish ( newElement ) ;
1551
1590
morphdom ( this . element , newElement , {
1552
1591
getNodeKey : ( node ) => {
1553
1592
if ( ! ( node instanceof HTMLElement ) ) {
@@ -1578,19 +1617,13 @@ class default_1 extends Controller {
1578
1617
&& ! this . _shouldChildLiveElementUpdate ( fromEl , toEl ) ) {
1579
1618
return false ;
1580
1619
}
1581
- if ( fromEl . hasAttribute ( 'data-live-ignore' ) ) {
1582
- return false ;
1583
- }
1584
- return true ;
1620
+ return ! fromEl . hasAttribute ( 'data-live-ignore' ) ;
1585
1621
} ,
1586
1622
onBeforeNodeDiscarded ( node ) {
1587
1623
if ( ! ( node instanceof HTMLElement ) ) {
1588
1624
return true ;
1589
1625
}
1590
- if ( node . hasAttribute ( 'data-live-ignore' ) ) {
1591
- return false ;
1592
- }
1593
- return true ;
1626
+ return ! node . hasAttribute ( 'data-live-ignore' ) ;
1594
1627
}
1595
1628
} ) ;
1596
1629
this . _exposeOriginalData ( ) ;
@@ -1846,6 +1879,9 @@ class default_1 extends Controller {
1846
1879
}
1847
1880
} ) ;
1848
1881
}
1882
+ isRequestActive ( ) {
1883
+ return ! ! this . backendRequest ;
1884
+ }
1849
1885
}
1850
1886
_instances = new WeakSet ( ) , _startPendingRequest = function _startPendingRequest ( ) {
1851
1887
if ( ! this . backendRequest && ( this . pendingActions . length > 0 || this . isRerenderRequested ) ) {
@@ -1865,7 +1901,6 @@ _instances = new WeakSet(), _startPendingRequest = function _startPendingRequest
1865
1901
'Accept' : 'application/vnd.live-component+html' ,
1866
1902
} ;
1867
1903
const updatedModels = this . valueStore . updatedModels ;
1868
- this . valueStore . updatedModels = [ ] ;
1869
1904
if ( actions . length === 0 && this . _willDataFitInUrl ( this . valueStore . asJson ( ) , params ) ) {
1870
1905
params . set ( 'data' , this . valueStore . asJson ( ) ) ;
1871
1906
updatedModels . forEach ( ( model ) => {
@@ -1893,10 +1928,11 @@ _instances = new WeakSet(), _startPendingRequest = function _startPendingRequest
1893
1928
}
1894
1929
fetchOptions . body = JSON . stringify ( requestData ) ;
1895
1930
}
1896
- this . _onLoadingStart ( ) ;
1897
1931
const paramsString = params . toString ( ) ;
1898
1932
const thisPromise = fetch ( `${ url } ${ paramsString . length > 0 ? `?${ paramsString } ` : '' } ` , fetchOptions ) ;
1899
- this . backendRequest = new BackendRequest ( thisPromise ) ;
1933
+ this . backendRequest = new BackendRequest ( thisPromise , actions . map ( action => action . name ) ) ;
1934
+ this . _onLoadingStart ( ) ;
1935
+ this . valueStore . updatedModels = [ ] ;
1900
1936
thisPromise . then ( async ( response ) => {
1901
1937
const html = await response . text ( ) ;
1902
1938
if ( response . headers . get ( 'Content-Type' ) !== 'application/vnd.live-component+html' ) {
@@ -1946,8 +1982,12 @@ default_1.values = {
1946
1982
debounce : Number ,
1947
1983
} ;
1948
1984
class BackendRequest {
1949
- constructor ( promise ) {
1985
+ constructor ( promise , actions ) {
1950
1986
this . promise = promise ;
1987
+ this . actions = actions ;
1988
+ }
1989
+ containsOneOfActions ( targetedActions ) {
1990
+ return ( this . actions . filter ( action => targetedActions . includes ( action ) ) ) . length > 0 ;
1951
1991
}
1952
1992
}
1953
1993
const parseLoadingAction = function ( action , isLoading ) {
0 commit comments