2 * (C) Copyright 2008 Jeremy Maitin-Shepard
4 * Use, modification, and distribution are subject to the terms specified in the
10 require("favicon.js");
13 function tab_bar (window) {
14 window.tab_bar = this;
15 var element = create_XUL(window, "arrowscrollbox");
16 element.setAttribute("id", "tab-bar");
17 element.setAttribute("orient", "horizontal");
18 var after = window.buffers.container;
20 this.element = element;
21 after.parentNode.insertBefore(element, after);
23 add_hook.call(window, "select_buffer_hook", tab_bar_select_buffer);
24 add_hook.call(window, "create_buffer_early_hook", tab_bar_add_buffer);
25 add_hook.call(window, "kill_buffer_hook", tab_bar_kill_buffer);
26 add_hook.call(window, "move_buffer_hook", tab_bar_move_buffer);
27 add_hook.call(window, "create_buffer_hook", tab_bar_update_buffer_title);
28 add_hook.call(window, "buffer_title_change_hook", tab_bar_update_buffer_title);
29 add_hook.call(window, "buffer_description_change_hook", tab_bar_update_buffer_title);
30 add_hook.call(window, "buffer_icon_change_hook", tab_bar_update_buffer_icon);
32 window.buffers.for_each(function (b) tab_bar_add_buffer(b, true));
33 this.update_multiple_attribute();
34 this.update_ordinals();
35 if (window.buffers.current != null)
36 tab_bar_select_buffer(window.buffers.current);
38 tab_bar.prototype.destroy = function () {
39 remove_hook.call(this.window, "select_buffer_hook", tab_bar_select_buffer);
40 remove_hook.call(this.window, "create_buffer_early_hook", tab_bar_add_buffer);
41 remove_hook.call(this.window, "kill_buffer_hook", tab_bar_kill_buffer);
42 remove_hook.call(this.window, "move_buffer_hook", tab_bar_move_buffer);
43 remove_hook.call(this.window, "create_buffer_hook", tab_bar_update_buffer_title);
44 remove_hook.call(this.window, "buffer_title_change_hook", tab_bar_update_buffer_title);
45 remove_hook.call(this.window, "buffer_description_change_hook", tab_bar_update_buffer_title);
46 remove_hook.call(this.window, "buffer_icon_change_hook", tab_bar_update_buffer_icon);
47 this.window.buffers.for_each(function (b) { delete b.tab; });
48 this.selected_buffer = null;
49 this.element.parentNode.removeChild(this.element);
50 delete this.window.tab_bar;
55 * Updates the "ordinal" attribute of all tabs.
57 tab_bar.prototype.update_ordinals = function () {
58 var buffers = this.window.buffers;
59 for (var i = 0, n = this.element.childNodes.length; i < n; i++) {
60 var ordinal = buffers.index_of(this.element.childNodes[i].buffer) + 1;
61 this.element.childNodes[i].setAttribute("ordinal", ordinal);
65 tab_bar.prototype.update_multiple_attribute = function () {
66 if (this.window.buffers.count > 1)
67 this.element.setAttribute("multiple", "true");
69 this.element.setAttribute("multiple", "false");
73 * Adds a tab for the given buffer. When second argument 'noupdate' is
74 * true, a new tab in the middle of the buffer list will not cause the
75 * ordinals of other tabs to be updated. This is used during
76 * initialization of the tab bar.
78 function tab_bar_add_buffer (b, noupdate) {
79 var t = b.window.tab_bar;
80 t.update_multiple_attribute();
81 var ordinal = b.window.buffers.index_of(b) + 1;
82 if (ordinal < b.window.buffers.buffer_list.length && ! noupdate)
84 var tab = create_XUL(b.window, "hbox");
86 tab.setAttribute("class", "tab");
87 tab.addEventListener("click", function () {
89 tab.buffer.window.buffers.current = tab.buffer;
90 }, false /* not capturing */);
91 tab.setAttribute("selected", "false");
92 var image = create_XUL(b.window, "image");
93 image.setAttribute("class", "tab-icon");
95 image.setAttribute("src", b.icon);
96 var label = create_XUL(b.window, "label");
97 label.setAttribute("class", "tab-label");
98 label.setAttribute("crop", "end");
99 var button = create_XUL(b.window, "toolbarbutton");
100 button.setAttribute("class", "tab-close-button");
101 button.addEventListener("click", function (event) {
102 kill_buffer(tab.buffer);
103 event.stopPropagation();
104 }, false /* not capturing */);
105 tab.appendChild(image);
106 tab.appendChild(label);
107 tab.appendChild(button);
108 tab.tab_label = label;
109 tab.tab_image = image;
110 t.element.appendChild(tab);
112 tab_bar_update_buffer_title(b);
114 // Note, XULRunner 1.9.x puts the tab in the wrong location if we set
115 // the ordinal before adding the tab to the tab-bar.
116 tab.setAttribute("ordinal", ordinal);
119 function tab_bar_kill_buffer (b) {
120 var t = b.window.tab_bar;
121 t.update_multiple_attribute();
122 if (t.selected_buffer == b)
123 t.selected_buffer = null;
124 b.tab.parentNode.removeChild(b.tab);
131 * Updates all tab indices and ensure that the current tab is still visible.
133 function tab_bar_move_buffer (b) {
134 var t = b.window.tab_bar;
136 t.element.ensureElementIsVisible(b.window.buffers.current.tab);
140 function tab_bar_select_buffer (b) {
141 var t = b.window.tab_bar;
142 if (t.selected_buffer != null)
143 t.selected_buffer.tab.setAttribute("selected", "false");
144 t.selected_buffer = b;
145 b.tab.setAttribute("selected", "true");
146 t.element.ensureElementIsVisible(b.tab);
149 function tab_bar_update_buffer_title (b) {
151 if (title == null || title.length == 0)
152 title = b.description;
153 b.tab.tab_label.setAttribute("value", title);
156 function tab_bar_update_buffer_icon (b) {
158 b.tab.tab_image.setAttribute("src", b.icon);
160 b.tab.tab_image.removeAttribute("src");
163 function tab_bar_install (window) {
165 throw new Error("tab bar already initialized for window");
169 function tab_bar_uninstall (window) {
171 throw new Error("tab bar not initialized for window");
172 window.tab_bar.destroy();
175 define_global_mode("tab_bar_mode",
176 function () { // enable
177 add_hook("window_initialize_hook", tab_bar_install);
178 for_each_window(tab_bar_install);
180 function () { // disable
181 remove_hook("window_initialize_hook", tab_bar_install);
182 for_each_window(tab_bar_uninstall);