@@ -14,6 +14,16 @@ import getSheet from '../../shared/sheet.js';
1414
1515const sheet = await getSheet ( '/blocks/edit/da-title/da-title.css' ) ;
1616
17+ function isSaveOnlyView ( details ) {
18+ if ( ! details ) return false ;
19+ if ( details . view === 'config' ) return true ;
20+ return details . view === 'sheet' && details . fullpath ?. includes ( '/.da/' ) ;
21+ }
22+
23+ function isHiddenActionsView ( details ) {
24+ return details ?. view === 'edit' && details ?. fullpath ?. includes ( '/.da/' ) ;
25+ }
26+
1727const ICONS = [
1828 '/blocks/edit/img/Smock_Cloud_18_N.svg' ,
1929 '/blocks/edit/img/Smock_CloudDisconnected_18_N.svg' ,
@@ -37,6 +47,8 @@ export default class DaTitle extends LitElement {
3747 collabUsers : { attribute : false } ,
3848 previewPrefix : { attribute : false } ,
3949 livePrefix : { attribute : false } ,
50+ hasChanges : { attribute : false } ,
51+ disableMessage : { attribute : false } ,
4052 _actionsVis : { state : true } ,
4153 _status : { state : true } ,
4254 _fixedActions : { state : true } ,
@@ -46,16 +58,17 @@ export default class DaTitle extends LitElement {
4658 connectedCallback ( ) {
4759 super . connectedCallback ( ) ;
4860 this . shadowRoot . adoptedStyleSheets = [ sheet ] ;
49- this . _actionsVis = [ ] ;
5061 inlinesvg ( { parent : this . shadowRoot , paths : ICONS } ) ;
51- if ( this . details . view === 'sheet' ) {
52- this . collabStatus = window . navigator . onLine
53- ? 'connected'
54- : 'offline' ;
62+ }
5563
56- window . addEventListener ( 'online' , ( ) => { this . collabStatus = 'connected' ; } ) ;
57- window . addEventListener ( 'offline' , ( ) => { this . collabStatus = 'offline' ; } ) ;
58- }
64+ disconnectedCallback ( ) {
65+ this . removeCollabListeners ( ) ;
66+ super . disconnectedCallback ( ) ;
67+ }
68+
69+ updated ( changedProperties ) {
70+ super . updated ( changedProperties ) ;
71+ if ( changedProperties . has ( 'details' ) ) this . syncDetailsState ( ) ;
5972 }
6073
6174 firstUpdated ( ) {
@@ -68,6 +81,7 @@ export default class DaTitle extends LitElement {
6881 }
6982
7083 handleError ( json , action , icon ) {
84+ // eslint-disable-next-line no-console
7185 console . log ( 'handleError' , json , action , icon ) ;
7286 this . _status = { ...json . error , action } ;
7387 icon . classList . remove ( 'is-sending' ) ;
@@ -91,26 +105,43 @@ export default class DaTitle extends LitElement {
91105 }
92106
93107 async handleAction ( action ) {
108+ if ( ! this . details ) return ;
94109 this . toggleActions ( ) ;
95110 this . _status = null ;
96- const sendBtn = this . shadowRoot . querySelector ( '.da-title-action-send-icon' ) ;
97- sendBtn . classList . add ( 'is-sending' ) ;
111+
112+ const sendBtn = this . shadowRoot . querySelector (
113+ this . actionView === 'saveOnly' ? '.da-title-action' : '.da-title-action-send-icon' ,
114+ ) ;
115+
116+ if ( sendBtn ) {
117+ sendBtn . classList . add ( 'is-sending' ) ;
118+ }
98119
99120 const { hash } = window . location ;
100121 const pathname = hash . replace ( '#' , '' ) ;
101122
102- // Only save to DA if it is a sheet or config
103- if ( this . details . view === 'sheet' ) {
123+ if ( this . details . view === 'sheet' && action === 'save' ) {
104124 const dasSave = await saveToDa ( pathname , this . sheet ) ;
125+ if ( sendBtn ) sendBtn . classList . remove ( 'is-sending' ) ;
105126 if ( ! dasSave . ok ) return ;
127+ this . hasChanges = false ;
128+ return ;
106129 }
107- if ( this . details . view === 'config' ) {
130+
131+ if ( this . _isConfigView ) {
108132 const daConfigResp = await saveDaConfig ( pathname , this . sheet ) ;
133+
134+ if ( sendBtn ) {
135+ sendBtn . classList . remove ( 'is-sending' ) ;
136+ }
137+
109138 if ( ! daConfigResp . ok ) {
110139 // eslint-disable-next-line no-console
111140 console . log ( 'Saving configuration failed because:' , daConfigResp . status , await daConfigResp . text ( ) ) ;
112- return ;
141+ } else {
142+ this . dispatchEvent ( new Event ( 'config-saved' ) ) ;
113143 }
144+ return ;
114145 }
115146 if ( action === 'preview' || action === 'publish' ) {
116147 const cdn = await getCdnConfig ( pathname ) ;
@@ -141,7 +172,7 @@ export default class DaTitle extends LitElement {
141172 window . open ( `${ toOpenInAem } ?nocache=${ Date . now ( ) } ` , toOpenInAem ) ;
142173 }
143174 if ( this . details . view === 'edit' && action === 'publish' ) saveDaVersion ( pathname ) ;
144- sendBtn . classList . remove ( 'is-sending' ) ;
175+ if ( sendBtn ) sendBtn . classList . remove ( 'is-sending' ) ;
145176 }
146177
147178 async handleRoleRequest ( ) {
@@ -189,15 +220,13 @@ export default class DaTitle extends LitElement {
189220 }
190221
191222 async toggleActions ( ) {
192- // toggle off if already on
193- if ( this . _actionsVis . length > 0 ) {
194- this . _actionsVis = [ ] ;
223+ if ( this . actionView !== 'full' ) {
195224 return ;
196225 }
197226
198- // toggle on for config
199- if ( this . details . view === 'config' ) {
200- this . _actionsVis = [ 'save' ] ;
227+ // toggle off if already on
228+ if ( ( this . _actionsVis || [ ] ) . length > 0 ) {
229+ this . _actionsVis = [ ] ;
201230 return ;
202231 }
203232
@@ -217,17 +246,87 @@ export default class DaTitle extends LitElement {
217246 return ! this . permissions . some ( ( permission ) => permission === 'write' ) ;
218247 }
219248
249+ get _isConfigView ( ) {
250+ return this . details ?. view === 'config' ;
251+ }
252+
253+ get actionView ( ) {
254+ if ( isHiddenActionsView ( this . details ) ) return 'hidden' ;
255+ if ( isSaveOnlyView ( this . details ) ) return 'saveOnly' ;
256+ return 'full' ;
257+ }
258+
259+ get visibleActions ( ) {
260+ if ( this . actionView === 'saveOnly' ) {
261+ return [ 'save' ] ;
262+ }
263+ return this . _actionsVis || [ ] ;
264+ }
265+
266+ syncDetailsState ( ) {
267+ this . _actionsVis = [ ] ;
268+ this . syncCollabStatus ( ) ;
269+ }
270+
271+ syncCollabStatus ( ) {
272+ this . removeCollabListeners ( ) ;
273+ if ( this . details ?. view !== 'sheet' ) {
274+ this . collabStatus = undefined ;
275+ return ;
276+ }
277+
278+ this . collabStatus = window . navigator . onLine
279+ ? 'connected'
280+ : 'offline' ;
281+
282+ this . _handleOnline = ( ) => { this . collabStatus = 'connected' ; } ;
283+ this . _handleOffline = ( ) => { this . collabStatus = 'offline' ; } ;
284+ window . addEventListener ( 'online' , this . _handleOnline ) ;
285+ window . addEventListener ( 'offline' , this . _handleOffline ) ;
286+ }
287+
288+ removeCollabListeners ( ) {
289+ if ( this . _handleOnline ) {
290+ window . removeEventListener ( 'online' , this . _handleOnline ) ;
291+ this . _handleOnline = null ;
292+ }
293+ if ( this . _handleOffline ) {
294+ window . removeEventListener ( 'offline' , this . _handleOffline ) ;
295+ this . _handleOffline = null ;
296+ }
297+ }
298+
220299 renderActions ( ) {
221- return html `${ this . _actionsVis . map ( ( action ) => html `
300+ const isDisabled = ! ! this . disableMessage || ( this . actionView === 'saveOnly' && ! this . hasChanges ) ;
301+ return html `${ this . visibleActions . map ( ( action ) => html `
222302 < button
223303 @click =${ ( ) => this . handleAction ( action ) }
224- class ="con-button blue da-title-action"
225- aria-label="Send">
304+ class ="con-button da-title-action ${ isDisabled ? '' : 'blue' } "
305+ aria-label="${ action } "
306+ ?disabled=${ isDisabled } >
226307 ${ action . charAt ( 0 ) . toUpperCase ( ) + action . slice ( 1 ) }
227308 </ button >
228309 ` ) } `;
229310 }
230311
312+ renderActionControls ( ) {
313+ if ( this . actionView === 'hidden' ) return nothing ;
314+
315+ return html `
316+ < div class ="da-title-actions ${ this . _fixedActions ? 'is-fixed' : '' } ${ this . actionView === 'full' && this . _actionsVis ?. length > 0 ? 'is-open' : '' } ${ this . actionView === 'saveOnly' ? 'save-only' : '' } ">
317+ ${ this . renderActions ( ) }
318+ ${ this . actionView === 'saveOnly' ? nothing : html `
319+ < button
320+ @click =${ this . toggleActions }
321+ class ="con-button blue da-title-action-send"
322+ aria-label="Send">
323+ < span class ="da-title-action-send-icon "> </ span >
324+ </ button >
325+ ` }
326+ </ div >
327+ ` ;
328+ }
329+
231330 popover ( { target } ) {
232331 // If toggling off, simply remove;
233332 if ( target . classList . contains ( 'collab-popup' ) ) {
@@ -279,6 +378,8 @@ export default class DaTitle extends LitElement {
279378 }
280379
281380 render ( ) {
381+ if ( ! this . details ) return nothing ;
382+
282383 return html `
283384 < div class ="da-title-inner ${ this . _readOnly ? 'is-read-only' : '' } ">
284385 < div class ="da-title-name ">
@@ -290,17 +391,12 @@ export default class DaTitle extends LitElement {
290391 < div class ="da-title-collab-actions-wrapper ">
291392 ${ this . collabStatus ? this . renderCollab ( ) : nothing }
292393 ${ this . _status ? this . renderError ( ) : nothing }
293- < div class ="da-title-actions ${ this . _fixedActions ? 'is-fixed' : '' } ${ this . _actionsVis . length > 0 ? 'is-open' : '' } ">
294- ${ this . renderActions ( ) }
295- < button
296- @click =${ this . toggleActions }
297- class ="con-button blue da-title-action-send"
298- aria-label="Send">
299- < span class ="da-title-action-send-icon "> </ span >
300- </ button >
301- </ div >
394+ ${ this . renderActionControls ( ) }
302395 </ div >
303396 </ div >
397+ ${ this . disableMessage
398+ ? html `< p class ="da-title-save-disabled-msg "> ${ this . disableMessage } </ p > `
399+ : nothing }
304400 ${ this . _dialog ? this . renderDialog ( ) : nothing }
305401 ` ;
306402 }
0 commit comments