Added SDK
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
WI.CookiePopover = class CookiePopover extends WI.Popover
|
||||
{
|
||||
constructor(delegate)
|
||||
{
|
||||
super(delegate);
|
||||
|
||||
this._nameInputElement = null;
|
||||
this._valueInputElement = null;
|
||||
this._domainInputElement = null;
|
||||
this._pathInputElement = null;
|
||||
this._sessionCheckboxElement = null;
|
||||
this._expiresInputElement = null;
|
||||
this._httpOnlyCheckboxElement = null;
|
||||
this._secureCheckboxElement = null;
|
||||
this._sameSiteSelectElement = null;
|
||||
|
||||
this._serializedDataWhenShown = null;
|
||||
|
||||
this.windowResizeHandler = this._presentOverTargetElement.bind(this);
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
get serializedData()
|
||||
{
|
||||
if (!this._targetElement)
|
||||
return null;
|
||||
|
||||
let name = this._nameInputElement.value;
|
||||
if (!name)
|
||||
return null;
|
||||
|
||||
let domain = this._domainInputElement.value || this._domainInputElement.placeholder;
|
||||
if (!domain)
|
||||
return null;
|
||||
|
||||
let path = this._pathInputElement.value || this._pathInputElement.placeholder;
|
||||
if (!path)
|
||||
return null;
|
||||
|
||||
let session = this._sessionCheckboxElement.checked;
|
||||
let expires = this._parseExpires();
|
||||
if (!session && isNaN(expires))
|
||||
return null;
|
||||
|
||||
// If a full URL is entered in the domain input, parse it to get just the domain.
|
||||
try {
|
||||
let url = new URL(domain);
|
||||
domain = url.hostname;
|
||||
} catch { }
|
||||
|
||||
if (!path.startsWith("/"))
|
||||
path = "/" + path;
|
||||
|
||||
let data = {
|
||||
name,
|
||||
value: this._valueInputElement.value,
|
||||
domain,
|
||||
path,
|
||||
httpOnly: this._httpOnlyCheckboxElement.checked,
|
||||
secure: this._secureCheckboxElement.checked,
|
||||
sameSite: this._sameSiteSelectElement.value,
|
||||
};
|
||||
|
||||
if (session)
|
||||
data.session = true;
|
||||
else
|
||||
data.expires = expires;
|
||||
|
||||
if (JSON.stringify(data) === JSON.stringify(this._serializedDataWhenShown))
|
||||
return null;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
show(cookie, targetElement, preferredEdges, options = {})
|
||||
{
|
||||
console.assert(!cookie || cookie instanceof WI.Cookie, cookie);
|
||||
console.assert(targetElement instanceof Element, targetElement);
|
||||
console.assert(Array.isArray(preferredEdges), preferredEdges);
|
||||
|
||||
this._targetElement = targetElement;
|
||||
this._preferredEdges = preferredEdges;
|
||||
|
||||
function formatDate(date) {
|
||||
function pad(number) {
|
||||
return String(number).padStart(2, "0");
|
||||
}
|
||||
return [
|
||||
date.getFullYear(),
|
||||
"-",
|
||||
pad(date.getMonth() + 1),
|
||||
"-",
|
||||
pad(date.getDate()),
|
||||
"T",
|
||||
pad(date.getHours()),
|
||||
":",
|
||||
pad(date.getMinutes()),
|
||||
":",
|
||||
pad(date.getSeconds()),
|
||||
].join("");
|
||||
}
|
||||
|
||||
let data = {};
|
||||
if (cookie) {
|
||||
data.name = cookie.name;
|
||||
data.value = cookie.value;
|
||||
data.domain = cookie.domain;
|
||||
data.path = cookie.path;
|
||||
data.expires = formatDate(cookie.expires || this._defaultExpires());
|
||||
data.session = cookie.session;
|
||||
data.httpOnly = cookie.httpOnly;
|
||||
data.secure = cookie.secure;
|
||||
data.sameSite = cookie.sameSite;
|
||||
} else {
|
||||
let urlComponents = WI.networkManager.mainFrame.mainResource.urlComponents;
|
||||
data.name = "";
|
||||
data.value = "";
|
||||
data.domain = urlComponents.host;
|
||||
data.path = urlComponents.path;
|
||||
data.expires = formatDate(this._defaultExpires());
|
||||
data.session = true;
|
||||
data.httpOnly = false;
|
||||
data.secure = false;
|
||||
data.sameSite = WI.Cookie.SameSiteType.None;
|
||||
}
|
||||
|
||||
let popoverContentElement = document.createElement("div");
|
||||
popoverContentElement.className = "cookie-popover-content";
|
||||
|
||||
let tableElement = popoverContentElement.appendChild(document.createElement("table"));
|
||||
|
||||
function createRow(id, label, editorElement) {
|
||||
let domId = `cookie-popover-${id}-editor`;
|
||||
|
||||
let rowElement = tableElement.appendChild(document.createElement("tr"));
|
||||
|
||||
let headerElement = rowElement.appendChild(document.createElement("th"));
|
||||
|
||||
let labelElement = headerElement.appendChild(document.createElement("label"));
|
||||
labelElement.setAttribute("for", domId);
|
||||
labelElement.textContent = label;
|
||||
|
||||
let dataElement = rowElement.appendChild(document.createElement("td"));
|
||||
|
||||
editorElement.id = domId;
|
||||
dataElement.appendChild(editorElement);
|
||||
|
||||
if (id === options.focusField) {
|
||||
setTimeout(() => {
|
||||
editorElement.focus();
|
||||
editorElement.select?.();
|
||||
});
|
||||
}
|
||||
|
||||
return {rowElement};
|
||||
}
|
||||
|
||||
let boundHandleInputKeyDown = this._handleInputKeyDown.bind(this);
|
||||
|
||||
function createInputRow(id, label, type, value) {
|
||||
let inputElement = document.createElement("input");
|
||||
inputElement.type = type;
|
||||
|
||||
if (type === "checkbox")
|
||||
inputElement.checked = value;
|
||||
else {
|
||||
if (cookie)
|
||||
inputElement.value = value;
|
||||
inputElement.placeholder = value;
|
||||
inputElement.spellcheck = false;
|
||||
inputElement.addEventListener("keydown", boundHandleInputKeyDown);
|
||||
}
|
||||
|
||||
let rowElement = createRow(id, label, inputElement).rowElement;
|
||||
|
||||
return {inputElement, rowElement};
|
||||
}
|
||||
|
||||
this._nameInputElement = createInputRow("name", WI.UIString("Name"), "text", data.name).inputElement;
|
||||
this._nameInputElement.required = true;
|
||||
|
||||
this._valueInputElement = createInputRow("value", WI.UIString("Value"), "text", data.value).inputElement;
|
||||
|
||||
this._domainInputElement = createInputRow("domain", WI.unlocalizedString("Domain"), "text", data.domain).inputElement;
|
||||
|
||||
this._pathInputElement = createInputRow("path", WI.unlocalizedString("Path"), "text", data.path).inputElement;
|
||||
|
||||
this._sessionCheckboxElement = createInputRow("session", WI.unlocalizedString("Session"), "checkbox", data.session).inputElement;
|
||||
|
||||
let expiresInputRow = createInputRow("expires", WI.unlocalizedString("Expires"), "datetime-local", data.expires);
|
||||
this._expiresInputElement = expiresInputRow.inputElement;
|
||||
this._expiresInputElement.step = 1; // Causes the seconds field to be shown.
|
||||
this._expiresInputElement.addEventListener("input", (event) => {
|
||||
this._expiresInputElement.classList.toggle("invalid", isNaN(this._parseExpires()));
|
||||
});
|
||||
|
||||
this._httpOnlyCheckboxElement = createInputRow("http-only", WI.unlocalizedString("HttpOnly"), "checkbox", data.httpOnly).inputElement;
|
||||
|
||||
this._secureCheckboxElement = createInputRow("secure", WI.unlocalizedString("Secure"), "checkbox", data.secure).inputElement;
|
||||
|
||||
this._sameSiteSelectElement = document.createElement("select");
|
||||
for (let sameSiteType of Object.values(WI.Cookie.SameSiteType)) {
|
||||
let optionElement = this._sameSiteSelectElement.appendChild(document.createElement("option"));
|
||||
optionElement.value = sameSiteType;
|
||||
optionElement.textContent = WI.Cookie.displayNameForSameSiteType(sameSiteType);
|
||||
}
|
||||
this._sameSiteSelectElement.value = data.sameSite;
|
||||
createRow("same-site", WI.unlocalizedString("SameSite"), this._sameSiteSelectElement);
|
||||
|
||||
let toggleExpiresRow = () => {
|
||||
expiresInputRow.rowElement.hidden = this._sessionCheckboxElement.checked;
|
||||
|
||||
this.update();
|
||||
};
|
||||
|
||||
this._sessionCheckboxElement.addEventListener("change", (event) => {
|
||||
toggleExpiresRow();
|
||||
});
|
||||
|
||||
toggleExpiresRow();
|
||||
|
||||
this._serializedDataWhenShown = this.serializedData;
|
||||
|
||||
this.content = popoverContentElement;
|
||||
this._presentOverTargetElement();
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_presentOverTargetElement()
|
||||
{
|
||||
if (!this._targetElement)
|
||||
return;
|
||||
|
||||
let targetFrame = WI.Rect.rectFromClientRect(this._targetElement.getBoundingClientRect());
|
||||
this.present(targetFrame.pad(2), this._preferredEdges);
|
||||
}
|
||||
|
||||
_defaultExpires()
|
||||
{
|
||||
return new Date(Date.now() + (1000 * 60 * 60 * 24)); // one day in the future
|
||||
}
|
||||
|
||||
_parseExpires()
|
||||
{
|
||||
let timestamp = Date.parse(this._expiresInputElement.value || this._expiresInputElement.placeholder);
|
||||
if (timestamp < Date.now())
|
||||
return NaN;
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
_handleInputKeyDown(event)
|
||||
{
|
||||
if (event.key === "Enter" || event.key === "Esc")
|
||||
this.dismiss();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user