Status: | Work in progress | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~midori/midori/webkitdom | ||||
Merge into: | lp:midori | ||||
Diff against target: |
312 lines (+208/-23) 4 files modified
midori/midori-tab.vala (+182/-1) midori/midori-view.c (+0/-22) midori/webkitgtk-3.0.vapi (+1/-0) tests/tab.vala (+25/-0) |
||||
To merge this branch: | bzr merge lp:~midori/midori/webkitdom | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Midori Devs | Pending | ||
Review via email: mp+174887@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 6171. By Cris Dywan
-
Port link hints to DOM code in Midori.Tab
- 6170. By Cris Dywan
-
Rework inline find with custom CSS styling
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'midori/midori-tab.vala' |
2 | --- midori/midori-tab.vala 2013-06-21 23:23:12 +0000 |
3 | +++ midori/midori-tab.vala 2013-07-15 22:57:23 +0000 |
4 | @@ -35,6 +35,11 @@ |
5 | |
6 | public class Tab : Gtk.VBox { |
7 | public WebKit.WebView web_view { get; private set; } |
8 | + int find_links; |
9 | + private string css_class_match; |
10 | + private string css_class_found; |
11 | + private string css_class_hint; |
12 | + private string css_class_key; |
13 | |
14 | #if HAVE_GRANITE_CLUTTER |
15 | public Granite.Widgets.NavigationBox navigation_box { get; private set; } |
16 | @@ -105,6 +110,11 @@ |
17 | web_view = new WebKit.WebView (); |
18 | /* Load something to avoid a bug where WebKit might not set a main frame */ |
19 | web_view.load_uri (""); |
20 | + css_class_match = "midori" + Checksum.compute_for_string (ChecksumType.MD5, "search-match"); |
21 | + css_class_found = "midori" + Checksum.compute_for_string (ChecksumType.MD5, "search-found"); |
22 | + css_class_hint = "midori" + Checksum.compute_for_string (ChecksumType.MD5, "search-hint"); |
23 | + css_class_key = "midori" + Checksum.compute_for_string (ChecksumType.MD5, "search-key"); |
24 | + setup_styles (); |
25 | } |
26 | |
27 | public void inject_stylesheet (string stylesheet) { |
28 | @@ -222,9 +232,115 @@ |
29 | |
30 | public void unmark_text_matches () { |
31 | #if !HAVE_WEBKIT2 |
32 | +#if HAVE_DOM |
33 | + var dom = web_view.get_dom_document (); |
34 | + var nodes = dom.get_elements_by_class_name (css_class_match); |
35 | + for (ulong i = 0; i < nodes.length; i++) { |
36 | + var node = nodes.item (i); |
37 | + var parent = node.parent_node; |
38 | + string inner_html; |
39 | + parent.get ("inner-html", out inner_html); |
40 | + var text_node = dom.create_text_node (node.text_content); |
41 | + parent.replace_child (text_node, node); |
42 | + parent.normalize (); |
43 | + string after; |
44 | + parent.get ("inner-html", out after); |
45 | + stdout.printf ("unmark before: %s\nafter: %s\n", inner_html, after); |
46 | + } |
47 | + |
48 | + /* FIXME There shouldn't be any remnants left */ |
49 | + nodes = dom.get_elements_by_class_name (css_class_match); |
50 | + if (nodes.length != 0) { |
51 | + for (ulong i = 0; i < nodes.length; i++) { |
52 | + var node = nodes.item (i); |
53 | + string remnant; |
54 | + node.get ("inner-html", out remnant); |
55 | + stdout.printf ("! %s\n", remnant); |
56 | + node.parent_node.remove_child (node); |
57 | + } |
58 | + } |
59 | +#else |
60 | web_view.unmark_text_matches (); |
61 | #endif |
62 | - } |
63 | +#endif |
64 | + } |
65 | + |
66 | +#if !HAVE_WEBKIT2 |
67 | +#if HAVE_DOM |
68 | + void setup_styles () { |
69 | + string css_style = """ |
70 | + .%s, .%s { |
71 | + padding: 0.1em !important; |
72 | + border: 1px solid transparent !important; |
73 | + border-radius: 0.3em !important; |
74 | + z-index: 555 !important; |
75 | + position: absolute !important; |
76 | + display: inline !important; |
77 | + color: #000 !important; |
78 | + background-color: #FCE94F !important; |
79 | + border-top-color: ##E8D539 !important; |
80 | + border-left-color: ##E8D539 !important; |
81 | + border-bottom-color: #F5E988 !important; |
82 | + border-right-color: #F5E988 !important; |
83 | + } |
84 | + .%s { |
85 | + background-color: #d1eeb9 !important; |
86 | + border-top-color: #C8D6BC !important; |
87 | + border-left-color: #C8D6BC !important; |
88 | + border-bottom-color: #93C967 !important; |
89 | + border-right-color: #93C967 !important; |
90 | + } |
91 | + """.printf (css_class_match, css_class_found, css_class_match); |
92 | + /* FIXME: style ::selection OR Source/WebCore/editing/Editor.cpp findString */ |
93 | + inject_stylesheet (css_style); |
94 | + } |
95 | + |
96 | + public override virtual signal bool navigation_policy_decision_requested ( |
97 | + WebKit.WebFrame frame, WebKit.NetworkRequest request, |
98 | + WebKit.WebNavigationAction action, WebKit.WebPolicyDecision decision) { |
99 | + |
100 | + setup_styles (); |
101 | + return false; |
102 | + } |
103 | + |
104 | + void handle_link_hints (Gdk.EventKey event) { |
105 | + int digit = ((char)event.keyval).digit_value (); |
106 | + unichar uc = Gdk.keyval_to_unicode (event.keyval); |
107 | + string? result = null; |
108 | + if (find_links < 0) { |
109 | + /* Links are currently off, turn them on */ |
110 | + string css_style = """ |
111 | + .%s, .%s { |
112 | + font-size:small !important; |
113 | + font-weight:bold !important; |
114 | + z-index: 777; |
115 | + border-radius:0.3em; |
116 | + line-height:1 !important; |
117 | + background: white !important; |
118 | + color: black !important; |
119 | + border: 1px solid gray; |
120 | + padding: 0 0.1em !important; |
121 | + position: absolute; |
122 | + display: inline !important; |
123 | + } |
124 | + .%s { |
125 | + padding: 0 0.1em 0.2em 0.1em !important; |
126 | + background: black !important; |
127 | + color: white !important; |
128 | + } |
129 | + """.printf (css_class_hint, css_class_key, css_class_key); |
130 | + inject_stylesheet (css_style); |
131 | + int label_count = 0; |
132 | + var dom = web_view.get_dom_document (); |
133 | + var links = dom.links; |
134 | + ulong nodes_length = links.length; |
135 | + for (ulong i = 0; i < nodes_length; i++) { |
136 | + var node = links.item (i); |
137 | + var element = node.parent_element; |
138 | + } |
139 | + } |
140 | +#endif |
141 | +#endif |
142 | |
143 | public bool find (string text, bool case_sensitive, bool forward) { |
144 | #if HAVE_WEBKIT2 |
145 | @@ -238,12 +354,77 @@ |
146 | // FIXME: mark matches, count matches, not found |
147 | return true; |
148 | #else |
149 | +#if HAVE_DOM |
150 | + uint matches = 0; |
151 | + unmark_text_matches (); |
152 | + setup_styles (); |
153 | + |
154 | + var dom = web_view.get_dom_document (); |
155 | + var nodes = dom.body.query_selector_all ("div,span,b,i,u,em,strong,p,input,button,h1,h2,h3,h4,h5,h6"); |
156 | + var regex = new Regex ("(" + text + ")", case_sensitive ? 0 : RegexCompileFlags.CASELESS); |
157 | + ulong nodes_length = nodes.length; |
158 | + for (ulong i = 0; i < nodes_length; i++) { |
159 | + var node = nodes.item (i); |
160 | + ulong children_length = node.child_nodes.length; |
161 | + for (ulong j = 0; j < children_length; j++) { |
162 | + var child = node.child_nodes.item (j); |
163 | + if (child.node_type != 3) /* text node */ |
164 | + continue; |
165 | + |
166 | + /* Use text content to not match markup or scripts */ |
167 | + string content = child.text_content; |
168 | + /* FIXME forward */ |
169 | + bool match = regex.match (content); |
170 | + if (match) { |
171 | + matches++; |
172 | + |
173 | + string inner_html; |
174 | + node.get ("inner-html", out inner_html); |
175 | + string new_html = regex.replace (inner_html, -1, 0, |
176 | + "<span class=\"%s\">\\1</span>".printf (css_class_match)); |
177 | + node.set ("inner-html", new_html); |
178 | + |
179 | + /* FIXME position |
180 | + var bubble = dom.create_element ("span"); |
181 | + bubble.set_attribute ("class", css_class_match); |
182 | + bubble.append_child (dom.create_text_node (text)); |
183 | + node.parent_node.insert_before (bubble, node); */ |
184 | + |
185 | + /* cf. |
186 | + var skip = 0; |
187 | + if (node.nodeType == 3) { |
188 | + var pos = node.data.toUpperCase().indexOf(pat); |
189 | + if (pos >= 0) { |
190 | + var spannode = document.createElement("span"); |
191 | + spannode.className = "highlight"; |
192 | + fbgcolor += ";padding: 0px; margin: 0px;"; |
193 | + spannode.setAttribute("style", fbgcolor); |
194 | + var middlebit = node.splitText(pos); |
195 | + var endbit = middlebit.splitText(pat.length); |
196 | + var middleclone = middlebit.cloneNode(true); |
197 | + spannode.appendChild(middleclone); |
198 | + middlebit.parentNode.replaceChild(spannode, middlebit); |
199 | + skip = 1; |
200 | + } |
201 | + } |
202 | + else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { |
203 | + for (var i = 0; i < node.childNodes.length; ++i) |
204 | + i += innerHighlight(node.childNodes[i], pat, fbgcolor); |
205 | + } |
206 | + return skip; |
207 | + */ |
208 | + } |
209 | + } |
210 | + } |
211 | + return matches > 0; |
212 | +#else |
213 | bool found = false; |
214 | found = web_view.search_text (text, case_sensitive, forward, true); |
215 | web_view.mark_text_matches (text, case_sensitive, 0); |
216 | web_view.set_highlight_text_matches (true); |
217 | return found; |
218 | #endif |
219 | +#endif |
220 | } |
221 | } |
222 | } |
223 | |
224 | === modified file 'midori/midori-view.c' |
225 | --- midori/midori-view.c 2013-07-15 17:07:45 +0000 |
226 | +++ midori/midori-view.c 2013-07-15 22:57:23 +0000 |
227 | @@ -1756,30 +1756,8 @@ |
228 | MidoriView* view) |
229 | { |
230 | #ifndef HAVE_WEBKIT2 |
231 | - gint digit = g_ascii_digit_value (event->keyval); |
232 | - gunichar uc = gdk_keyval_to_unicode (event->keyval); |
233 | - gchar* result = NULL; |
234 | - WebKitWebFrame* web_frame = webkit_web_view_get_main_frame (web_view); |
235 | - JSContextRef js_context = webkit_web_frame_get_global_context (web_frame); |
236 | - |
237 | - if (view->find_links < 0) |
238 | { |
239 | - /* Links are currently off, turn them on */ |
240 | - midori_tab_inject_stylesheet (MIDORI_TAB (view), ".midoriHKD87346 {" |
241 | - " font-size:small !important; font-weight:bold !important;" |
242 | - " z-index:500; border-radius:0.3em; line-height:1 !important;" |
243 | - " background: white !important; color: black !important;" |
244 | - " border:1px solid gray; padding:0 0.1em !important;" |
245 | - " position:absolute; display:inline !important; }"); |
246 | - midori_tab_inject_stylesheet (MIDORI_TAB (view), ".midori_access_key_fc04de {" |
247 | - " font-size:small !important; font-weight:bold !important;" |
248 | - " z-index:500; border-radius:0.3em; line-height:1 !important;" |
249 | - " background: black !important; color: white !important;" |
250 | - " border:1px solid gray; padding:0 0.1em 0.2em 0.1em !important;" |
251 | - " position:absolute; display:inline !important; }"); |
252 | result = sokoke_js_script_eval (js_context, |
253 | - " var label_count = 0;" |
254 | - " for (i in document.links) {" |
255 | " if (document.links[i].href && document.links[i].insertBefore) {" |
256 | " var child = document.createElement ('span');" |
257 | " if (document.links[i].accessKey && isNaN (document.links[i].accessKey)) {" |
258 | |
259 | === modified file 'midori/webkitgtk-3.0.vapi' |
260 | --- midori/webkitgtk-3.0.vapi 2012-12-16 18:40:10 +0000 |
261 | +++ midori/webkitgtk-3.0.vapi 2013-07-15 22:57:23 +0000 |
262 | @@ -158,6 +158,7 @@ |
263 | public WebKit.DOMNode first_child { get; } |
264 | public WebKit.DOMNode last_child { get; } |
265 | public WebKit.DOMNode next_sibling { get; } |
266 | + public uint node_type { get; } |
267 | public WebKit.DOMElement parent_element { get; } |
268 | public WebKit.DOMNode parent_node { get; } |
269 | public WebKit.DOMNode previous_sibling { get; } |
270 | |
271 | === modified file 'tests/tab.vala' |
272 | --- tests/tab.vala 2013-04-04 21:23:44 +0000 |
273 | +++ tests/tab.vala 2013-07-15 22:57:23 +0000 |
274 | @@ -266,6 +266,30 @@ |
275 | assert (!did_request_download); |
276 | } |
277 | |
278 | +void tab_find () { |
279 | + var browser = new Gtk.Window (Gtk.WindowType.TOPLEVEL); |
280 | + var tab = new Midori.View.with_title (); |
281 | + browser.add (tab); |
282 | + var loop = MainContext.default (); |
283 | + tab.set_uri ("http://.invalid"); |
284 | + do { loop.iteration (true); } while (tab.load_status != Midori.LoadStatus.FINISHED); |
285 | + /* One button in the error page */ |
286 | + assert (tab.find (_("Try again"), true, true) == 1); |
287 | +#if HAVE_DOM |
288 | + /* The hostname occurs thrice */ |
289 | + assert (tab.find (".invalid", true, true) == 3); |
290 | + /* Regex */ |
291 | + assert (tab.find ("(in)?valid", true, true) == 3); |
292 | +#endif |
293 | + /* Wrong case, shouldn't yield any matches */ |
294 | + assert (tab.find ("http://.INValid", true, true) == 0); |
295 | + /* Not case sensitive */ |
296 | + assert (tab.find ("http://.INValid", false, true) > 0); |
297 | + /* Lots of matches shouldn't pose a problem */ |
298 | + assert (tab.find ("i", false, true) > 0); |
299 | + assert (tab.find ("n", false, true) > 0); //TODO: Berliner Weisse → Berliner Weiße |
300 | +} |
301 | + |
302 | void main (string[] args) { |
303 | Test.init (ref args); |
304 | Midori.App.setup (ref args, null); |
305 | @@ -277,6 +301,7 @@ |
306 | Test.add_func ("/tab/display-title", tab_display_title); |
307 | Test.add_func ("/tab/ellipsize", tab_display_ellipsize); |
308 | Test.add_func ("/tab/special", tab_special); |
309 | + Test.add_func ("/tab/find", tab_find); |
310 | Test.add_func ("/tab/alias", tab_alias); |
311 | Test.add_func ("/tab/http", tab_http); |
312 | Test.add_func ("/tab/movement", tab_movement); |