Skip to content
This repository has been archived by the owner on Dec 23, 2018. It is now read-only.

Commit

Permalink
Implement custom UI for user-defined exception on the options page
Browse files Browse the repository at this point in the history
  • Loading branch information
ntninja committed Jan 9, 2017
1 parent 26ea54c commit a5f2789
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 47 deletions.
20 changes: 11 additions & 9 deletions webextension/deps/wext-options/options.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ body {
/**
* Simple gird layout for option entries (very similar to the JetPack option page)
*/
form > *[data-option] {
body > *[data-option] {
display: flex;
flex-direction: row;
align-items: center;
Expand All @@ -21,31 +21,33 @@ form > *[data-option] {
min-height: 35px;
border-top: 1px solid #c1c1c1;
}
form > *[data-option]:first-child {
body > *[data-option]:first-child {
border-top: 0;
}
form > *[data-option].hidden {
body > *[data-option].hidden {
display: none;
}

form > *[data-option] > label,
form > *[data-option] > .label {
body > *[data-option] > label,
body > *[data-option] > .label {
width: 37%;

font-size: 1.125em;
}

form > *[data-option] > .label.description > span {
body > *[data-option] > .label.description > span {
display: block;
margin: 0 0.5em 0 2em;

font-size: 90.9%;
color: graytext;
}

form > *[data-option] > input,
form > *[data-option] > select,
form > *[data-option] > .value {
body > *[data-option] > input,
body > *[data-option] > select,
body > *[data-option] > .value {
flex-grow: 1;
width: 63%;

margin: 3px 0;
}
7 changes: 6 additions & 1 deletion webextension/deps/wext-options/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
// available option items
let hooks = OPTION_HOOKS || {};
let options = {};
for(let DOMOption of document.querySelectorAll("form > *[data-option]")) {
for(let DOMOption of document.querySelectorAll("body > *[data-option]")) {
let name = DOMOption.getAttribute("data-option");

// Find option value form element
Expand Down Expand Up @@ -270,6 +270,11 @@
type = "text";
} else if(DOMOptionTarget.hasAttribute("type")) {
type = DOMOptionTarget.getAttribute("type");
if(type === "hidden") {
// <input type="hidden" /> may be used if the consumer implements a
// a custom UI and wishes to use us only for event management.
type = "text";
}
} else {
type = "text";
}
Expand Down
102 changes: 65 additions & 37 deletions webextension/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,75 @@
<link rel="stylesheet" type="text/css" href="deps/wext-options/options.css" />
</head>
<body>
<form>
<div data-option="enable">
<label for="option_enable">Enable Smart Referer</label>
<div class="value">
<input type="checkbox" id="option_enable" />
</div>
<div data-option="enable">
<label for="option_enable">Enable Smart Referer</label>
<div class="value">
<input type="checkbox" id="option_enable" />
</div>
<div data-option="strict">
<div class="label description">
<label for="option_strict">Strict</label>
<span>Treat subdomains as different domains</span>
</div>
<div class="value">
<input type="checkbox" id="option_strict" />
</div>
</div>

<div data-option="strict">
<div class="label description">
<label for="option_strict">Strict</label>
<span>Treat subdomains as different domains</span>
</div>
<div class="value">
<input type="checkbox" id="option_strict" />
</div>

<div data-option="allow">
<label for="option_allow">Allow</label>
<input type="text" id="option_allow" />
</div>

<div data-option="allow">
<div class="label description">
<label for="option_strict">Exceptions</label>
<span>Always allow referers to be passed from and to the given source and target host</span>
</div>

<div data-option="whitelist">
<label for="option_whitelist">Whitelist Source</label>
<input type="url" id="option_whitelist" />
<div class="value">
<!-- String value storage for `wext-options` -->
<input type="hidden" />

<form id="option_allow_new_form">
<table>
<thead>
<tr>
<th>Source</th>
<th>Destination</th>
<th>&nbsp;</th>
</tr>
</thead>
<tfoot>
<tr>
<td><input type="text" size="18" required pattern="(?:[a-zA-Z0-9*\x0080-\xFFFF-]+[.])*[a-zA-Z0-9*\x0080-\xFFFF-]+" id="option_allow_new_source" /></td>
<td><input type="text" size="18" required pattern="(?:[a-zA-Z0-9*\x0080-\xFFFF-]+[.])*[a-zA-Z0-9*\x0080-\xFFFF-]+" id="option_allow_new_destination" /></td>
<td><button type="submit" title="Add Item"></button></td>
</tr>
</tfoot>
<tbody id="option_allow_display" style="text-align: center;">

</tbody>
</table>
</form>

<p style="width: 100%; font-size: 0.76em; margin: 0.2em;">Both source and target hosts may contain contain wildcards: <code>*.example.com</code> matches all domains at <code>example.com</code>. A single star character (<code>*</code>) means “any host”.</p>
</div>

<div data-option="mode">
<label for="option_mode">Mode</label>
<div class="value">
<select id="option_mode" style="display: block; width: 30em;">
<option value="self">Send the URL you're going to as referer</option>
<option value="direct">Send nothing as referer, looking like a direct hit</option>
<option value="user">Use the following, provided referer:
</select>
<input type="text" id="option_referer" style="width: 29.5em;" title="User Referer" disabled />
</div>
</div>

<div data-option="whitelist">
<label for="option_whitelist">Whitelist Source</label>
<input type="url" id="option_whitelist" />
</div>

<div data-option="mode">
<label for="option_mode">Mode</label>
<div class="value">
<select id="option_mode" style="display: block; width: 30em;">
<option value="self">Send the URL you're going to as referer</option>
<option value="direct">Send nothing as referer, looking like a direct hit</option>
<option value="user">Use the following, provided referer:
</select>
<input type="text" id="option_referer" style="width: 29.5em;" title="User Referer" disabled />
</div>
<div data-option="referer" class="hidden" data-option-id="option_referer"></div>
</form>
</div>

<div data-option="referer" class="hidden" data-option-id="option_referer"></div>
</body>
</html>
86 changes: 86 additions & 0 deletions webextension/options.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,91 @@
// Some helper code for integrating more nicely with `wext-options`
const OPTION_HOOKS = {
"allow": function(option, api) {
function rebuildUI(data) {
let DOMTable = document.getElementById("option_allow_display");

// Clear current table entries
let range = document.createRange();
range.selectNodeContents(DOMTable);
range.deleteContents();

// Add all table entries from data
for(let entry of data.split(/\s+/)) {
let source, destination;
if(entry.includes(">")) {
[source, destination] = entry.split(">", 2);
} else {
[source, destination] = ["*", entry];
}

let DOMRow = document.createElement("tr");
DOMRow.setAttribute("data-source", entry);

let DOMColSource = document.createElement("td");
DOMColSource.appendChild(document.createTextNode(source));
DOMRow.appendChild(DOMColSource);

let DOMColDestination = document.createElement("td");
DOMColDestination.appendChild(document.createTextNode(destination));
DOMRow.appendChild(DOMColDestination);

let DOMColRemove = document.createElement("td");
let DOMBtnRemove = document.createElement("button");
DOMBtnRemove.title = "Remove Item";
DOMBtnRemove.appendChild(document.createTextNode("➖"));
DOMColRemove.appendChild(DOMBtnRemove);
DOMRow.appendChild(DOMColRemove);

DOMTable.appendChild(DOMRow);

DOMBtnRemove.addEventListener("click", (event) => {
// Find the actual data token that caused the clicked row to be generated
let entry = event.target.parentNode.parentNode.getAttribute("data-source");

// Construct new data value without the entry
let value = option.value.split(/\s+/).filter(item => (item !== entry)).join(" ");

// Write the new data value
option.value = value;
option.triggerUserChange();

// Update table
rebuildUI(value);
});
}
}

let DOMEntrySource = document.getElementById("option_allow_new_source");
let DOMEntryDestination = document.getElementById("option_allow_new_destination");
document.getElementById("option_allow_new_form").addEventListener("submit", (event) => {
event.preventDefault();

// Format of the entries has already been validated by the browser 🙂
let value = `${option.value} ${DOMEntrySource.value}>${DOMEntryDestination.value}`;

// Write the new data value
option.value = value;
option.triggerUserChange();

// Update table
rebuildUI(value);

// Clear input fields
DOMEntrySource.value = "";
DOMEntryDestination.value = "";
});


option.onStorageChange.addListener((event) => {
rebuildUI(event.value);
});

api.onReady.addListener((event) => {
rebuildUI(option.value);
});
},


"mode": function(option, api) {
function onChange(event) {
if(event.value === "user") {
Expand Down

0 comments on commit a5f2789

Please sign in to comment.