-
Notifications
You must be signed in to change notification settings - Fork 43
/
url_selector.js
166 lines (161 loc) · 4.88 KB
/
url_selector.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import {Site} from './utils.js';
export function UrlSelector(url_string) {
// Needed to reference 'this' when concatenating arrays.
const self = this;
if (!(this instanceof UrlSelector)) {
return new UrlSelector(url_string);
}
const site = new Site(url_string);
this.subdomains = site.domain_hierarchy.slice(1).reverse();
this.domain = site.domain_hierarchy[0];
this.path_parts = site.page_hierarchy.slice(0);
this.pieces = [];
Array.prototype.push.apply(this.pieces, this.subdomains.map(function(sub) {
return self.url_component(sub);
}));
const domain_piece = this.url_component(this.domain);
domain_piece.id = 'domain';
domain_piece.classList.add('end');
this.pieces.push(domain_piece);
this.pieces[0].classList.add('start');
Array.prototype.push.apply(this.pieces, this.path_parts.map(function(path) {
return self.url_component(path, false);
}));
}
UrlSelector.prototype.render_to = function(target) {
// Set the appropriate class for CSS rendering
if (!target.classList.contains('url_selector')) {
target.classList.add('url_selector');
}
// Clear any existing contents. Hope you didn't want it!
while (target.firstChild) {
target.removeChild(target.firstChild);
}
this.pieces.forEach(function(piece) {
target.appendChild(piece);
});
}
UrlSelector.prototype.clear_start = function() {
this.clear_class_from_children('start');
}
UrlSelector.prototype.clear_end = function() {
this.clear_class_from_children('end');
}
UrlSelector.prototype.clear_class_from_children = function(class_name) {
this.pieces.forEach(function(piece) {
piece.classList.remove(class_name);
});
}
UrlSelector.prototype.clear_path = function() {
this.clear_end();
document.getElementById('domain').classList.add('end');
}
UrlSelector.prototype.reset_default = function() {
this.clear_path();
this.clear_start();
this.pieces[0].classList.add('start');
}
UrlSelector.prototype.url_component = function(text, is_host) {
// Needed to reference 'this' in the onclick callback
const self = this;
is_host = typeof is_host !== 'undefined' ? is_host : true;
const new_element = document.createElement('span');
new_element.textContent = text;
new_element.onclick = (function(evt) {
const target = evt.target;
if (is_host) {
self.clear_start();
self.clear_path();
target.classList.add('start');
} else {
self.clear_end();
target.classList.add('end');
}
});
new_element.classList.add(is_host ? 'host' : 'path');
return new_element;
}
UrlSelector.prototype.select_host = function(name) {
const self = this;
this.pieces.filter(is_host_element).forEach(function(elem) {
if (elem.textContent.match(name)) {
self.select_item(elem);
}
});
}
UrlSelector.prototype.select_path = function(name) {
const self = this;
this.pieces.filter(is_path_element).forEach(function(elem) {
if (elem.textContent.match(name)) {
self.select_item(elem);
}
});
}
UrlSelector.prototype.select_item = function(elem) {
elem.click();
}
UrlSelector.prototype.get_site = function() {
let selected = false;
const domains = [];
const paths = [];
this.pieces.forEach(function(piece) {
if (piece.classList.contains('start')) {
selected = true;
}
if (selected && piece.classList.contains('host')) {
domains.push(piece.textContent);
} else if (selected) {
paths.push(piece.textContent);
}
if (piece.classList.contains('end')) {
selected = false;
}
});
domains.reverse();
return new Site.build(domains, paths);
}
UrlSelector.prototype.select_site = function(site) {
// Just use the default if the site doesn't actually match. Don't treat
// this as an error because it's more convenient to treat the default case
// as an instance of this.
if (site.domain_hierarchy[0] != this.domain) {
this.reset_default();
return;
}
const hosts = site.domain_hierarchy.slice(1);
const paths = site.page_hierarchy.slice(0);
let idx = 0;
// Use the default full-domain selection if all domain components are the
// same
this.subdomains.slice(0).reverse().every(function(sub) {
if (hosts[idx] != sub) {
return false;
}
idx++;
return true;
});
// Select the matching component of the domain
this.select_item(this.pieces[this.subdomains.length - idx]);
idx = 0;
// Find the first path component that's not the same
this.path_parts.every(function(path) {
if (paths[idx] != path) {
return false;
}
idx++;
return true;
});
// Don't use the default if any common paths were found
if (idx > 0) {
// Select the matching component of the path
this.select_item(this.pieces[this.subdomains.length + idx]);
}
}
function is_host_element(elem) {
return elem.classList.contains('host');
}
function is_path_element(elem) {
return elem.classList.contains('path');
}
export default UrlSelector;
// vim: et ts=2 sts=2 sw=2