2 * (C) Copyright 2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2008 Nicholas A. Zigarovich
4 * (C) Copyright 2008 John J. Foerch
6 * Use, modification, and distribution are subject to the terms specified in the
9 * This is a tab bar which is based on tab-bar.js but makes customization of the
10 * tabs much easier. It provides sensible default styles but lets the user
11 * simply override these defaults by normal CSS.
16 define_variable("tab_bar_button_select", 0,
17 "The mouse button that selects tabs. " +
18 "0 = left, 1 = middle, 2 = right, null = disabled. " +
21 define_variable("tab_bar_button_close", 2,
22 "The mouse button that closes tabs.. " +
23 "0 = left, 1 = middle, 2 = right, null = disabled. " +
27 function tab_bar(window) {
28 window.tab_bar = this;
29 var scrollbox = create_XUL(window, "arrowscrollbox");
30 scrollbox.setAttribute("id", "tab2-bar");
31 scrollbox.setAttribute("orient", "horizontal");
32 var after = window.buffers.container;
34 this.element = scrollbox;
35 after.parentNode.insertBefore(scrollbox, after);
37 add_hook.call(window, "select_buffer_hook", tab_bar_select_buffer);
38 add_hook.call(window, "create_buffer_hook", tab_bar_add_buffer);
39 add_hook.call(window, "kill_buffer_hook", tab_bar_kill_buffer);
40 add_hook.call(window, "buffer_title_change_hook", tab_bar_update_buffer_title);
41 add_hook.call(window, "buffer_description_change_hook", tab_bar_update_buffer_title);
42 // add_hook.call(window, "buffer_favicon_change_hook", tab_bar_update_buffer_icon);
43 window.buffers.for_each(tab_bar_add_buffer);
44 this.update_multiple_attribute();
45 if (window.buffers.current != null)
46 tab_bar_select_buffer(window.buffers.current);
49 tab_bar.prototype.destroy = function () {
50 remove_hook.call(this.window, "select_buffer_hook", tab_bar_select_buffer);
51 remove_hook.call(this.window, "create_buffer_hook", tab_bar_add_buffer);
52 remove_hook.call(this.window, "kill_buffer_hook", tab_bar_kill_buffer);
53 remove_hook.call(this.window, "buffer_title_change_hook", tab_bar_update_buffer_title);
54 remove_hook.call(this.window, "buffer_description_change_hook", tab_bar_update_buffer_title);
55 // remove_hook.call(this.window, "buffer_favicon_change_hook", tab_bar_update_buffer_icon);
56 this.window.buffers.for_each(function (b) {
59 this.selected_buffer = null;
60 this.element.parentNode.removeChild(this.element);
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");
70 function tab_bar_add_buffer(buffer) {
73 var tabbar = buffer.window.tab_bar;
74 tabbar.update_multiple_attribute();
76 // Create a tab and add it to the tab bar
77 var tab = create_XUL(buffer.window, "hbox");
78 tab.setAttribute("class", "tab2");
79 tab.addEventListener("click", function (event) {
80 if (event.button == tab_bar_button_select) {
82 buffer.window.buffers.current = buffer;
84 }, false /* not capturing */);
85 tab.setAttribute("selected", "false");
87 // Create the label to hold the tab number
88 // TODO: Make the numbers optional and use the favicon if that's what the
90 var iconlabel = create_XUL(buffer.window, "label");
91 iconlabel.setAttribute("class", "tab2-icon");
93 // Create the label to hold the tab title
94 var label = create_XUL(buffer.window, "label");
95 label.setAttribute("class", "tab2-label");
96 label.setAttribute("crop", "end");
98 // No close button, just use the designated mouse button.
99 tab.addEventListener("click", function (event) {
100 if (event.button == tab_bar_button_close) {
102 event.stopPropagation();
104 }, false /* not capturing */);
106 // Add all the stuff to the new tab
107 tab.appendChild(iconlabel);
108 tab.appendChild(label);
109 tab.tab_label = label;
110 tab.tab_icon = iconlabel;
111 tabbar.element.appendChild(tab);
113 tab_bar_update_buffer_title(buffer);
115 // Set the tab number. Remember that at this point, the tab has already been
116 // added to the hbox.
117 var total = tabbar.element.getElementsByClassName("tab2").length;
118 iconlabel.value = total;
121 function tab_bar_kill_buffer(b) {
122 var t = b.window.tab_bar;
123 t.update_multiple_attribute();
124 if (t.selected_buffer == b)
125 t.selected_buffer = null;
126 b.tab.parentNode.removeChild(b.tab);
127 t = b.window.tab_bar;
130 // Renumber the tabs.
131 for (var i = 0; i < t.element.childNodes.length; i++) {
132 t.element.childNodes[i].childNodes[0].value = i + 1;
136 function tab_bar_select_buffer(b) {
138 var t = b.window.tab_bar;
139 if (t.selected_buffer != null)
140 t.selected_buffer.tab.setAttribute("selected", "false");
141 t.selected_buffer = b;
142 b.tab.setAttribute("selected", "true");
143 t.element.ensureElementIsVisible(b.tab);
146 function tab_bar_update_buffer_title(b) {
148 if (title == null || title.length == 0)
149 title = b.description;
150 b.tab.tab_label.setAttribute("value", title);
153 function tab_bar_install(window) {
155 throw new Error("tab bar already initialized for window");
159 function tab_bar_uninstall(window) {
161 throw new Error("tab bar not initialized for window");
162 window.tab_bar.destroy();
163 delete window.tab_bar;
166 define_global_mode("tab_bar_mode",
167 function () { // enable
168 add_hook("window_initialize_hook", tab_bar_install);
169 for_each_window(tab_bar_install);
171 function () { // disable
172 remove_hook("window_initialize_hook", tab_bar_install);
173 for_each_window(tab_bar_uninstall);