2 * Copyright (c) 2011 Marco Peereboom <marco@peereboom.us>
3 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #if WEBKIT_CHECK_VERSION(1, 5, 0)
21 /* we got the DOM API we need */
24 focus_body(WebKitDOMDocument
*doc
)
26 WebKitDOMNodeList
*body
= NULL
;
30 body
= webkit_dom_document_get_elements_by_tag_name(doc
, "body");
31 for (i
= 0; i
< webkit_dom_node_list_get_length(body
); ++i
) {
32 n
= webkit_dom_node_list_item(body
, i
);
33 webkit_dom_element_focus((WebKitDOMElement
*)n
);
34 #if WEBKIT_CHECK_VERSION(1, 8, 0)
35 webkit_dom_html_element_click((WebKitDOMHTMLElement
*)n
);
42 node_is_valid_entry(WebKitDOMNode
*n
)
47 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(n
) &&
48 webkit_dom_html_input_element_check_validity(
49 (WebKitDOMHTMLInputElement
*)n
))
51 if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(n
) &&
52 webkit_dom_html_text_area_element_check_validity(
53 (WebKitDOMHTMLTextAreaElement
*)n
))
60 focus_input_document(struct tab
*t
, WebKitDOMDocument
*doc
)
62 WebKitDOMNodeList
*input
= NULL
, *textarea
= NULL
;
65 int i
, rv
= 0 /* not found */;
67 WebKitDOMHTMLTextAreaElement
*ta
;
68 WebKitDOMHTMLInputElement
*in
;
70 /* we are deliberately ignoring tab index! */
73 input
= webkit_dom_document_get_elements_by_tag_name(doc
, "input");
74 for (i
= 0; i
< webkit_dom_node_list_get_length(input
); i
++) {
75 n
= webkit_dom_node_list_item(input
, i
);
76 in
= (WebKitDOMHTMLInputElement
*)n
;
77 g_object_get(G_OBJECT(in
), "type", &es
, (char *)NULL
);
78 if ((g_strcmp0("text", es
) && g_strcmp0("password",es
)) ||
79 webkit_dom_html_input_element_get_disabled(in
)) {
84 webkit_dom_element_focus((WebKitDOMElement
*)in
);
85 #if WEBKIT_CHECK_VERSION(1, 8, 0)
86 webkit_dom_html_element_click((WebKitDOMHTMLElement
*)in
);
93 /* now try textarea */
94 textarea
= webkit_dom_document_get_elements_by_tag_name(doc
, "textarea");
95 for (i
= 0; i
< webkit_dom_node_list_get_length(textarea
); i
++) {
96 n
= webkit_dom_node_list_item(textarea
, i
);
97 ta
= (WebKitDOMHTMLTextAreaElement
*)n
;
98 if (webkit_dom_html_text_area_element_get_disabled(ta
)) {
99 /* it is hidden so skip */
102 webkit_dom_element_focus((WebKitDOMElement
*)ta
);
103 #if WEBKIT_CHECK_VERSION(1, 8, 0)
104 webkit_dom_html_element_click((WebKitDOMHTMLElement
*)ta
);
111 g_object_unref(input
);
113 g_object_unref(textarea
);
119 get_element_text(WebKitDOMNode
*n
)
121 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(n
))
122 return (g_strdup(webkit_dom_html_input_element_get_value(
123 (WebKitDOMHTMLInputElement
*)n
)));
124 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(n
))
125 return (g_strdup(webkit_dom_html_text_area_element_get_value(
126 (WebKitDOMHTMLTextAreaElement
*)n
)));
131 focus_input(struct tab
*t
)
133 WebKitDOMDocument
*doc
;
135 WebKitDOMNodeList
*fl
= NULL
, *ifl
= NULL
;
137 int i
, fl_count
, ifl_count
, rv
= 0; /* not found */
139 WebKitDOMHTMLFrameElement
*frame
;
140 WebKitDOMHTMLIFrameElement
*iframe
;
143 * Here is what we are doing:
145 * If a textbox is already focused, leave it alone.
147 * Try the tab's previous active entry, for example if it was set by
148 * some javascript when the page loaded.
150 * See if we got frames or iframes
152 * if we do focus on input or textarea in frame or in iframe
154 * if we find nothing or there are no frames focus on first input or
158 doc
= webkit_web_view_get_dom_document(t
->wv
);
160 /* try current active element */
161 a
= webkit_dom_html_document_get_active_element(
162 (WebKitDOMHTMLDocument
*)doc
);
163 if (node_is_valid_entry((WebKitDOMNode
*)a
)) {
168 /* try previous active element */
169 if (node_is_valid_entry((WebKitDOMNode
*)t
->active
)) {
170 webkit_dom_element_focus((WebKitDOMElement
*)t
->active
);
171 #if WEBKIT_CHECK_VERSION(1, 8, 0)
172 webkit_dom_html_element_click((WebKitDOMHTMLElement
*)t
->active
);
178 g_object_unref(t
->active
);
180 if (t
->active_text
) {
181 g_free(t
->active_text
);
182 t
->active_text
= NULL
;
187 fl
= webkit_dom_document_get_elements_by_tag_name(doc
, "frame");
188 fl_count
= webkit_dom_node_list_get_length(fl
);
191 ifl
= webkit_dom_document_get_elements_by_tag_name(doc
, "iframe");
192 ifl_count
= webkit_dom_node_list_get_length(ifl
);
194 /* walk frames and look for a text input */
195 for (i
= 0; i
< fl_count
; i
++) {
196 n
= webkit_dom_node_list_item(fl
, i
);
197 frame
= (WebKitDOMHTMLFrameElement
*)n
;
198 doc
= webkit_dom_html_frame_element_get_content_document(frame
);
200 if (focus_input_document(t
, doc
)) {
206 /* walk iframes and look for a text input */
207 for (i
= 0; i
< ifl_count
; i
++) {
208 n
= webkit_dom_node_list_item(ifl
, i
);
209 iframe
= (WebKitDOMHTMLIFrameElement
*)n
;
210 doc
= webkit_dom_html_iframe_element_get_content_document(iframe
);
212 if (focus_input_document(t
, doc
)) {
218 /* if we made it here nothing got focused so use normal heuristic */
219 if (focus_input_document(t
, webkit_web_view_get_dom_document(t
->wv
)))
232 dom_is_input(struct tab
*t
, char **text
)
234 WebKitDOMDocument
*doc
;
236 WebKitDOMHTMLElement
*aa
;
237 WebKitDOMHTMLObjectElement
*object
;
239 WebKitDOMHTMLFrameElement
*frame
;
240 WebKitDOMHTMLIFrameElement
*iframe
;
242 /* proof positive that OO is stupid */
244 doc
= webkit_web_view_get_dom_document(t
->wv
);
246 /* unwind frames and iframes until the cows come home */
248 a
= webkit_dom_html_document_get_active_element(
249 (WebKitDOMHTMLDocument
*)doc
);
253 frame
= (WebKitDOMHTMLFrameElement
*)a
;
254 if (WEBKIT_DOM_IS_HTML_FRAME_ELEMENT(frame
)) {
255 doc
= webkit_dom_html_frame_element_get_content_document(
260 iframe
= (WebKitDOMHTMLIFrameElement
*)a
;
261 if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT(iframe
)) {
262 doc
= webkit_dom_html_iframe_element_get_content_document(
267 object
= (WebKitDOMHTMLObjectElement
*)a
;
268 if (WEBKIT_DOM_IS_HTML_OBJECT_ELEMENT(object
)) {
269 doc
= webkit_dom_html_object_element_get_content_document(
275 * I think this is a total hack because this property isn't
276 * set for textareas or input however, it is set for jquery
277 * textareas that do rich text. Since this works around issues
278 * in RT we'll simply keep it!
280 * This might break some other stuff but for now it helps.
282 aa
= (WebKitDOMHTMLElement
*)a
;
283 if (WEBKIT_DOM_IS_HTML_ELEMENT(aa
) &&
284 webkit_dom_html_element_get_is_content_editable(aa
)) {
285 if (t
->active
== NULL
) {
287 g_object_ref(t
->active
);
289 *text
= get_element_text((WebKitDOMNode
*)a
);
290 if (t
->active_text
== NULL
)
291 t
->active_text
= g_strdup(*text
);
300 if (node_is_valid_entry((WebKitDOMNode
*)a
)) {
301 if (!node_is_valid_entry((WebKitDOMNode
*)t
->active
)) {
303 g_object_unref(t
->active
);
305 if (t
->active_text
) {
306 g_free(t
->active_text
);
307 t
->active_text
= NULL
;
310 if (t
->active
== NULL
) {
312 g_object_ref(t
->active
);
314 *text
= get_element_text((WebKitDOMNode
*)a
);
315 if (t
->active_text
== NULL
)
316 t
->active_text
= g_strdup(*text
);
324 input_check_mode(struct tab
*t
)
328 if (dom_is_input(t
, &text
)) {
329 t
->mode
= XT_MODE_INSERT
;
336 command_mode(struct tab
*t
, struct karg
*args
)
338 WebKitDOMDocument
*doc
;
341 if (args
->i
== XT_MODE_COMMAND
) {
342 doc
= webkit_web_view_get_dom_document(t
->wv
);
343 a
= webkit_dom_html_document_get_active_element(
344 (WebKitDOMHTMLDocument
*)doc
);
346 webkit_dom_element_blur(a
);
349 t
->mode
= XT_MODE_COMMAND
;
350 } else if (args
->i
== XT_MODE_INSERT
&& focus_input(t
))
351 t
->mode
= XT_MODE_INSERT
;
352 else if (args
->i
== XT_MODE_HINT
|| args
->i
== XT_MODE_PASSTHROUGH
)
355 if (!node_is_valid_entry((WebKitDOMNode
*)t
->active
)) {
357 g_object_unref(t
->active
);
359 if (t
->active_text
) {
360 g_free(t
->active_text
);
361 t
->active_text
= NULL
;
365 return (XT_CB_HANDLED
);
369 input_autofocus(struct tab
*t
)
371 struct karg args
= {0};
374 if (autofocus_onload
&&
375 t
->tab_id
== gtk_notebook_get_current_page(notebook
)) {
377 t
->mode
= XT_MODE_INSERT
;
379 t
->mode
= XT_MODE_COMMAND
;
381 if (dom_is_input(t
, &text
)) {
382 if (text
!= NULL
&& g_strcmp0(text
, t
->active_text
))
383 args
.i
= XT_MODE_INSERT
;
385 args
.i
= XT_MODE_COMMAND
;
387 args
.i
= XT_MODE_COMMAND
;
388 command_mode(t
, &args
);
394 #else /* WEBKIT_CHECK_VERSION */
395 /* incomplete DOM API */
399 * note that we can't check the return value of run_script so we
400 * have to assume that the command worked; this may leave you in
401 * insertmode when in fact you shouldn't be
404 input_autofocus(struct tab
*t
)
406 if (autofocus_onload
&&
407 t
->tab_id
== gtk_notebook_get_current_page(notebook
)) {
408 run_script(t
, "hints.focusInput();");
409 t
->mode
= XT_MODE_INSERT
;
411 run_script(t
, "hints.clearFocus();");
412 t
->mode
= XT_MODE_COMMAND
;
417 input_check_mode(struct tab
*t
)
423 command_mode(struct tab
*t
, struct karg
*args
)
425 if (args
->i
== XT_MODE_COMMAND
) {
426 run_script(t
, "hints.clearFocus();");
427 t
->mode
= XT_MODE_COMMAND
;
429 run_script(t
, "hints.focusInput();");
430 t
->mode
= XT_MODE_INSERT
;
433 return (XT_CB_HANDLED
);