isearch-backspace, isearch-done: docstrings
[conkeror.git] / modules / new-tabs.js
blob2f271d55fea049cdf59ae69e685dc9b09bda32b1
1 /**
2  * (C) Copyright 2008 Jeremy Maitin-Shepard
3  * (C) Copyright 2008 Nicholas A. Zigarovich
4  * (C) Copyright 2008 John J. Foerch
5  * (C) Copyright 2011 Peter Lunicks
6  *
7  * Use, modification, and distribution are subject to the terms specified in the
8  * COPYING file.
9  *
10  * This is a tab bar which is based on tab-bar.js but makes customization of the
11  * tabs much easier. It provides sensible default styles but lets the user
12  * simply override these defaults by normal CSS.
13  **/
15 require("mode.js");
17 define_variable("tab_bar_button_select", 0,
18                 "The mouse button that selects tabs." +
19                 "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.");
25 define_variable("tab_bar_show_icon", false,
26                 "Whether or not to show buffer icons in tabs.");
28 define_variable("tab_bar_show_index", true,
29                 "Whether or not to show the tab index in each tab.");
31 /**
32  * Constructs a tab bar for the given window.
33  */
34 function tab_bar (window) {
35     window.tab_bar = this;
36     var scrollbox = create_XUL(window, "arrowscrollbox");
37     scrollbox.setAttribute("id", "tab2-bar");
38     scrollbox.setAttribute("orient", "horizontal");
39     var after = window.buffers.container;
40     this.window = window;
41     this.element = scrollbox;
42     after.parentNode.insertBefore(scrollbox, after);
44     add_hook.call(window, "select_buffer_hook", tab_bar_select_buffer);
45     add_hook.call(window, "create_buffer_early_hook", tab_bar_add_buffer);
46     add_hook.call(window, "kill_buffer_hook", tab_bar_kill_buffer);
47     add_hook.call(window, "move_buffer_hook", tab_bar_move_buffer);
48     add_hook.call(window, "create_buffer_hook", tab_bar_update_buffer_title);
49     add_hook.call(window, "buffer_title_change_hook", tab_bar_update_buffer_title);
50     add_hook.call(window, "buffer_description_change_hook", tab_bar_update_buffer_title);
51     add_hook.call(window, "buffer_icon_change_hook", tab_bar_update_buffer_icon);
53     window.buffers.for_each(function (b) tab_bar_add_buffer(b, true));
54     this.update_multiple_attribute();
55     if (window.buffers.current != null)
56         tab_bar_select_buffer(window.buffers.current);
60 /**
61  * Destroys the tab bar.
62  */
63 tab_bar.prototype.destroy = function () {
64     remove_hook.call(this.window, "select_buffer_hook", tab_bar_select_buffer);
65     remove_hook.call(this.window, "create_buffer_early_hook", tab_bar_add_buffer);
66     remove_hook.call(this.window, "kill_buffer_hook", tab_bar_kill_buffer);
67     remove_hook.call(this.window, "move_buffer_hook", tab_bar_move_buffer);
68     remove_hook.call(this.window, "create_buffer_hook", tab_bar_update_buffer_title);
69     remove_hook.call(this.window, "buffer_title_change_hook", tab_bar_update_buffer_title);
70     remove_hook.call(this.window, "buffer_description_change_hook", tab_bar_update_buffer_title);
71     remove_hook.call(this.window, "buffer_icon_change_hook", tab_bar_update_buffer_icon);
72     this.window.buffers.for_each(function (b) { delete b.tab; });
73     this.selected_buffer = null;
74     this.element.parentNode.removeChild(this.element);
75     delete this.window.tab_bar;
79 /**
80  * Updates the "index" node and "ordinal" attribute of all tabs.
81  */
82 tab_bar.prototype.update_ordinals = function () {
83     var buffers = this.window.buffers;
84     for (var i = 0, n = this.element.childNodes.length; i < n; i++) {
85         var ordinal = buffers.index_of(this.element.childNodes[i].buffer) + 1;
86         this.element.childNodes[i].setAttribute("ordinal", ordinal);
87         this.element.childNodes[i].index.setAttribute("value", ordinal);
88     }
92 /**
93  * Updates the "multiple" attribute of the tab bar.
94  */
95 tab_bar.prototype.update_multiple_attribute = function () {
96     if (this.window.buffers.count > 1)
97         this.element.setAttribute("multiple", "true");
98     else
99         this.element.setAttribute("multiple", "false");
104  * Adds a tab for the given buffer.  When second argument 'noupdate' is
105  * true, a new tab in the middle of the buffer list will not cause the
106  * ordinals of other tabs to be updated.  This is used during
107  * initialization of the tab bar.
108  */
109 function tab_bar_add_buffer (buffer, noupdate) {
111     // Get the tab bar
112     var tabbar = buffer.window.tab_bar;
113     tabbar.update_multiple_attribute();
115     var ordinal = buffer.window.buffers.index_of(buffer) + 1;
116     if (ordinal < buffer.window.buffers.buffer_list.length && ! noupdate)
117         tabbar.update_ordinals();
119     // Create a tab and add it to the tab bar
120     var tab = create_XUL(buffer.window, "hbox");
121     tab.buffer = buffer;
122     tab.setAttribute("class", "tab2");
123     tab.addEventListener("click", function (event) {
124             if (event.button == tab_bar_button_select) {
125                 if (!tab.buffer.dead)
126                     tab.buffer.window.buffers.current = tab.buffer;
127             }
128         }, false /* not capturing */);
129     tab.setAttribute("selected", "false");
131     // Create the label to hold the buffer icon
132     var image = create_XUL(buffer.window, "image");
133     image.setAttribute("class", "tab2-icon");
134     if (buffer.icon != null)
135         image.setAttribute("src", buffer.icon);
137     // Create the label to hold the tab number
138     var index = create_XUL(buffer.window, "label");
139     index.setAttribute("class", "tab2-index");
140     index.setAttribute("value", ordinal);
142     // Create the label to hold the tab title
143     var label = create_XUL(buffer.window, "label");
144     label.setAttribute("class", "tab2-label");
145     label.setAttribute("crop", "end");
147     // No close button, just use the designated mouse button.
148     tab.addEventListener("click", function (event) {
149             if (event.button == tab_bar_button_close) {
150                 kill_buffer(tab.buffer);
151                 event.stopPropagation();
152             }
153         }, false /* not capturing */);
155     // Add all the stuff to the new tab
156     tab.image = image;
157     tab.label = label;
158     tab.index = index;
159     if (tab_bar_show_index)
160         tab.appendChild(index);
161     if (tab_bar_show_icon)
162         tab.appendChild(image);
163     tab.appendChild(label);
164     tabbar.element.appendChild(tab);
165     buffer.tab = tab;
166     tab_bar_update_buffer_title(buffer);
168     // Note, XULRunner 1.9.x puts the tab in the wrong location if we set
169     // the ordinal before adding the tab to the tab-bar.
170     tab.setAttribute("ordinal", ordinal);
175  * Removes the tab for the given buffer.
176  */
177 function tab_bar_kill_buffer (b) {
178     var t = b.window.tab_bar;
179     t.update_multiple_attribute();
180     if (t.selected_buffer == b)
181         t.selected_buffer = null;
182     b.tab.parentNode.removeChild(b.tab);
183     t = b.window.tab_bar;
184     delete b.tab;
186     // Renumber the tabs.
187     t.update_ordinals();
192  * Updates all tab indices and ensure that the current tab is still visible.
193  */
194 function tab_bar_move_buffer (b) {
195     var t = b.window.tab_bar;
196     t.update_ordinals();
197     t.element.ensureElementIsVisible(b.window.buffers.current.tab);
202  * Updates the tab of the given buffer to indicate it is the currently open one.
203  */
204 function tab_bar_select_buffer (b) {
205     var t = b.window.tab_bar;
206     if (t.selected_buffer != null)
207         t.selected_buffer.tab.setAttribute("selected", "false");
208     t.selected_buffer = b;
209     b.tab.setAttribute("selected", "true");
210     t.element.ensureElementIsVisible(b.tab);
215  * Updates the tab title for the given buffer.
216  */
217 function tab_bar_update_buffer_title (b) {
218     var title = b.title;
219     if (title == null || title.length == 0)
220         title = b.description;
221     b.tab.label.setAttribute("value", title);
226  * Updates the tab icon for the given buffer.
227  */
228 function tab_bar_update_buffer_icon (b) {
229     if (b.icon != null)
230         b.tab.image.setAttribute("src", b.icon);
231     else
232         b.tab.image.removeAttribute("src");
237  * Inserts the tab bar in the given window.
238  */
239 function tab_bar_install (window) {
240     if (window.tab_bar)
241         throw new Error("tab bar already initialized for window");
242     new tab_bar(window);
247  * Removes the tab bar from the given window.
248  * If the tab bar is not installed, throws an error.
249  */
250 function tab_bar_uninstall (window) {
251     if (!window.tab_bar)
252         throw new Error("tab bar not initialized for window");
253     window.tab_bar.destroy();
257 define_global_mode("tab_bar_mode",
258                    function () { // enable
259                        add_hook("window_initialize_hook", tab_bar_install);
260                        for_each_window(tab_bar_install);
261                    },
262                    function () { // disable
263                        remove_hook("window_initialize_hook", tab_bar_install);
264                        for_each_window(tab_bar_uninstall);
265                    });
267 tab_bar_mode(true);
269 provide("tab-bar");
270 provide("new-tabs");