I am working on a Chrome extension that replaces words on websites with different words.
I allow users to input their own words that they would like to be replaced, and I save these like this:
function storeOptions(){
var words = new Object(); // storageArea.set() method takes an object that contains all the items to be stored. This Object contains those.
$("option").each(function(key,value){ // .each(index, element)
words[value.id] = value.text;
chrome.storage.sync.set(words, function(){console.log("Stored: "+value.text);});
});
}
Before this was implemented I was successfully enabling and disabling the extension with a browseraction that used a setting stored in the same storagearea in a similar way:
chrome.storage.sync.set({"status":"enabled"});
The problem I am facing is that after implementing the option to add words, the status either isn't being stored properly or is affected by the options, as when I try to retrieve it it doesn't have the values "enabled" or "disabled" as shown here:
chrome.storage.sync.get("status", function(result) {
console.log("status: "+result["status"]); // status: status
});
I was thinking that perhaps I could store the words to replace as an array called in a way like:
chrome.storage.sync.set({"words" : words});
And I would then be able to differentiate the two by getting "status" or "words", but that did not work.
How can I store status and the words without them interfering with each other?
The only reason for what you describe to happen is if there is an <option> element with id status and value status (in which case it would overwrite the original status).
In any case, it is (as you suggested) a good idea to "encapsulate" all option-related key-value pairs in an object (not necessarily an array) inside storage.
(Finally, there is no need to store the values one-by-one. It would be more efficient to first create the whole object and then store it with a single call to chrome.storage.sync.set().)
function storeOptions() {
const words = {};
$('option').each((idx, element) => words[element.id] = element.text);
chrome.storage.sync.set({words: words});
}
Now your storage.sync will be looking like this:
{
"status": "enabled",
"words": {
"option_id1": "option_text1",
"option_id2": "option_text2",
...
}
}
You can retrieve the values like this:
// Retrieve the extension status:
chrome.storage.sync.get('status', items => {
const status = items.status;
...
});
// Retrieve the words:
chrome.storage.sync.get('words', items => {
const words = items.words;
Object.keys(words).forEach(key => {
console.log(`Replacing '${key}' with '${words[key]}'...`);
...
});
});
Related
I am really struggling with this:
What I am trying to do is create an array that is stored in chrome.sync with the url of unique pages a user visits. Adding the url to the array works fine - what I am struggling with is how to check if that url already exists in the array. This is what I have currently:
function getURL(array) {
chrome.tabs.query({active: true, lastFocusedWindow: true, currentWindow: true}, tabs => {
let tabUrl = tabs[0].url;
addArr(tabUrl, array);
});
}
function addArr(tabUrl, array) {
array.map((x) => {
let urlCheck = x.url;
console.log(urlCheck);
if(urlCheck != tabUrl) {
array.push(tabUrl);
chrome.storage.sync.set({data: array}, function() {
console.log("added")
});
}
})
}
The annoying thing I can't work out is that it works when I remove anything to do with the the map and only keep the:
array.push(tabUrl);
chrome.storage.sync.set({data: array}, function() {
console.log("added")
});
This makes even less sense because when I inspect the array by inspecting the popup and then looking at console, there is no error only an empty data array. The error that it gives me, however, when I inspect the popup (actually right click on extension) is
Error handling response: TypeError: Cannot read properties of
undefined (reading 'url') at
chrome-extension://jkhpfndgmiimdbmjbajgdnmgembbkmgf/getURL.js:31:30
That getURL.js line 31? That is part of the code that gets the active tab. i.e
let tabUrl = tabs[0].url;
which isn't even in the same function.
Any ideas? I am totally stumped.
Use includes method:
function addArr(tabUrl, array) {
if (!array.includes(tabUrl)) {
array.push(tabUrl);
chrome.storage.sync.set({data: array});
}
}
However, chrome.storage.sync has a limit of 8192 bytes for each value which can only hold in the ballpark of 100 URLs, so you'll have to limit the amount of elements in the array e.g. by using array.splice or use several keys in the storage or use chrome.storage.local. There are also other limits in the sync storage like the frequency of write operations, which you can easily exceed if the user does a lot of navigation. An even better solution is to use IndexedDB with each URL as a separate key so you don't have to rewrite the entire array each time.
I'm working with a Dungeons & Dragons 5e API and want that an especific result be treated in a special way. The user can choose what to search from a range of options, and in only one of them would I need to take care of the answer in a different way. In this option, I get the answer in JSON that contains a 'name' field, which stores a String, but in this specific case this String comes with an acronym, and I would like to transform it into the full name.I'm afraid to just put am 'if' statement in the middle of the code and deal with the situation inefficiently, even more so that I did not find similar situations to have any reference.
This is part of the result of the API I want to handle in a special way:
{"count":6,
"results":[
{"name":"STR",
"url":"http://www.dnd5eapi.co/api/ability-score/1"},
{"name":"DEX",
"url":"http://www.dnd5eapi.co/api/ability-scores2"},
....
]
}
This is how I handle the answer:
fetch(fullAPIURL)
.then(result => result.json())
.then(data => {
let resultContainer = document.getElementById('resultContainer');
//Cleaning the result container from previous results
document.querySelectorAll('#resultContainer article').forEach(container =>
resultContainer.removeChild(container));
spanSearchResult.classList.remove('invisible', 'searchFail');
spanSearchResult.classList.add('searchSucess');
spanSearchResult.innerHTML = `Search returned ${data.count} results`;
for (element of data.results) {
let containerTitle = element.name != undefined ? element.name : element.class;
resultContainer.appendChild(createResultContainer(containerTitle));
}
})
.catch(err => {
spanSearchResult.classList.remove('invisible');
spanSearchResult.classList.add('searchFail');
spanSearchResult.innerHTML = 'Something went wrong! Details in the console';
console.log(err);
});
Is putting a condition in this snippet of code really the most efficient way to solve this situation?
Thanks in advance.
You could just make a lookup call, actually. In fact, that'd be preferable if you ever want to port your application to another language, for example.
Define the following:
var retrieve = (function() {
var items = {
"STR": "Strength",
"DEX": "Dexterity"
};
return function(item) {
return items[item] || item;
}
})();
console.log(retrieve("DEX"));
With this, you can simply call retrieve(element.name) to retrieve its "actual" name. You can add elements to the object to create new translations, and if you ever need to support multiple languages, you can even replace the function entirely.
I'm new to FeathersJS and want to add additional data to the user object after authorization. (I want to access the data with app.get('user').newData)
First I tried to set a value in hook.result.newData, but it doesn't work. I'm only able to change an existing value like email.
module.exports = function(options) {
return function(hook) {
hook.result.households = hook.app.service('households').find({'people.userId': hook.id}).then(household => {
console.log('households: ', household.data);
return household.data;
});
hook.result.email = '!' + hook.result.email + '?'; // this works
hook.result.newData = 'test'; // this doesn't work
};
};
Another approach I tried was modifying the code snippet found here: https://github.com/feathersjs/feathers-hooks/issues/56 but also with no success.
But I'm also not sure how to populate in my case. I want to add objects of another service, which have an array of user ids. And I only want those objects, which contain the own user id among others in the array.
In my cloud code I want to retrieve the first object in the "Messages" class. Then i want to grab some information from that object, send it to another class, and finally delete that object from the "Messages" class i originally pulled it from.
My question is do i need to query the entire "Messages" class just to get the first object in it? I don't want to slow down my app due to inefficient code.
Parse.Cloud.afterSave("sendMessage", function(Parse.Message, response) {
var body = null;
var senderName = null;
var senderId = null;
var randUsers = [];
var query = new.Parse.Query(Parse.Message);
query.find({
success: function(results){
body.push(results[1].get("messageBody"));
senderName.push(results[1].get("senderName"));
senderId.push(results[1].get("senderId"));
response.success(getUsers);
},
error: funtion(error){
response.error("Error");
}
});
});
to avoid confusion: "getUsers" is an arbitrary function call.
To retrieve entry from class, you need the query the table. However, your problem is getting the first record which does not require getting the all record. From your code I can see that you get the first record of result array (result[1] ). You can apply the solution; getting the first record of the class that you want to query. You can do it via two ways; either you can set the limit 1 to your query or you can use the first() method. The Parse.Query JS API link is below;
https://parse.com/docs/js/symbols/Parse.Query.html
Check the limit and first methods.
Hope this helps.
Regards.
Hi guys so i have a form which takes in data like item name, code etc, so when i press the enter button...iv used json stringify and get an alert of what is stored in the local storage. However when i click reset and create a new item it just shows the new item, is there anyway i could store all my items created in local storage...? this is part of my coding. Im a beginner so please excuse if the question is too simple
Thanks
$('#myBox #EnterButton').click(function() {
ItemData = {
'ItemCode' : $('#ItemCode').val(),
'ItemName' : $('#ItemName').val()
};
localStorage.ItemData=JSON.stringify(ItemData);
$('#myBox').slideUp();
});
...
$('#myBox2 #EnterButton').click(function() {
if (localStorage.ItemData) {
alert(localStorage.ItemData);
ItemData = JSON.parse(localStorage.ItemData);
}
if (ItemData.ItemCode) {
$('#myBox #ItemCode').val(ItemData.ItemCode);
}
if (ItemData.ItemName) {
$('#myBox #ItemName').val(ItemData.ItemName);
}
})
and i have declared itemdata as a public variable. Hope its clear. TIA
You have to organize the way ÿou are using localStorage (a getter/setter class might help with maintenance). From your code above, it seems you are always overriding localStorage.ItemData with the values just inserted.
The solution would be for localStorage.Items to be an array and whenever you insert in that array, iterate over it to see if it's not already added (based on itemCode for instance) and override or insert a new item.
I presume this is enough for playing around. A more advanced concept than localStorage and used for slightly different purpuses would be pouchdb - websql in the browser.
Sounds like if you want multiple items to be stored, you should be using an array of itemData objects. You'll then have to parse this (array), and use something like Array.push(newItem) then stringify it again before saving it.
var allItems = localStorage.getItem('ItemData');
if(allItems == null) {
localStorage.setItem('ItemData', JSON.stringify([ItemData]));
} else {
allItems = JSON.parse(allItems);
allItems.push(ItemData);
localStorage.setItem('ItemData', JSON.stringify(allItems));
}