2 * (C) Copyright 2005 Shawn Betts
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5 * Use, modification, and distribution are subject to the terms specified in the
13 define_window_local_hook("mode_line_hook");
15 define_keywords("$flex", "$align", "$class", "$crop");
16 function generic_element_widget_container (window, container) {
18 this.container = container;
20 generic_element_widget_container.prototype = {
21 constructor: generic_element_widget_container,
22 add_text_widget: function (widget) {
23 keywords(arguments, $flex = widget.flex,
24 $class = widget.class_name, $crop = widget.crop);
25 var flex = arguments.$flex;
26 var class_name = arguments.$class;
27 var align = arguments.$align;
28 var crop = arguments.$crop;
29 var element = create_XUL(this.window, "label");
31 element.setAttribute("flex", flex);
33 element.setAttribute("align", align);
35 element.setAttribute("class", class_name);
37 element.setAttribute("crop", crop);
38 return this.add_widget(widget, element);
40 add_widget: function (widget, element) {
41 element.conkeror_widget = new generic_widget_element(element, widget);
42 this.container.appendChild(element);
43 return element.conkeror_widget;
45 destroy: function () {
46 var children = this.container.childNodes;
47 for (var i = 0, nchildren = children.length; i < nchildren; ++i)
48 children.item(i).conkeror_widget.destroy();
52 function mode_line (window) {
53 var element = create_XUL(window, "hbox");
54 element.setAttribute("class", "mode-line");
55 /* FIXME: this will need to changed to be buffer-local */
56 var insert_before = window.document.getElementById("minibuffer");
57 insert_before.parentNode.insertBefore(element, insert_before);
58 window.mode_line = this;
59 generic_element_widget_container.call(this, window, element);
60 mode_line_hook.run(window, this);
62 mode_line.prototype = {
63 constructor: mode_line,
64 __proto__: generic_element_widget_container.prototype,
66 uninstall: function () {
67 this.container.parentNode.removeChild(this.window.mode_line.container);
68 generic_element_widget_container.prototype.destroy.call(this);
73 function generic_widget_element (element, widget) {
74 this.element = element;
78 generic_widget_element.prototype = {
79 constructor: generic_widget_element,
81 return this.element.getAttribute("value");
85 this.element.setAttribute("value", v);
88 destroy: function () {
89 this.widget.destroy();
93 this.element.parentNode.removeChild(this.element);
99 function text_widget (window) {
100 this.window_hooks = [];
101 this.window = window;
103 text_widget.prototype = {
104 constructor: text_widget,
105 add_hook: function (hook_name, handler) {
108 handler = function () { obj.update(); };
109 add_hook.call(this.window, hook_name, handler);
110 this.window_hooks.push([hook_name, handler]);
115 attach: function (view) {
120 update: function () {},
122 destroy: function () {
123 for each (let i in this.window_hooks) {
124 remove_hook.call(this.window, i[0], i[1]);
128 remove: function () {
134 define_global_window_mode("mode_line", "window_initialize_early_hook");
136 function current_buffer_name_widget (window) {
137 this.class_name = "current-buffer-name-widget";
138 text_widget.call(this, window);
141 this.add_hook("current_content_buffer_location_change_hook");
142 this.add_hook("select_buffer_hook");
144 current_buffer_name_widget.prototype.__proto__ = text_widget.prototype;
145 current_buffer_name_widget.prototype.update = function () {
146 this.view.text = this.window.buffers.current.description;
149 function current_buffer_scroll_position_widget (window) {
150 this.class_name = "current-buffer-scroll-position-widget";
151 text_widget.call(this, window);
152 this.add_hook("current_buffer_scroll_hook");
153 this.add_hook("select_buffer_hook");
154 this.add_hook("current_content_buffer_location_change_hook");
155 this.add_hook("current_content_buffer_focus_change_hook");
156 this.add_hook("current_special_buffer_generated_hook");
158 current_buffer_scroll_position_widget.prototype.__proto__ = text_widget.prototype;
159 current_buffer_scroll_position_widget.prototype.update = function () {
160 var b = this.window.buffers.current;
161 var scrollX, scrollY, scrollMaxX, scrollMaxY;
162 var w = b.focused_frame;
165 scrollMaxX = w.scrollMaxX;
166 scrollMaxY = w.scrollMaxY;
167 var x = scrollMaxX == 0 ? 100 : Math.round(scrollX / scrollMaxX * 100);
168 var y = scrollMaxY == 0 ? 100 : Math.round(scrollY / scrollMaxY * 100);
169 this.view.text = "(" + x + ", " + y + ")";
172 function clock_widget (window) {
173 this.class_name = "clock-widget";
174 text_widget.call(this, window);
176 this.do_update = function () { obj.update(); };
177 // todo: use one timer for multiple clock widgets
178 this.timer_ID = window.setTimeout(this.do_update, 0);
179 this.timer_timeout = true;
181 clock_widget.prototype.__proto__ = text_widget.prototype;
182 clock_widget.prototype.update = function () {
183 var time = new Date();
184 var hours = time.getHours();
185 var mins = time.getMinutes();
186 this.view.text = (hours<10 ? "0" + hours:hours) + ":" + (mins<10 ?"0" +mins:mins);
187 if (time.getSeconds() > 0 || time.getMilliseconds() > 100) {
188 this.window.clearTimeout(this.timer_ID);
189 var time = time.getSeconds() * 1000 + time.getMilliseconds();
191 this.timer_ID = this.window.setTimeout(this.do_update, time);
192 this.timer_timeout = true;
193 } else if (this.timer_timeout) {
194 this.window.clearTimeout(this.timer_ID);
195 this.timer_ID = this.window.setInterval(this.do_update, 60000);
196 this.timer_timeout = false;
199 clock_widget.prototype.destroy = function () {
200 this.window.clearTimeout(this.timer_ID);
203 function buffer_count_widget (window) {
204 this.class_name = "buffer-count-widget";
205 text_widget.call(this, window);
206 this.add_hook("select_buffer_hook");
207 this.add_hook("create_buffer_hook");
208 this.add_hook("kill_buffer_hook");
210 buffer_count_widget.prototype.__proto__ = text_widget.prototype;
211 buffer_count_widget.prototype.update = function () {
212 this.view.text = ("[" + (this.window.buffers.selected_index+1) + "/" +
213 this.window.buffers.count + "]");
216 function loading_count_widget (window) {
217 this.class_name = "loading-count-widget";
218 text_widget.call(this, window);
220 this.add_hook("content_buffer_started_loading_hook");
221 this.add_hook("content_buffer_finished_loading_hook");
222 this.add_hook("kill_buffer_hook");
224 loading_count_widget.prototype.__proto__ = text_widget.prototype;
225 loading_count_widget.prototype.update = function () {
227 for_each_buffer(function (b) { if (b.loading) count++; });
229 this.view.text = "(" + count + " loading)";
234 function mode_line_adder (widget_constructor) {
235 if (!('mode_line_adder' in widget_constructor))
236 widget_constructor.mode_line_adder = function (window) {
237 window.mode_line.add_text_widget(new widget_constructor(window));
239 return widget_constructor.mode_line_adder;
242 add_hook("mode_line_hook", mode_line_adder(current_buffer_name_widget));
243 add_hook("mode_line_hook", mode_line_adder(clock_widget));
244 add_hook("mode_line_hook", mode_line_adder(current_buffer_scroll_position_widget));
246 mode_line_mode(true);
248 provide("mode-line");