blob: 870fd5c30ff766e4f86832bff53707d851380107 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright (c) 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Tim van der Lippe119690c2020-01-13 12:31:304
5/** @type {?BlockedURLsPane} */
6export let _instance = null;
7
Blink Reformat4c46d092018-04-07 15:32:378/**
9 * @implements {UI.ListWidget.Delegate<SDK.NetworkManager.BlockedPattern>}
10 */
Tim van der Lippe119690c2020-01-13 12:31:3011export class BlockedURLsPane extends UI.VBox {
Blink Reformat4c46d092018-04-07 15:32:3712 constructor() {
13 super(true);
14 this.registerRequiredCSS('network/blockedURLsPane.css');
15
Tim van der Lippe119690c2020-01-13 12:31:3016 _instance = this;
Blink Reformat4c46d092018-04-07 15:32:3717 this._manager = SDK.multitargetNetworkManager;
18 this._manager.addEventListener(SDK.MultitargetNetworkManager.Events.BlockedPatternsChanged, this._update, this);
19
20 this._toolbar = new UI.Toolbar('', this.contentElement);
21 this._enabledCheckbox =
22 new UI.ToolbarCheckbox(Common.UIString('Enable request blocking'), undefined, this._toggleEnabled.bind(this));
23 this._toolbar.appendToolbarItem(this._enabledCheckbox);
24 this._toolbar.appendSeparator();
25 const addButton = new UI.ToolbarButton(Common.UIString('Add pattern'), 'largeicon-add');
26 addButton.addEventListener(UI.ToolbarButton.Events.Click, this._addButtonClicked, this);
27 this._toolbar.appendToolbarItem(addButton);
28 const clearButton = new UI.ToolbarButton(Common.UIString('Remove all patterns'), 'largeicon-clear');
29 clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._removeAll, this);
30 this._toolbar.appendToolbarItem(clearButton);
31
32 /** @type {!UI.ListWidget<!SDK.NetworkManager.BlockedPattern>} */
33 this._list = new UI.ListWidget(this);
34 this._list.element.classList.add('blocked-urls');
35 this._list.registerRequiredCSS('network/blockedURLsPane.css');
36 this._list.setEmptyPlaceholder(this._createEmptyPlaceholder());
37 this._list.show(this.contentElement);
38
39 /** @type {?UI.ListWidget.Editor<!SDK.NetworkManager.BlockedPattern>} */
40 this._editor = null;
41
42 /** @type {!Map<string, number>} */
43 this._blockedCountForUrl = new Map();
Paul Lewis4ae5f4f2020-01-23 10:19:3344 self.SDK.targetManager.addModelListener(
Blink Reformat4c46d092018-04-07 15:32:3745 SDK.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this._onRequestFinished, this);
46
47 this._updateThrottler = new Common.Throttler(200);
48
49 this._update();
50 }
51
52 /**
53 * @return {!Element}
54 */
55 _createEmptyPlaceholder() {
56 const element = this.contentElement.createChild('div', 'no-blocked-urls');
Mandy Chen6a711a92019-10-08 22:58:1857 const addButton = UI.createTextButton(ls`Add pattern`, this._addButtonClicked.bind(this), 'add-button');
58 UI.ARIAUtils.setAccessibleName(addButton, ls`Add request blocking pattern`);
59 element.appendChild(UI.formatLocalized('Requests are not blocked. %s', [addButton]));
Blink Reformat4c46d092018-04-07 15:32:3760 return element;
61 }
62
63 static reset() {
Tim van der Lippe119690c2020-01-13 12:31:3064 if (_instance) {
65 _instance.reset();
Tim van der Lippe1d6e57a2019-09-30 11:55:3466 }
Blink Reformat4c46d092018-04-07 15:32:3767 }
68
69 _addButtonClicked() {
70 this._manager.setBlockingEnabled(true);
71 this._list.addNewItem(0, {url: '', enabled: true});
72 }
73
74 /**
75 * @override
76 * @param {!SDK.NetworkManager.BlockedPattern} pattern
77 * @param {boolean} editable
78 * @return {!Element}
79 */
80 renderItem(pattern, editable) {
81 const count = this._blockedRequestsCount(pattern.url);
82 const element = createElementWithClass('div', 'blocked-url');
83 const checkbox = element.createChild('input', 'blocked-url-checkbox');
84 checkbox.type = 'checkbox';
85 checkbox.checked = pattern.enabled;
86 checkbox.disabled = !this._manager.blockingEnabled();
87 element.createChild('div', 'blocked-url-label').textContent = pattern.url;
88 element.createChild('div', 'blocked-url-count').textContent = Common.UIString('%d blocked', count);
89 element.addEventListener('click', event => this._togglePattern(pattern, event), false);
90 checkbox.addEventListener('click', event => this._togglePattern(pattern, event), false);
91 return element;
92 }
93
94 /**
95 * @param {!SDK.NetworkManager.BlockedPattern} pattern
96 * @param {!Event} event
97 */
98 _togglePattern(pattern, event) {
99 event.consume(true);
100 const patterns = this._manager.blockedPatterns();
101 patterns.splice(patterns.indexOf(pattern), 1, {enabled: !pattern.enabled, url: pattern.url});
102 this._manager.setBlockedPatterns(patterns);
103 }
104
105 _toggleEnabled() {
106 this._manager.setBlockingEnabled(!this._manager.blockingEnabled());
107 this._update();
108 }
109
110 /**
111 * @override
112 * @param {!SDK.NetworkManager.BlockedPattern} pattern
113 * @param {number} index
114 */
115 removeItemRequested(pattern, index) {
116 const patterns = this._manager.blockedPatterns();
117 patterns.splice(index, 1);
118 this._manager.setBlockedPatterns(patterns);
119 }
120
121 /**
122 * @override
123 * @param {!SDK.NetworkManager.BlockedPattern} pattern
124 * @return {!UI.ListWidget.Editor}
125 */
126 beginEdit(pattern) {
127 this._editor = this._createEditor();
128 this._editor.control('url').value = pattern.url;
129 return this._editor;
130 }
131
132 /**
133 * @override
134 * @param {!SDK.NetworkManager.BlockedPattern} item
135 * @param {!UI.ListWidget.Editor} editor
136 * @param {boolean} isNew
137 */
138 commitEdit(item, editor, isNew) {
139 const url = editor.control('url').value;
140 const patterns = this._manager.blockedPatterns();
Tim van der Lippe1d6e57a2019-09-30 11:55:34141 if (isNew) {
Blink Reformat4c46d092018-04-07 15:32:37142 patterns.push({enabled: true, url: url});
Tim van der Lippe1d6e57a2019-09-30 11:55:34143 } else {
Blink Reformat4c46d092018-04-07 15:32:37144 patterns.splice(patterns.indexOf(item), 1, {enabled: true, url: url});
Tim van der Lippe1d6e57a2019-09-30 11:55:34145 }
Blink Reformat4c46d092018-04-07 15:32:37146
147 this._manager.setBlockedPatterns(patterns);
148 }
149
150 /**
151 * @return {!UI.ListWidget.Editor<!SDK.NetworkManager.BlockedPattern>}
152 */
153 _createEditor() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34154 if (this._editor) {
Blink Reformat4c46d092018-04-07 15:32:37155 return this._editor;
Tim van der Lippe1d6e57a2019-09-30 11:55:34156 }
Blink Reformat4c46d092018-04-07 15:32:37157
158 const editor = new UI.ListWidget.Editor();
159 const content = editor.contentElement();
160 const titles = content.createChild('div', 'blocked-url-edit-row');
161 titles.createChild('div').textContent =
162 Common.UIString('Text pattern to block matching requests; use * for wildcard');
163 const fields = content.createChild('div', 'blocked-url-edit-row');
Amanda Bakerca502822019-07-02 00:01:28164 const validator = (item, index, input) => {
Michael Liaoaf4130a2020-01-14 22:13:14165 let valid = true;
166 let errorMessage;
167 if (!input.value) {
168 errorMessage = ls`Pattern input cannot be empty.`;
169 valid = false;
170 } else if (this._manager.blockedPatterns().find(pattern => pattern.url === input.value)) {
171 errorMessage = ls`Pattern already exists.`;
172 valid = false;
173 }
174 return {valid, errorMessage};
Amanda Bakerca502822019-07-02 00:01:28175 };
176 const urlInput = editor.createInput('url', 'text', '', validator);
Blink Reformat4c46d092018-04-07 15:32:37177 fields.createChild('div', 'blocked-url-edit-value').appendChild(urlInput);
178 return editor;
179 }
180
181 _removeAll() {
182 this._manager.setBlockedPatterns([]);
183 }
184
185 /**
186 * @return {!Promise<?>}
187 */
188 _update() {
189 const enabled = this._manager.blockingEnabled();
190 this._list.element.classList.toggle('blocking-disabled', !enabled && !!this._manager.blockedPatterns().length);
191 this._enabledCheckbox.setChecked(enabled);
192 this._list.clear();
Tim van der Lippe1d6e57a2019-09-30 11:55:34193 for (const pattern of this._manager.blockedPatterns()) {
Blink Reformat4c46d092018-04-07 15:32:37194 this._list.appendItem(pattern, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34195 }
Blink Reformat4c46d092018-04-07 15:32:37196 return Promise.resolve();
197 }
198
199 /**
200 * @param {string} url
201 * @return {number}
202 */
203 _blockedRequestsCount(url) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34204 if (!url) {
Blink Reformat4c46d092018-04-07 15:32:37205 return 0;
Tim van der Lippe1d6e57a2019-09-30 11:55:34206 }
Blink Reformat4c46d092018-04-07 15:32:37207
208 let result = 0;
209 for (const blockedUrl of this._blockedCountForUrl.keys()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34210 if (this._matches(url, blockedUrl)) {
Blink Reformat4c46d092018-04-07 15:32:37211 result += this._blockedCountForUrl.get(blockedUrl);
Tim van der Lippe1d6e57a2019-09-30 11:55:34212 }
Blink Reformat4c46d092018-04-07 15:32:37213 }
214 return result;
215 }
216
217 /**
218 * @param {string} pattern
219 * @param {string} url
220 * @return {boolean}
221 */
222 _matches(pattern, url) {
223 let pos = 0;
224 const parts = pattern.split('*');
225 for (let index = 0; index < parts.length; index++) {
226 const part = parts[index];
Tim van der Lippe1d6e57a2019-09-30 11:55:34227 if (!part.length) {
Blink Reformat4c46d092018-04-07 15:32:37228 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34229 }
Blink Reformat4c46d092018-04-07 15:32:37230 pos = url.indexOf(part, pos);
Tim van der Lippe1d6e57a2019-09-30 11:55:34231 if (pos === -1) {
Blink Reformat4c46d092018-04-07 15:32:37232 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34233 }
Blink Reformat4c46d092018-04-07 15:32:37234 pos += part.length;
235 }
236 return true;
237 }
238
239 reset() {
240 this._blockedCountForUrl.clear();
241 this._updateThrottler.schedule(this._update.bind(this));
242 }
243
244 /**
245 * @param {!Common.Event} event
246 */
247 _onRequestFinished(event) {
248 const request = /** @type {!SDK.NetworkRequest} */ (event.data);
249 if (request.wasBlocked()) {
250 const count = this._blockedCountForUrl.get(request.url()) || 0;
251 this._blockedCountForUrl.set(request.url(), count + 1);
252 this._updateThrottler.schedule(this._update.bind(this));
253 }
254 }
Paul Lewis56509652019-12-06 12:51:58255}