forked from aminomancer/uc.css.js
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathurlbarMods.uc.js
More file actions
219 lines (213 loc) · 14.7 KB
/
urlbarMods.uc.js
File metadata and controls
219 lines (213 loc) · 14.7 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// ==UserScript==
// @name Urlbar Mods
// @version 1.3.3
// @author aminomancer
// @homepage https://github.com/aminomancer/uc.css.js
// @description Makes some minor modifications to the urlbar. When you click & drag the identity box in the urlbar, it lets you drag and drop the URL into text fields, the tab bar, desktop, etc. while dragging it shows a little white box with the URL and favicon as the drag image. This script changes the colors of that drag box so they use CSS variables instead. This script can also be configured to restore the context menu that used to appear when right-clicking a search engine one-off button in the urlbar results panel. (The context menu was disabled recently) I'll continue to add to this script as I think of more urlbar mods that are too small to deserve their own dedicated script.
// ==/UserScript==
(function () {
class UrlbarMods {
static config = {
"restore one-offs context menu": false, // recently the context menu for the search engine one-off buttons in the urlbar results panel has been disabled. but the context menu for the one-off buttons in the searchbar is still enabled. I'm not sure why they did this, and it's a really minor thing, but it's not like right-clicking the buttons does anything else, (at least on windows) so you may want to restore the context menu.
"style identity icon drag box": true, // when you click & drag the identity box in the urlbar, it lets you drag and drop the URL into text fields, the tab bar, desktop, etc. while dragging it shows a little white box with the URL and favicon as the drag image. this can't be styled with CSS because it's drawn by the canvas 2D API. but we can easily change the function so that it sets the background and text colors equal to some CSS variables. it uses --tooltip-bgcolor, --tooltip-color, and --tooltip-border-color, or if those don't exist, it uses the vanilla variables --arrowpanel-background, --arrowpanel-color, and --arrowpanel-border-color. so if you use my theme duskFox it'll look similar to a tooltip. if you don't use my theme it'll look similar to a popup panel.
"show device icon in remote tab urlbar results": true, // my theme increases the prominence of the "type icon" in urlbar results. for bookmarks, this is a star. for open tabs, it's a tab icon. for remote tabs, aka synced tabs, it's a sync icon. with this option enabled, however, instead of showing a sync icon it will show a device icon specific to the type of device. so if the tab was synced from a cell phone, the type icon will show a phone. if it was synced from a laptop, it'll show a laptop, etc. the script will add some CSS to set the icons, but it won't change the way type icons are layed out. that's particular to my theme and it's purely a CSS issue, so I don't want the script to get involved in that. my urlbar-results.css file makes the type icon look basically like a 2nd favicon. it goes next to the favicon, rather than displaying on top of it. the script's CSS just changes the icon, so it'll fit with however you have type icons styled. if you don't use my theme but you want type icons to look more prominent, see urlbar-results.css and search "type-icon"
"disable urlbar intervention tips": true, // normally, when you type something like "firefox install" or "clear cookies" in the urlbar, it suggests an "intervention" or "tip" which acts as a kind of shortcut to various settings and profile operations that some beginners might have a hard time finding. this is a fine feature for people who are new to firefox. but people who use firefox a lot use the urlbar quickly and could very easily accidentally hit enter on one of those results. I decided to add this option to the script because I very nearly wiped my entire profile due to the tip that lets you "Restore default settings and remove old add-ons for optimal performance." From my point of view, these results just waste space while presenting a major hazard to the user, which makes them far more of a liability than an asset. Therefore, they will be removed entirely by this setting.
"underline whitespace results": true, // when you type nothing but space or tab characters in the urlbar, the first result will have an empty title. consecutive whitespace characters don't add to the displayed node width so it ends up looking basically empty. we can change this by setting it to use non-breaking spaces instead of space characters, and adding an attribute "all-whitespace" to the title element. then your CSS can underline it. this is already done in uc-urlbar-results.css but if you wanna do it yourself: .urlbarView-title[all-whitespace] {text-decoration: underline}
};
constructor() {
if (UrlbarMods.config["restore one-offs context menu"])
this.restoreOneOffsContextMenu();
if (UrlbarMods.config["style identity icon drag box"]) this.styleIdentityIconDragBox();
if (UrlbarMods.config["show device icon in remote tab urlbar results"])
this.urlbarResultsDeviceIcon();
if (UrlbarMods.config["disable urlbar intervention tips"])
this.disableUrlbarInterventions();
if (UrlbarMods.config["underline whitespace results"]) this.underlineSpaceResults();
}
get urlbarOneOffs() {
return this._urlbarOneOffs || (this._urlbarOneOffs = gURLBar.view.oneOffSearchButtons);
}
restoreOneOffsContextMenu() {
const urlbarOneOffsProto = Object.getPrototypeOf(this.urlbarOneOffs);
const oneOffsBase = Object.getPrototypeOf(urlbarOneOffsProto);
this.urlbarOneOffs._on_contextmenu = oneOffsBase._on_contextmenu;
}
urlbarResultsDeviceIcon() {
XPCOMUtils.defineLazyPreferenceGetter(
this,
"showRemoteIconsPref",
"services.sync.syncedTabs.showRemoteIcons",
true
);
XPCOMUtils.defineLazyModuleGetter(
this,
"UrlbarResult",
"resource:///modules/UrlbarResult.jsm"
);
let showRemoteIconsPref = this.showRemoteIconsPref;
let UrlbarResult = this.UrlbarResult;
let gUniqueIdSerial = 1;
const RECENT_REMOTE_TAB_THRESHOLD_MS = 72 * 60 * 60 * 1000;
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function getUniqueId(prefix) {
return prefix + (gUniqueIdSerial++ % 9999);
}
let provider = gURLBar.view.controller.manager.providers.find(
(provider) => provider.name === "RemoteTabs"
);
UrlbarUtils.RESULT_PAYLOAD_SCHEMA[
UrlbarUtils.RESULT_TYPE.REMOTE_TAB
].properties.clientType = {
type: "string",
};
let src1 = provider.startQuery.toSource();
let src2 = gURLBar.view._updateRow.toSource();
if (!src1.includes("client.clientType"))
eval(
`provider.startQuery = async function ` +
provider.startQuery
.toSource()
.replace(/async startQuery/, ``)
.replace(
/(device\: client\.name\,)/,
`$1 clientType: client.clientType,`
)
);
if (!src2.includes("result.payload.clientType"))
eval(
`gURLBar.view._updateRow = function ` +
gURLBar.view._updateRow
.toSource()
.replace(
/(item\.removeAttribute\(\"stale\"\)\;)/,
`$1 item.removeAttribute("clientType");`
)
.replace(
/(item\.setAttribute\(\"type\"\, \"remotetab\"\)\;)/,
`$1 if (result.payload.clientType) item.setAttribute("clientType", result.payload.clientType);`
)
);
let css = `.urlbarView-row[type="remotetab"] .urlbarView-type-icon{background:var(--device-icon,url("chrome://browser/skin/sync.svg")) center/contain no-repeat;}.urlbarView-row[type="remotetab"][clientType="phone"]{--device-icon:url("chrome://browser/skin/device-phone.svg");}.urlbarView-row[type="remotetab"][clientType="tablet"]{--device-icon:url("chrome://browser/skin/device-tablet.svg");}.urlbarView-row[type="remotetab"][clientType="desktop"]{--device-icon:url("chrome://browser/skin/device-desktop.svg");}.urlbarView-row[type="remotetab"][clientType="tv"]{--device-icon:url("chrome://browser/skin/device-tv.svg");}.urlbarView-row[type="remotetab"][clientType="vr"]{--device-icon:url("chrome://browser/skin/device-vr.svg");}`;
let sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(
Ci.nsIStyleSheetService
);
let uri = makeURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (sss.sheetRegistered(uri, sss.AUTHOR_SHEET)) return;
sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET);
}
styleIdentityIconDragBox() {
// for a given string in CSS3 custom property syntax, e.g. "var(--tooltip-color)" or "var(--tooltip-color, rgb(255, 255, 255))", convert it to a hex code string e.g. "#FFFFFF"
function varToHex(variable) {
let temp = document.createElement("div");
document.body.appendChild(temp);
temp.style.color = variable;
let rgb = getComputedStyle(temp).color;
temp.remove();
rgb = rgb
.split("(")[1]
.split(")")[0]
.split(rgb.indexOf(",") > -1 ? "," : " ");
rgb.length = 3;
rgb.forEach((c, i) => {
c = (+c).toString(16);
rgb[i] = c.length === 1 ? "0" + c : c.slice(0, 2);
});
return "#" + rgb.join("");
}
// draw a rectangle with rounded corners
function roundRect(ctx, x, y, width, height, radius = 5, fill, stroke) {
if (typeof radius === "number")
radius = { tl: radius, tr: radius, br: radius, bl: radius };
else {
let defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
for (let side in defaultRadius)
radius[side] = radius[side] || defaultRadius[side];
}
ctx.beginPath();
ctx.moveTo(x + radius.tl, y);
ctx.lineTo(x + width - radius.tr, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
ctx.lineTo(x + width, y + height - radius.br);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
ctx.lineTo(x + radius.bl, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
ctx.lineTo(x, y + radius.tl);
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
ctx.closePath();
if (fill) {
ctx.fillStyle = fill;
ctx.fill();
}
if (stroke) {
ctx.strokeStyle = stroke;
ctx.stroke();
}
}
// override the internal dragstart callback so it uses variables instead of "white" and "black"
eval(
`gIdentityHandler.onDragStart = function ` +
gIdentityHandler.onDragStart
.toSource()
.replace(
/(let backgroundColor = ).*;/,
`$1varToHex("var(--tooltip-bgcolor, var(--arrowpanel-background))");`
)
.replace(
/(let textColor = ).*;/,
`$1varToHex("var(--tooltip-color, var(--arrowpanel-color))");`
)
.replace(/ctx\.fillStyle = backgroundColor;/, ``)
.replace(
/ctx\.fillRect.*;/,
`roundRect(ctx, 0, 0, totalWidth * scale, totalHeight * scale, 5, backgroundColor, varToHex("var(--tooltip-border-color, var(--arrowpanel-border-color))"));`
)
);
}
disableUrlbarInterventions() {
let manager = gURLBar.controller.manager;
let interventions = manager.providers.find(
(provider) => provider.name === "UrlbarProviderInterventions"
);
if (interventions) manager.unregisterProvider(interventions);
}
underlineSpaceResults() {
gURLBar.view._addTextContentWithHighlights = function (node, text, highlights) {
node.textContent = "";
if (!text) return;
if (/^\s{2,}$/.test(text) && !highlights.length) {
text = text.replace(/\s/g, `\u00A0`);
node.setAttribute("all-whitespace", true);
} else node.removeAttribute("all-whitespace");
highlights = (highlights || []).concat([[text.length, 0]]);
let index = 0;
for (let [highlightIndex, highlightLength] of highlights) {
if (highlightIndex - index > 0)
node.appendChild(
this.document.createTextNode(text.substring(index, highlightIndex))
);
if (highlightLength > 0) {
let strong = this._createElement("strong");
strong.textContent = text.substring(
highlightIndex,
highlightIndex + highlightLength
);
node.appendChild(strong);
}
index = highlightIndex + highlightLength;
}
};
}
}
if (gBrowserInit.delayedStartupFinished) new UrlbarMods();
else {
let delayedListener = (subject, topic) => {
if (topic == "browser-delayed-startup-finished" && subject == window) {
Services.obs.removeObserver(delayedListener, topic);
new UrlbarMods();
}
};
Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished");
}
})();