Compare commits

...

4 Commits

Author SHA1 Message Date
Ray
de36d49fc0 Merge pull request 'release/0.1.0.035' (#1) from release/0.1.0.035 into master
Reviewed-on: #1
2024-02-04 17:12:38 +00:00
Ray
b55b10c7b3 Added hotkey support on Ctrl+Shift+2 and Ctrl+Shift+3 2024-02-01 23:07:51 +00:00
Ray
a39229690c Refactor to separate form-data fro message action 2024-02-01 22:03:49 +00:00
Ray
2b97d44a4f Added support for paste with hidden elements
Added support for no parent form node found
Refactored
2024-02-01 20:31:47 +00:00
3 changed files with 209 additions and 96 deletions

View File

@ -1,15 +1,37 @@
chrome.runtime.onInstalled.addListener(function() { chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({ "id": "copy_form", "title": "Copy Form", "contexts": ["editable"] }); chrome.contextMenus.create({ "id": "copy-form", "title": "Copy Form", "contexts": ["editable"] });
chrome.contextMenus.create({ "id": "paste_form", "title": "Paste Form", "contexts": ["editable"], enabled: false }); chrome.contextMenus.create({ "id": "paste-form", "title": "Paste Form", "contexts": ["editable"], enabled: false });
chrome.contextMenus.create({ "id": "paste-form2", "title": "Paste Form (with Hidden)", "contexts": ["editable"], enabled: false });
}); });
chrome.contextMenus.onClicked.addListener(function(msg, tab) { chrome.contextMenus.onClicked.addListener(function(msg, tab) {
switch (msg.menuItemId) { switch (msg.menuItemId) {
case "copy_form": case "copy-form":
copyFormContextMenu(tab); copyFormContextMenu(tab);
break; break;
case "paste_form": case "paste-form":
pastFormContextMenu(tab); pasteFormContextMenu(tab, false);
break;
case "paste-form2":
pasteFormContextMenu(tab, true);
break;
default: break;
}
});
chrome.commands.onCommand.addListener(function (command) {
switch (command) {
case 'copy-form':
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
copyFormContextMenu(tabs[0]);
});
break;
case 'paste-form':
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
pasteFormContextMenu(tabs[0], false);
});
break; break;
default: break; default: break;
} }
@ -20,23 +42,26 @@ chrome.contextMenus.onClicked.addListener(function(msg, tab) {
function copyFormContextMenu(tab) { function copyFormContextMenu(tab) {
chrome.tabs.sendMessage(tab.id, { action: "copy" }, function(response) { chrome.tabs.sendMessage(tab.id, { action: "copy" }, function(response) {
if (response) {
chrome.storage.local.set({ 'clipboard': JSON.stringify(response) },function() {
chrome.contextMenus.update("paste_form", { enabled: true });
});
} else {
// Reload required
}
});
}
function pastFormContextMenu(tab) {
chrome.storage.local.get('clipboard', function(response) {
try { try {
let msgData = JSON.parse(response.clipboard); chrome.storage.local.set({ 'clipboard': JSON.stringify(response) },function() {
msgData.action = "paste"; chrome.contextMenus.update("paste-form", { enabled: true });
chrome.contextMenus.update("paste-form2", { enabled: true });
chrome.tabs.sendMessage(tab.id, msgData); });
} catch (err) {
// Do nothing
}
});
}
function pasteFormContextMenu(tab, includeHiddenEl) {
chrome.storage.local.get('clipboard', function(response) {
try {
const payload = {
action: (includeHiddenEl === true ? "paste2" : "paste"),
formData: JSON.parse(response.clipboard)
};
chrome.tabs.sendMessage(tab.id, payload);
} catch (err) { } catch (err) {
// Do nothing // Do nothing
} }

View File

@ -1,75 +1,97 @@
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
switch (message.action) {
const parentForm = getParentFormNode(document.activeElement);
if (parentForm == null) {
console.log("Form not found");
return;
}
switch (request.action) {
case "copy": case "copy":
const result = buildFormValueSet(parentForm, "input", "select", "textarea"); const result = copyFormElementValues(document.activeElement);
console.log(result);
sendResponse(result); sendResponse(result);
break; break;
case "paste": case "paste":
delete request.pasteForm; pasteFormElementValues(document.activeElement, message.formData, false);
break;
// console.log(request); case "paste2":
pasteFormElementValues(document.activeElement, message.formData, true);
for (let key in request) {
if (String.isNullOrWhitespace(key)) {
continue;
}
const dataType = checkDataType(request[key]);
if (dataType == "object") {
continue;
}
const foundElements = parentForm.querySelectorAll("[name='" + key + "']");
if (foundElements.length <= 0) {
continue;
}
if (dataType == "array") {
setFormElementValues(foundElements, request[key]);
} else {
for (let x=0; x<foundElements.length; x++) {
setFormElementValue(foundElements[x], request[key]);
}
}
}
break; break;
default: break; default: break;
} }
}); });
/** function copyFormElementValues(el) {
* Check the data type of the value (string, number, array, object). const container = getContainer(el);
*/ if (container == null) {
function checkDataType(value) { writeLog("Form container not found");
if (String.isNullOrUndefined(value)) { return null;
return "null";
} }
if (typeof(value) == "object") { const result = getFormElementValueSet(container, "input", "select", "textarea");
if (Array.isArray(value)) {
return "array"; console.log(result);
return result;
}
function pasteFormElementValues(el, formData, includeHidden) {
if (String.isNullOrUndefined(formData)) {
return;
}
let container = getContainer(el);
if (container == null) {
writeLog("Form container not found");
return;
}
for (let key in formData) {
if (String.isNullOrWhitespace(key)) {
continue;
}
const dataType = Object.getDataType(formData[key]);
if (dataType == "object") {
continue;
}
const foundEls = container.querySelectorAll("[name='" + key + "']");
if (foundEls.length <= 0) {
continue;
}
if (dataType == "array") {
setFormElementValues(foundEls, formData[key], includeHidden);
} else { } else {
return "object"; for (let x=0; x<foundEls.length; x++) {
setFormElementValue(foundEls[x], formData[key], includeHidden);
}
} }
} }
return typeof(value); writeLog("Pasted");
}
/**
* Get node container.
*/
function getContainer(node) {
let result = node;
if (result.nodeName.toLocaleLowerCase() == "iframe") {
writeLog("iFrame found");
result = getIFrameFormNode(document.activeElement);
} else {
result = getParentFormNode(document.activeElement);
if (result == null) {
writeLog("No form found");
result = node.parentNode;
} else {
writeLog("Form found");
}
}
return ((typeof(result) == "undefined") ? null : result);
} }
/** /**
@ -80,10 +102,7 @@ function getParentFormNode(node) {
// Special case, look inside iframe. // Special case, look inside iframe.
if (result.nodeName.toLocaleLowerCase() == "iframe") { if (result.nodeName.toLocaleLowerCase() == "iframe") {
const foundForms = (result.contentDocument || result.contentWindow).getElementsByTagName("form"); return null;
if (foundForms.length > 0) {
return foundForms[0];
}
} }
while (true) { while (true) {
@ -103,9 +122,25 @@ function getParentFormNode(node) {
} }
/** /**
* Push form element value to array. * Get form node in iframe.
*/ */
function buildFormValueSet(form, ...tagNames){ function getIFrameFormNode(node) {
if (node.nodeName.toLocaleLowerCase() != "iframe") {
return null;
}
const foundEls = (node.contentDocument || node.contentWindow).getElementsByTagName("form");
if (foundEls.length <= 0) {
return null;
}
return foundEls[0];
}
/**
* Get form element values.
*/
function getFormElementValueSet(form, ...tagNames){
let result = { }; let result = { };
for (let x=0; x<tagNames.length; x++) { for (let x=0; x<tagNames.length; x++) {
@ -114,17 +149,20 @@ function buildFormValueSet(form, ...tagNames){
for (let i=0; i<els.length; i++) { for (let i=0; i<els.length; i++) {
let newValue = null; let newValue = null;
if (String.isNullOrWhitespace(els[i].name)) {
continue;
}
switch (els[i].type) switch (els[i].type)
{ {
case "hidden":
// Do nothing
break;
case "checkbox": case "checkbox":
newValue = els[i].checked;
break;
case "radio": case "radio":
newValue = els[i].checked; newValue = els[i].checked;
break; break;
// case "hidden":
// continue;
case "submit":
continue;
default: default:
newValue = els[i].value; newValue = els[i].value;
break; break;
@ -136,7 +174,7 @@ function buildFormValueSet(form, ...tagNames){
if (result[els[i].name]) { if (result[els[i].name]) {
// Convert single to array // Convert single to array
if (checkDataType(result[els[i].name]) != "array") { if (Object.getDataType(result[els[i].name]) != "array") {
result[els[i].name] = [result[els[i].name]]; result[els[i].name] = [result[els[i].name]];
} }
@ -153,14 +191,20 @@ function buildFormValueSet(form, ...tagNames){
/** /**
* Set single form element value. * Set single form element value.
*/ */
function setFormElementValue(el, value) { function setFormElementValue(el, value, includeHidden) {
switch (el.type) { switch (el.type) {
case "hidden": case "hidden":
if (includeHidden === true) {
el.value = value;
}
break; break;
case "checkbox": case "checkbox":
case "radio": case "radio":
el.checked = value; el.checked = value;
break; break;
case "submit":
break;
default: default:
el.value = value; el.value = value;
break; break;
@ -170,12 +214,38 @@ function setFormElementValue(el, value) {
/** /**
* Set form element value from an array of values. * Set form element value from an array of values.
*/ */
function setFormElementValues(els, values) { function setFormElementValues(els, values, includeHidden) {
for (let i=0; i<Math.min(els.length, values.length); i++) { for (let i=0; i<Math.min(els.length, values.length); i++) {
setFormElementValue(els[i], values[i]); setFormElementValue(els[i], values[i], includeHidden);
} }
} }
/**
* Write log to console.
*/
function writeLog(message) {
console.log("Form Copypasta > " + message);
}
Object.getDataType = function(value) {
if (String.isNullOrUndefined(value)) {
return "null";
}
if (typeof(value) == "object") {
if (Array.isArray(value)) {
return "array";
} else {
return "object";
}
}
return typeof(value);
};
String.isNullOrUndefined = function(value) { String.isNullOrUndefined = function(value) {
if (typeof (value) == "undefined") { if (typeof (value) == "undefined") {
return true; return true;

View File

@ -2,7 +2,20 @@
"manifest_version": 3, "manifest_version": 3,
"name": "Form Copypasta", "name": "Form Copypasta",
"description": "Copy and paste form element values. Not for distribution. Internal use only. Based on Copy Form (0.0.1.2) by Sam Larison.", "description": "Copy and paste form element values. Not for distribution. Internal use only. Based on Copy Form (0.0.1.2) by Sam Larison.",
"version": "0.1.0.028", "version": "0.1.0.075",
"icons": {
"16": "icon16.png",
"32": "icon32.png",
"48": "icon48.png",
"64": "icon64.png",
"128": "icon128.png"
},
"permissions": [
"activeTab",
"contextMenus",
"storage",
"tabs"
],
"content_scripts": [ "content_scripts": [
{ {
"js": [ "js": [
@ -19,17 +32,22 @@
"service_worker": "background.js", "service_worker": "background.js",
"type": "module" "type": "module"
}, },
"icons": { "commands": {
"16": "icon16.png", "copy-form": {
"32": "icon32.png", "suggested_key": {
"48": "icon48.png", "default": "Ctrl+Shift+2",
"64": "icon64.png", "windows": "Ctrl+Shift+2",
"128": "icon128.png" "mac": "Command+Shift+2"
}, },
"permissions": [ "description": "Copy form"
"activeTab", },
"contextMenus", "paste-form": {
"storage", "suggested_key": {
"tabs" "default": "Ctrl+Shift+3",
] "windows": "Ctrl+Shift+3",
"mac": "Command+Shift+3"
},
"description": "Paste form"
}
}
} }