blob: 3991d9191f6da1df1ade255317d2b20d58406449 [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.
4/**
5 * @implements {UI.ListWidget.Delegate<SDK.NetworkManager.BlockedPattern>}
6 */
7Network.BlockedURLsPane = class extends UI.VBox {
8 constructor() {
9 super(true);
10 this.registerRequiredCSS('network/blockedURLsPane.css');
11
12 Network.BlockedURLsPane._instance = this;
13 this._manager = SDK.multitargetNetworkManager;
14 this._manager.addEventListener(SDK.MultitargetNetworkManager.Events.BlockedPatternsChanged, this._update, this);
15
16 this._toolbar = new UI.Toolbar('', this.contentElement);
17 this._enabledCheckbox =
18 new UI.ToolbarCheckbox(Common.UIString('Enable request blocking'), undefined, this._toggleEnabled.bind(this));
19 this._toolbar.appendToolbarItem(this._enabledCheckbox);
20 this._toolbar.appendSeparator();
21 const addButton = new UI.ToolbarButton(Common.UIString('Add pattern'), 'largeicon-add');
22 addButton.addEventListener(UI.ToolbarButton.Events.Click, this._addButtonClicked, this);
23 this._toolbar.appendToolbarItem(addButton);
24 const clearButton = new UI.ToolbarButton(Common.UIString('Remove all patterns'), 'largeicon-clear');
25 clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._removeAll, this);
26 this._toolbar.appendToolbarItem(clearButton);
27
28 /** @type {!UI.ListWidget<!SDK.NetworkManager.BlockedPattern>} */
29 this._list = new UI.ListWidget(this);
30 this._list.element.classList.add('blocked-urls');
31 this._list.registerRequiredCSS('network/blockedURLsPane.css');
32 this._list.setEmptyPlaceholder(this._createEmptyPlaceholder());
33 this._list.show(this.contentElement);
34
35 /** @type {?UI.ListWidget.Editor<!SDK.NetworkManager.BlockedPattern>} */
36 this._editor = null;
37
38 /** @type {!Map<string, number>} */
39 this._blockedCountForUrl = new Map();
40 SDK.targetManager.addModelListener(
41 SDK.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this._onRequestFinished, this);
42
43 this._updateThrottler = new Common.Throttler(200);
44
45 this._update();
46 }
47
48 /**
49 * @return {!Element}
50 */
51 _createEmptyPlaceholder() {
52 const element = this.contentElement.createChild('div', 'no-blocked-urls');
Mandy Chena14625d2019-06-14 21:54:3953 const addLink = UI.XLink.create('', ls`Add pattern`);
Blink Reformat4c46d092018-04-07 15:32:3754 addLink.addEventListener('click', this._addButtonClicked.bind(this), false);
Mandy Chena14625d2019-06-14 21:54:3955 element.appendChild(UI.formatLocalized('Requests are not blocked. %s.', [addLink]));
Blink Reformat4c46d092018-04-07 15:32:3756 return element;
57 }
58
59 static reset() {
60 if (Network.BlockedURLsPane._instance)
61 Network.BlockedURLsPane._instance.reset();
62 }
63
64 _addButtonClicked() {
65 this._manager.setBlockingEnabled(true);
66 this._list.addNewItem(0, {url: '', enabled: true});
67 }
68
69 /**
70 * @override
71 * @param {!SDK.NetworkManager.BlockedPattern} pattern
72 * @param {boolean} editable
73 * @return {!Element}
74 */
75 renderItem(pattern, editable) {
76 const count = this._blockedRequestsCount(pattern.url);
77 const element = createElementWithClass('div', 'blocked-url');
78 const checkbox = element.createChild('input', 'blocked-url-checkbox');
79 checkbox.type = 'checkbox';
80 checkbox.checked = pattern.enabled;
81 checkbox.disabled = !this._manager.blockingEnabled();
82 element.createChild('div', 'blocked-url-label').textContent = pattern.url;
83 element.createChild('div', 'blocked-url-count').textContent = Common.UIString('%d blocked', count);
84 element.addEventListener('click', event => this._togglePattern(pattern, event), false);
85 checkbox.addEventListener('click', event => this._togglePattern(pattern, event), false);
86 return element;
87 }
88
89 /**
90 * @param {!SDK.NetworkManager.BlockedPattern} pattern
91 * @param {!Event} event
92 */
93 _togglePattern(pattern, event) {
94 event.consume(true);
95 const patterns = this._manager.blockedPatterns();
96 patterns.splice(patterns.indexOf(pattern), 1, {enabled: !pattern.enabled, url: pattern.url});
97 this._manager.setBlockedPatterns(patterns);
98 }
99
100 _toggleEnabled() {
101 this._manager.setBlockingEnabled(!this._manager.blockingEnabled());
102 this._update();
103 }
104
105 /**
106 * @override
107 * @param {!SDK.NetworkManager.BlockedPattern} pattern
108 * @param {number} index
109 */
110 removeItemRequested(pattern, index) {
111 const patterns = this._manager.blockedPatterns();
112 patterns.splice(index, 1);
113 this._manager.setBlockedPatterns(patterns);
114 }
115
116 /**
117 * @override
118 * @param {!SDK.NetworkManager.BlockedPattern} pattern
119 * @return {!UI.ListWidget.Editor}
120 */
121 beginEdit(pattern) {
122 this._editor = this._createEditor();
123 this._editor.control('url').value = pattern.url;
124 return this._editor;
125 }
126
127 /**
128 * @override
129 * @param {!SDK.NetworkManager.BlockedPattern} item
130 * @param {!UI.ListWidget.Editor} editor
131 * @param {boolean} isNew
132 */
133 commitEdit(item, editor, isNew) {
134 const url = editor.control('url').value;
135 const patterns = this._manager.blockedPatterns();
136 if (isNew)
137 patterns.push({enabled: true, url: url});
138 else
139 patterns.splice(patterns.indexOf(item), 1, {enabled: true, url: url});
140
141 this._manager.setBlockedPatterns(patterns);
142 }
143
144 /**
145 * @return {!UI.ListWidget.Editor<!SDK.NetworkManager.BlockedPattern>}
146 */
147 _createEditor() {
148 if (this._editor)
149 return this._editor;
150
151 const editor = new UI.ListWidget.Editor();
152 const content = editor.contentElement();
153 const titles = content.createChild('div', 'blocked-url-edit-row');
154 titles.createChild('div').textContent =
155 Common.UIString('Text pattern to block matching requests; use * for wildcard');
156 const fields = content.createChild('div', 'blocked-url-edit-row');
157 const urlInput = editor.createInput(
158 'url', 'text', '',
159 (item, index, input) =>
160 !!input.value && !this._manager.blockedPatterns().find(pattern => pattern.url === input.value));
161 fields.createChild('div', 'blocked-url-edit-value').appendChild(urlInput);
162 return editor;
163 }
164
165 _removeAll() {
166 this._manager.setBlockedPatterns([]);
167 }
168
169 /**
170 * @return {!Promise<?>}
171 */
172 _update() {
173 const enabled = this._manager.blockingEnabled();
174 this._list.element.classList.toggle('blocking-disabled', !enabled && !!this._manager.blockedPatterns().length);
175 this._enabledCheckbox.setChecked(enabled);
176 this._list.clear();
177 for (const pattern of this._manager.blockedPatterns())
178 this._list.appendItem(pattern, true);
179 return Promise.resolve();
180 }
181
182 /**
183 * @param {string} url
184 * @return {number}
185 */
186 _blockedRequestsCount(url) {
187 if (!url)
188 return 0;
189
190 let result = 0;
191 for (const blockedUrl of this._blockedCountForUrl.keys()) {
192 if (this._matches(url, blockedUrl))
193 result += this._blockedCountForUrl.get(blockedUrl);
194 }
195 return result;
196 }
197
198 /**
199 * @param {string} pattern
200 * @param {string} url
201 * @return {boolean}
202 */
203 _matches(pattern, url) {
204 let pos = 0;
205 const parts = pattern.split('*');
206 for (let index = 0; index < parts.length; index++) {
207 const part = parts[index];
208 if (!part.length)
209 continue;
210 pos = url.indexOf(part, pos);
211 if (pos === -1)
212 return false;
213 pos += part.length;
214 }
215 return true;
216 }
217
218 reset() {
219 this._blockedCountForUrl.clear();
220 this._updateThrottler.schedule(this._update.bind(this));
221 }
222
223 /**
224 * @param {!Common.Event} event
225 */
226 _onRequestFinished(event) {
227 const request = /** @type {!SDK.NetworkRequest} */ (event.data);
228 if (request.wasBlocked()) {
229 const count = this._blockedCountForUrl.get(request.url()) || 0;
230 this._blockedCountForUrl.set(request.url(), count + 1);
231 this._updateThrottler.schedule(this._update.bind(this));
232 }
233 }
234};
235
236/** @type {?Network.BlockedURLsPane} */
237Network.BlockedURLsPane._instance = null;