Project

General

Profile

Download (7.05 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / html / display-panel.js @ c483ae19

1
/**
2
 * Hachette display panel logic
3
 *
4
 * Copyright (C) 2021 Wojtek Kosior
5
 * Redistribution terms are gathered in the `copyright' file.
6
 */
7

    
8
/*
9
 * IMPORTS_START
10
 * IMPORT browser
11
 * IMPORT is_chrome
12
 * IMPORT is_mozilla
13
 * IMPORT CONNECTION_TYPE
14
 * IMPORT url_item
15
 * IMPORT is_privileged_url
16
 * IMPORT TYPE_PREFIX
17
 * IMPORT nice_name
18
 * IMPORT open_in_settings
19
 * IMPORT for_each_possible_pattern
20
 * IMPORTS_END
21
 */
22

    
23
function by_id(id)
24
{
25
    return document.getElementById(id);
26
}
27

    
28
const tab_query = {currentWindow: true, active: true};
29

    
30
async function get_current_tab()
31
{
32
    /* Fix for fact that Chrome does not use promises here */
33
    const promise = is_chrome ?
34
	  new Promise((resolve, reject) =>
35
		      browser.tabs.query(tab_query, tab => resolve(tab))) :
36
	  browser.tabs.query(tab_query);
37

    
38
    try {
39
	return (await promise)[0];
40
    } catch(e) {
41
	console.log(e);
42
    }
43
}
44

    
45
const page_url_heading = by_id("page_url_heading");
46
const show_privileged_notice_chbx = by_id("show_privileged_notice_chbx");
47
const show_page_state_chbx = by_id("show_page_state_chbx");
48

    
49
async function show_page_activity_info()
50
{
51
    const tab = await get_current_tab();
52

    
53
    if (tab === undefined) {
54
	page_url_heading.textContent = "unknown page";
55
	return;
56
    }
57

    
58
    const url = url_item(tab.url);
59
    page_url_heading.textContent = url;
60
    if (is_privileged_url(url)) {
61
	show_privileged_notice_chbx.checked = true;
62
	return;
63
    }
64

    
65
    populate_possible_patterns_list(url);
66
    show_page_state_chbx.checked = true;
67

    
68
    try_to_connect(tab.id);
69
}
70

    
71
function populate_possible_patterns_list(url)
72
{
73
    for_each_possible_pattern(url, add_pattern_to_list);
74

    
75
    const port = browser.runtime.connect({name: CONNECTION_TYPE.PAGE_INFO});
76
    port.onMessage.addListener(handle_page_info);
77
    port.postMessage(["subscribe", url]);
78
}
79

    
80
const possible_patterns_ul = by_id("possible_patterns");
81
const pattern_li_template = by_id("pattern_li_template");
82
pattern_li_template.removeAttribute("id");
83
const known_patterns = new Map();
84

    
85
function add_pattern_to_list(pattern)
86
{
87
    const li = pattern_li_template.cloneNode(true);
88
    li.id = `pattern_li_${known_patterns.size}`;
89
    known_patterns.set(pattern, li.id);
90

    
91
    const span = li.firstElementChild;
92
    span.textContent = pattern;
93

    
94
    const button = span.nextElementSibling;
95
    const settings_opener = () => open_in_settings(TYPE_PREFIX.PAGE, pattern);
96
    button.addEventListener("click", settings_opener);
97

    
98
    possible_patterns_ul.appendChild(li)
99

    
100
    return li.id;
101
}
102

    
103
function ensure_pattern_exists(pattern)
104
{
105
    let id = known_patterns.get(pattern);
106
    /*
107
     * As long as pattern computation works well, we should never get into this
108
     * conditional block. This is just a safety measure. To be removed as part
109
     * of a bigger rework when we start taking iframes into account.
110
     */
111
    if (id === undefined) {
112
	console.log(`unknown pattern: ${pattern}`);
113
	id = add_pattern_to_list(pattern);
114
    }
115

    
116
    return id;
117
}
118

    
119
function set_pattern_li_button_text(li_id, text)
120
{
121
    by_id(li_id).firstElementChild.nextElementSibling.textContent = text;
122
}
123

    
124
function handle_page_info(message)
125
{
126
    const [type, data] = message;
127

    
128
    if (type === "change") {
129
	const li_id = ensure_pattern_exists(data.item);
130
	if (data.old_val === undefined)
131
	    set_pattern_li_button_text(li_id, "Edit in settings");
132
	if (data.new_val === undefined)
133
	    set_pattern_li_button_text(li_id, "Add setting");
134
    }
135

    
136
    if (type === "new_url") {
137
	for (const li_id of known_patterns.values())
138
	    set_pattern_li_button_text(li_id, "Add setting");
139
	for (const [pattern, settings] of data) {
140
	    set_pattern_li_button_text(ensure_pattern_exists(pattern),
141
				       "Edit in settings")
142
	}
143
    }
144
}
145

    
146
const connected_chbx = by_id("connected_chbx");
147
const query_pattern_but = by_id("query_pattern");
148

    
149
function try_to_connect(tab_id)
150
{
151
    /* This won't connect to iframes. We'll add support for them later */
152
    const connect_info = {name: CONNECTION_TYPE.ACTIVITY_INFO, frameId: 0};
153
    const port = browser.tabs.connect(tab_id, connect_info);
154

    
155
    const button_cb = (e) => start_querying_repos(port);
156

    
157
    port.onDisconnect.addListener(port => handle_disconnect(tab_id, button_cb));
158
    port.onMessage.addListener(handle_activity_report);
159

    
160
    query_pattern_but.addEventListener("click", button_cb);
161

    
162
    if (is_mozilla)
163
	setTimeout(() => monitor_connecting(port, tab_id), 1000);
164
}
165

    
166
const query_started_chbx = by_id("query_started_chbx");
167

    
168
function start_querying_repos(port)
169
{
170
    port.postMessage("dummy (trigger repo querying)");
171
    query_started_chbx.checked = true;
172
}
173

    
174
const loading_chbx = by_id("loading_chbx");
175

    
176
function handle_disconnect(tab_id, button_cb)
177
{
178
    query_pattern_but.removeEventListener("click", button_cb);
179

    
180
    if (is_chrome && !browser.runtime.lastError)
181
	return;
182

    
183
    /* return if error was not during connection initialization */
184
    if (connected_chbx.checked)
185
	return;
186

    
187
    loading_chbx.checked = !loading_chbx.checked;
188
    setTimeout(() => try_to_connect(tab_id), 1000);
189
}
190

    
191
function monitor_connecting(port, tab_id)
192
{
193
    if (connected_chbx.checked)
194
	return;
195

    
196
    port.disconnect();
197
    loading_chbx.checked = !loading_chbx.checked;
198
    try_to_connect(tab_id);
199
}
200

    
201
const pattern_span = by_id("pattern");
202
const view_pattern_but = by_id("view_pattern");
203
const blocked_span = by_id("blocked");
204
const payload_span = by_id("payload");
205
const view_payload_but = by_id("view_payload");
206
const container_for_injected = by_id("container_for_injected");
207
const container_for_repo_responses = by_id("container_for_repo_responses");
208

    
209
function handle_activity_report(message)
210
{
211
    connected_chbx.checked = true;
212

    
213
    const [type, data] = message;
214

    
215
    if (type === "settings") {
216
	let [pattern, settings, repos] = data;
217

    
218
	settings = settings || {};
219
	blocked_span.textContent = settings.allow ? "no" : "yes";
220

    
221
	if (pattern) {
222
	    pattern_span.textContent = pattern;
223
	    const settings_opener =
224
		  () => open_in_settings(TYPE_PREFIX.PAGE, pattern);
225
	    view_pattern_but.classList.remove("hide");
226
	    view_pattern_but.addEventListener("click", settings_opener);
227
	} else {
228
	    pattern_span.textContent = "none";
229
	}
230

    
231
	const components = settings.components;
232
	if (components) {
233
	    payload_span.textContent = nice_name(...components);
234
	    const settings_opener = () => open_in_settings(...components);
235
	    view_payload_but.classList.remove("hide");
236
	    view_payload_but.addEventListener("click", settings_opener);
237
	} else {
238
	    payload_span.textContent = "none";
239
	}
240
    }
241
    if (type === "script") {
242
	const h4 = document.createElement("h4");
243
	const pre = document.createElement("pre");
244
	h4.textContent = "script";
245
	pre.textContent = data;
246

    
247
	container_for_injected.appendChild(h4);
248
	container_for_injected.appendChild(pre);
249
    }
250
    if (type === "repo_query_result") {
251
	const [repo_url, response_text] = data;
252

    
253
	const h4 = document.createElement("h4");
254
	const pre = document.createElement("pre");
255
	h4.textContent = repo_url;
256
	pre.textContent = response_text;
257

    
258
	container_for_repo_responses.appendChild(h4);
259
	container_for_repo_responses.appendChild(pre);
260
    }
261
}
262

    
263
by_id("settings_but")
264
    .addEventListener("click", (e) => browser.runtime.openOptionsPage());
265

    
266
show_page_activity_info();
(2-2/4)