@@ -10,10 +10,16 @@ var gZenUIManager = {
10
10
XPCOMUtils . defineLazyPreferenceGetter ( this , 'contentElementSeparation' , 'zen.theme.content-element-separation' , 0 ) ;
11
11
XPCOMUtils . defineLazyPreferenceGetter ( this , 'urlbarWaitToClear' , 'zen.urlbar.wait-to-clear' , 0 ) ;
12
12
13
+ gURLBar . _zenTrimURL = this . urlbarTrim . bind ( this ) ;
14
+
13
15
ChromeUtils . defineLazyGetter ( this , 'motion' , ( ) => {
14
16
return ChromeUtils . importESModule ( 'chrome://browser/content/zen-vendor/motion.min.mjs' , { global : 'current' } ) ;
15
17
} ) ;
16
18
19
+ ChromeUtils . defineLazyGetter ( this , '_toastContainer' , ( ) => {
20
+ return document . getElementById ( 'zen-toast-container' ) ;
21
+ } ) ;
22
+
17
23
new ResizeObserver ( this . updateTabsToolbar . bind ( this ) ) . observe ( document . getElementById ( 'TabsToolbar' ) ) ;
18
24
19
25
new ResizeObserver (
@@ -147,6 +153,8 @@ var gZenUIManager = {
147
153
this . __currentPopupTrackElement = null ;
148
154
} ,
149
155
156
+ // Section: URL bar
157
+
150
158
get newtabButtons ( ) {
151
159
return document . querySelectorAll ( '#tabs-newtab-button' ) ;
152
160
} ,
@@ -209,6 +217,46 @@ var gZenUIManager = {
209
217
}
210
218
}
211
219
} ,
220
+
221
+ urlbarTrim ( aURL ) {
222
+ if ( gZenVerticalTabsManager . _hasSetSingleToolbar ) {
223
+ let url = BrowserUIUtils . removeSingleTrailingSlashFromURL ( aURL ) ;
224
+ return url . startsWith ( 'http://' ) || url . startsWith ( 'https://' ) ? url . split ( '/' ) [ 2 ] : url ;
225
+ }
226
+ return BrowserUIUtils . trimURL ( aURL ) ;
227
+ } ,
228
+
229
+ // Section: Notification messages
230
+ _createToastElement ( messageId , options ) {
231
+ const element = document . createXULElement ( 'vbox' ) ;
232
+ const label = document . createXULElement ( 'label' ) ;
233
+ document . l10n . setAttributes ( label , messageId , options ) ;
234
+ element . appendChild ( label ) ;
235
+ if ( options . descriptionId ) {
236
+ const description = document . createXULElement ( 'label' ) ;
237
+ description . classList . add ( 'description' ) ;
238
+ document . l10n . setAttributes ( description , options . descriptionId , options ) ;
239
+ element . appendChild ( description ) ;
240
+ }
241
+ element . classList . add ( 'zen-toast' ) ;
242
+ return element ;
243
+ } ,
244
+
245
+ async showToast ( messageId , options = { } ) {
246
+ const toast = this . _createToastElement ( messageId , options ) ;
247
+ this . _toastContainer . removeAttribute ( 'hidden' ) ;
248
+ this . _toastContainer . appendChild ( toast ) ;
249
+ await this . motion . animate ( toast , { opacity : [ 0 , 1 ] , scale : [ 0.8 , 1 ] } , { type : 'spring' , bounce : 0.5 , duration : 0.5 } ) ;
250
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 3000 ) ) ;
251
+ await this . motion . animate ( toast , { opacity : [ 1 , 0 ] , scale : [ 1 , 0.9 ] } , { duration : 0.2 , bounce : 0 } ) ;
252
+ const toastHeight = toast . getBoundingClientRect ( ) . height ;
253
+ // 5 for the separation between toasts
254
+ await this . motion . animate ( toast , { marginBottom : [ 0 , `-${ toastHeight + 5 } px` ] } , { duration : 0.2 } ) ;
255
+ toast . remove ( ) ;
256
+ if ( ! this . _toastContainer . hasChildNodes ( ) ) {
257
+ this . _toastContainer . setAttribute ( 'hidden' , 'true' ) ;
258
+ }
259
+ } ,
212
260
} ;
213
261
214
262
var gZenVerticalTabsManager = {
@@ -248,6 +296,9 @@ var gZenVerticalTabsManager = {
248
296
if ( ! this . isWindowsStyledButtons ) {
249
297
document . documentElement . setAttribute ( 'zen-window-buttons-reversed' , true ) ;
250
298
}
299
+
300
+ this . _renameTabHalt = this . renameTabHalt . bind ( this ) ;
301
+ gBrowser . tabContainer . addEventListener ( 'dblclick' , this . renameTabStart . bind ( this ) ) ;
251
302
} ,
252
303
253
304
toggleExpand ( ) {
@@ -613,4 +664,89 @@ var gZenVerticalTabsManager = {
613
664
}
614
665
target . appendChild ( child ) ;
615
666
} ,
667
+
668
+ async renameTabKeydown ( event ) {
669
+ if ( event . key === 'Enter' ) {
670
+ let label = this . _tabEdited . querySelector ( '.tab-label-container-editing' ) ;
671
+ let input = this . _tabEdited . querySelector ( '#tab-label-input' ) ;
672
+ let newName = input . value . trim ( ) ;
673
+
674
+ // Check if name is blank, reset if so
675
+ // Always remove, so we can always rename and if it's empty,
676
+ // it will reset to the original name anyway
677
+ this . _tabEdited . removeAttribute ( 'zen-has-static-label' ) ;
678
+ if ( newName ) {
679
+ gBrowser . _setTabLabel ( this . _tabEdited , newName ) ;
680
+ this . _tabEdited . setAttribute ( 'zen-has-static-label' , 'true' ) ;
681
+ } else {
682
+ gBrowser . setTabTitle ( this . _tabEdited ) ;
683
+ }
684
+ if ( this . _tabEdited . getAttribute ( 'zen-pin-id' ) ) {
685
+ // Update pin title in storage
686
+ await gZenPinnedTabManager . updatePinTitle ( this . _tabEdited , this . _tabEdited . label , ! ! newName ) ;
687
+ }
688
+
689
+ // Maybe add some confetti here?!?
690
+ gZenUIManager . motion . animate (
691
+ this . _tabEdited ,
692
+ {
693
+ scale : [ 1 , 0.98 , 1 ] ,
694
+ } ,
695
+ {
696
+ duration : 0.25 ,
697
+ }
698
+ ) ;
699
+
700
+ this . _tabEdited . querySelector ( '.tab-editor-container' ) . remove ( ) ;
701
+ label . classList . remove ( 'tab-label-container-editing' ) ;
702
+
703
+ this . _tabEdited = null ;
704
+ } else if ( event . key === 'Escape' ) {
705
+ event . target . blur ( ) ;
706
+ }
707
+ } ,
708
+
709
+ renameTabStart ( event ) {
710
+ if (
711
+ this . _tabEdited ||
712
+ ! Services . prefs . getBoolPref ( 'zen.tabs.rename-tabs' ) ||
713
+ Services . prefs . getBoolPref ( 'browser.tabs.closeTabByDblclick' ) ||
714
+ ! gZenVerticalTabsManager . _prefsSidebarExpanded
715
+ )
716
+ return ;
717
+ this . _tabEdited = event . target . closest ( '.tabbrowser-tab' ) ;
718
+ if ( ! this . _tabEdited || ! this . _tabEdited . pinned || this . _tabEdited . hasAttribute ( 'zen-essential' ) ) {
719
+ this . _tabEdited = null ;
720
+ return ;
721
+ }
722
+ const label = this . _tabEdited . querySelector ( '.tab-label-container' ) ;
723
+ label . classList . add ( 'tab-label-container-editing' ) ;
724
+
725
+ const container = window . MozXULElement . parseXULToFragment ( `
726
+ <vbox class="tab-label-container tab-editor-container" flex="1" align="start" pack="center"></vbox>
727
+ ` ) ;
728
+ label . after ( container ) ;
729
+ const containerHtml = this . _tabEdited . querySelector ( '.tab-editor-container' ) ;
730
+ const input = document . createElement ( 'input' ) ;
731
+ input . id = 'tab-label-input' ;
732
+ input . value = this . _tabEdited . label ;
733
+ input . addEventListener ( 'keydown' , this . renameTabKeydown . bind ( this ) ) ;
734
+
735
+ containerHtml . appendChild ( input ) ;
736
+ input . focus ( ) ;
737
+ input . select ( ) ;
738
+
739
+ input . addEventListener ( 'blur' , this . _renameTabHalt ) ;
740
+ } ,
741
+
742
+ renameTabHalt ( event ) {
743
+ if ( document . activeElement === event . target || ! this . _tabEdited ) {
744
+ return ;
745
+ }
746
+ this . _tabEdited . querySelector ( '.tab-editor-container' ) . remove ( ) ;
747
+ const label = this . _tabEdited . querySelector ( '.tab-label-container-editing' ) ;
748
+ label . classList . remove ( 'tab-label-container-editing' ) ;
749
+
750
+ this . _tabEdited = null ;
751
+ } ,
616
752
} ;
0 commit comments