youtube: update scraper for youtube.com change
[conkeror.git] / modules / mode-line.js
blob74c268af3169a75f4d1e7b8db2d0f09cee6f5ab6
1 /**
2  * (C) Copyright 2005 Shawn Betts
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 in_module(null);
11 require("mode.js");
13 define_window_local_hook("mode_line_hook");
15 define_keywords("$flex", "$align", "$class", "$crop");
16 function generic_element_widget_container (window, container) {
17     this.window = window;
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");
30         if (flex)
31             element.setAttribute("flex", flex);
32         if (align)
33             element.setAttribute("align", align);
34         if (class_name)
35             element.setAttribute("class", class_name);
36         if (crop)
37             element.setAttribute("crop", crop);
38         return this.add_widget(widget, element);
39     },
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;
44     },
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();
49     }
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);
69     }
73 function generic_widget_element (element, widget) {
74     this.element = element;
75     this.widget = widget;
76     widget.attach(this);
78 generic_widget_element.prototype = {
79     constructor: generic_widget_element,
80     get text () {
81         return this.element.getAttribute("value");
82     },
84     set text (v) {
85         this.element.setAttribute("value", v);
86     },
88     destroy: function () {
89         this.widget.destroy();
90     },
92     remove: function () {
93         this.element.parentNode.removeChild(this.element);
94         this.destroy();
95     }
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) {
106         var obj = this;
107         if (handler == null)
108             handler = function () { obj.update(); };
109         add_hook.call(this.window, hook_name, handler);
110         this.window_hooks.push([hook_name, handler]);
111     },
113     view: null,
115     attach: function (view) {
116         this.view = view;
117         this.update();
118     },
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]);
125         }
126     },
128     remove: function () {
129         this.view.remove();
130     }
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);
139     this.flex = "1";
140     this.crop = "end";
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;
163     scrollX = w.scrollX;
164     scrollY = w.scrollY;
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 + ")";
173 define_variable("clock_time_format", "%R",
174     "Format string for the mode-line clock widget.\n"+
175     "It takes the same format as strftime() in C. "+
176     "See http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html "+
177     "for details.");
179 function clock_widget (window) {
180     this.class_name = "clock-widget";
181     text_widget.call(this, window);
182     var obj = this;
183     this.do_update = function () { obj.update(); };
184     // todo: use one timer for multiple clock widgets
185     this.timer_ID = window.setTimeout(this.do_update, 0);
186     this.timer_timeout = true;
188 clock_widget.prototype.__proto__ = text_widget.prototype;
189 clock_widget.prototype.update = function () {
190     var time = new Date();
191     this.view.text = time.toLocaleFormat(clock_time_format);
192     if (time.getSeconds() > 0 || time.getMilliseconds() > 100) {
193         this.window.clearTimeout(this.timer_ID);
194         var time = time.getSeconds() * 1000 + time.getMilliseconds();
195         time = 60000 - time;
196         this.timer_ID = this.window.setTimeout(this.do_update, time);
197         this.timer_timeout = true;
198     } else if (this.timer_timeout) {
199         this.window.clearTimeout(this.timer_ID);
200         this.timer_ID = this.window.setInterval(this.do_update, 60000);
201         this.timer_timeout = false;
202     }
204 clock_widget.prototype.destroy = function () {
205     this.window.clearTimeout(this.timer_ID);
208 function buffer_count_widget (window) {
209     this.class_name = "buffer-count-widget";
210     text_widget.call(this, window);
211     this.add_hook("select_buffer_hook");
212     this.add_hook("create_buffer_hook");
213     this.add_hook("kill_buffer_hook");
215 buffer_count_widget.prototype.__proto__ = text_widget.prototype;
216 buffer_count_widget.prototype.update = function () {
217     this.view.text = ("[" + (this.window.buffers.selected_index+1) + "/" +
218                       this.window.buffers.count + "]");
221 function loading_count_widget (window) {
222     this.class_name = "loading-count-widget";
223     text_widget.call(this, window);
224     var obj = this;
225     this.add_hook("content_buffer_started_loading_hook");
226     this.add_hook("content_buffer_finished_loading_hook");
227     this.add_hook("kill_buffer_hook");
229 loading_count_widget.prototype.__proto__ = text_widget.prototype;
230 loading_count_widget.prototype.update = function () {
231     var count = 0;
232     for_each_buffer(function (b) { if (b.loading) count++; });
233     if (count)
234         this.view.text = "(" + count + " loading)";
235     else
236         this.view.text = "";
239 function mode_line_adder (widget_constructor) {
240     if (!('mode_line_adder' in widget_constructor))
241         widget_constructor.mode_line_adder = function (window) {
242             window.mode_line.add_text_widget(new widget_constructor(window));
243         };
244     return widget_constructor.mode_line_adder;
247 add_hook("mode_line_hook", mode_line_adder(current_buffer_name_widget));
248 add_hook("mode_line_hook", mode_line_adder(clock_widget));
249 add_hook("mode_line_hook", mode_line_adder(current_buffer_scroll_position_widget));
251 mode_line_mode(true);
253 provide("mode-line");