2 * (C) Copyright 2008 Jeremy Maitin-Shepard
4 * Use, modification, and distribution are subject to the terms specified in the
11 function tab_bar (window
) {
12 window
.tab_bar
= this;
13 var element
= create_XUL(window
, "arrowscrollbox");
14 element
.setAttribute("id", "tab-bar");
15 element
.setAttribute("orient", "horizontal");
16 var after
= window
.buffers
.container
;
18 this.element
= element
;
19 after
.parentNode
.insertBefore(element
, after
);
21 add_hook
.call(window
, "select_buffer_hook", tab_bar_select_buffer
);
22 add_hook
.call(window
, "create_buffer_early_hook", tab_bar_add_buffer
);
23 add_hook
.call(window
, "kill_buffer_hook", tab_bar_kill_buffer
);
24 add_hook
.call(window
, "move_buffer_hook", tab_bar_move_buffer
);
25 add_hook
.call(window
, "create_buffer_hook", tab_bar_update_buffer_title
);
26 add_hook
.call(window
, "buffer_title_change_hook", tab_bar_update_buffer_title
);
27 add_hook
.call(window
, "buffer_description_change_hook", tab_bar_update_buffer_title
);
28 add_hook
.call(window
, "buffer_icon_change_hook", tab_bar_update_buffer_icon
);
30 window
.buffers
.for_each(function (b
) tab_bar_add_buffer(b
, true));
31 this.update_multiple_attribute();
32 this.update_ordinals();
33 if (window
.buffers
.current
!= null)
34 tab_bar_select_buffer(window
.buffers
.current
);
36 tab_bar
.prototype.destroy = function () {
37 remove_hook
.call(this.window
, "select_buffer_hook", tab_bar_select_buffer
);
38 remove_hook
.call(this.window
, "create_buffer_early_hook", tab_bar_add_buffer
);
39 remove_hook
.call(this.window
, "kill_buffer_hook", tab_bar_kill_buffer
);
40 remove_hook
.call(this.window
, "move_buffer_hook", tab_bar_move_buffer
);
41 remove_hook
.call(this.window
, "create_buffer_hook", tab_bar_update_buffer_title
);
42 remove_hook
.call(this.window
, "buffer_title_change_hook", tab_bar_update_buffer_title
);
43 remove_hook
.call(this.window
, "buffer_description_change_hook", tab_bar_update_buffer_title
);
44 remove_hook
.call(this.window
, "buffer_icon_change_hook", tab_bar_update_buffer_icon
);
45 this.window
.buffers
.for_each(function (b
) { delete b
.tab
; });
46 this.selected_buffer
= null;
47 this.element
.parentNode
.removeChild(this.element
);
48 delete this.window
.tab_bar
;
53 * Updates the "ordinal" attribute of all tabs.
55 tab_bar
.prototype.update_ordinals = function () {
56 var buffers
= this.window
.buffers
;
57 for (var i
= 0, n
= this.element
.childNodes
.length
; i
< n
; i
++) {
58 var ordinal
= buffers
.index_of(this.element
.childNodes
[i
].buffer
) + 1;
59 this.element
.childNodes
[i
].setAttribute("ordinal", ordinal
);
63 tab_bar
.prototype.update_multiple_attribute = function () {
64 if (this.window
.buffers
.count
> 1)
65 this.element
.setAttribute("multiple", "true");
67 this.element
.setAttribute("multiple", "false");
71 * Adds a tab for the given buffer. When second argument 'noupdate' is
72 * true, a new tab in the middle of the buffer list will not cause the
73 * ordinals of other tabs to be updated. This is used during
74 * initialization of the tab bar.
76 function tab_bar_add_buffer (b
, noupdate
) {
77 var t
= b
.window
.tab_bar
;
78 t
.update_multiple_attribute();
79 var ordinal
= b
.window
.buffers
.index_of(b
) + 1;
80 if (ordinal
< b
.window
.buffers
.buffer_list
.length
&& ! noupdate
)
82 var tab
= create_XUL(b
.window
, "hbox");
84 tab
.setAttribute("class", "tab");
85 tab
.addEventListener("click", function () {
87 tab
.buffer
.window
.buffers
.current
= tab
.buffer
;
88 }, false /* not capturing */);
89 tab
.setAttribute("selected", "false");
90 var image
= create_XUL(b
.window
, "image");
91 image
.setAttribute("class", "tab-icon");
93 image
.setAttribute("src", b
.icon
);
94 var label
= create_XUL(b
.window
, "label");
95 label
.setAttribute("class", "tab-label");
96 label
.setAttribute("crop", "end");
97 var button
= create_XUL(b
.window
, "toolbarbutton");
98 button
.setAttribute("class", "tab-close-button");
99 button
.addEventListener("click", function (event
) {
100 kill_buffer(tab
.buffer
);
101 event
.stopPropagation();
102 }, false /* not capturing */);
103 tab
.appendChild(image
);
104 tab
.appendChild(label
);
105 tab
.appendChild(button
);
106 tab
.tab_label
= label
;
107 tab
.tab_image
= image
;
108 t
.element
.appendChild(tab
);
110 tab_bar_update_buffer_title(b
);
112 // Note, XULRunner 1.9.x puts the tab in the wrong location if we set
113 // the ordinal before adding the tab to the tab-bar.
114 tab
.setAttribute("ordinal", ordinal
);
117 function tab_bar_kill_buffer (b
) {
118 var t
= b
.window
.tab_bar
;
119 t
.update_multiple_attribute();
120 if (t
.selected_buffer
== b
)
121 t
.selected_buffer
= null;
122 b
.tab
.parentNode
.removeChild(b
.tab
);
129 * Updates all tab indices and ensure that the current tab is still visible.
131 function tab_bar_move_buffer (b
) {
132 var t
= b
.window
.tab_bar
;
134 t
.element
.ensureElementIsVisible(b
.window
.buffers
.current
.tab
);
138 function tab_bar_select_buffer (b
) {
139 var t
= b
.window
.tab_bar
;
140 if (t
.selected_buffer
!= null)
141 t
.selected_buffer
.tab
.setAttribute("selected", "false");
142 t
.selected_buffer
= b
;
143 b
.tab
.setAttribute("selected", "true");
144 t
.element
.ensureElementIsVisible(b
.tab
);
147 function tab_bar_update_buffer_title (b
) {
149 if (title
== null || title
.length
== 0)
150 title
= b
.description
;
151 b
.tab
.tab_label
.setAttribute("value", title
);
154 function tab_bar_update_buffer_icon (b
) {
156 b
.tab
.tab_image
.setAttribute("src", b
.icon
);
158 b
.tab
.tab_image
.removeAttribute("src");
161 function tab_bar_install (window
) {
163 throw new Error("tab bar already initialized for window");
167 function tab_bar_uninstall (window
) {
169 throw new Error("tab bar not initialized for window");
170 window
.tab_bar
.destroy();
173 define_global_mode("tab_bar_mode",
174 function () { // enable
175 add_hook("window_initialize_hook", tab_bar_install
);
176 for_each_window(tab_bar_install
);
178 function () { // disable
179 remove_hook("window_initialize_hook", tab_bar_install
);
180 for_each_window(tab_bar_uninstall
);