Js saving dictionaries in localStorage not working [duplicate] - javascript

Is this possible to insert to localstorage or is there other way to store this?
$('#pass_to_score').on('click',function(){
var compressed = function(){
$('.whole_wrap_of_editcriteria').css('display','none');
$('#wrappler').css('display','block');
$('#li_addcriteria').css('display','none');
$('#li_menu1').addClass('active');
$('#home').removeClass('active');
$('#menu1').addClass('active');
$('#title_panel').html('Edit criteria scoring');
}
compressed();
localStorage.setItem('compressed', compressed());
//i also try set as JSON.stringify but its undefined
});

I don't know why you'd want that, I would not recommend it, but you can do it using toString.
Store it:
var myFunc = function (){
alert('Hello world!');
};
// Store it as a String
localStorage.setItem('compressedFunc', myFunc.toString());
Later, retrieve it:
var compressedFunc = localStorage.getItem('compressedFunc');
// Convert the String back to a function
var myFunc = eval('(' + compressedFunc + ')');
// Use it
myFunc();

If you have the function encoded in JavaScript, there would be no need to restore it ever from localStorage, as you already have it available.
You cannot JSON encode a function. You could save the source code of the function, and upon retrieval apply eval to it. But as all know, this has certain risks, captured in the phrase "eval is evil".
You could limit that risk a bit, if you would invent an object structure that closely describes what the function should do. In your case, every statement in the function is a method applied to a jQuery selector. This you could represent with the following object:
var compressed = [
{ selector: '.whole_wrap_of_editcriteria', method: 'css', args: ['display', 'none'] },
{ selector: '#wrappler', method: 'css', args: ['display', 'none'] },
{ selector: '#li_addcriteria', method: 'css', args: ['display','none'] },
{ selector: '#li_menu1', method: 'addClass', args: ['active'] },
{ selector: '#home', method: 'removeClass', args: ['active'] },
{ selector: '#menu1', method: 'addClass', args: ['active'] },
{ selector: '#title_panel', method: 'html', args: ['Edit criteria scoring'] }
];
Then your actual function, could take that object as its input, and process it, resulting in the same effect:
var applyInstructions = function(instructions) {
instructions.forEach( cmd => $(cmd.selector)[cmd.method](...cmd.args) );
}
Now, when you want to save this knowledge to localStorage, you only need to store the above constructed object, like so:
// save to localStorage:
localStorage.setItem('compressed', JSON.stringify(compressed));
And after retrieving it, you would execute the generic function on it:
// get from localStorage:
applyInstructions(JSON.parse(localStorage.getItem('compressed')));
This is similar to using eval, but it has the advantage that you can put limits to what can be executed (in applyInstructions). You could for instance check that the method attribute should only be one of the values css, addClass, removeClass, and html, although that last one could be a dangerous one to keep. text would be a better alternative, if possible.
Here is how that safer applyInstructions could look like:
var applyInstructions = function(instructions) {
if (instructions.some(
cmd => ['css','addClass','removeClass','textContent'].indexOf(cmd.method)==-1)) {
throw "Invalid instructions object";
}
instructions.forEach( cmd => $(cmd.selector)[cmd.method](...cmd.args) );
}

Related

JS-Interpreter - changing “this” context

JS-Interpreter is a somewhat well-known JavaScript Interpreter. It has security advantages in that it can completely isolate your code from document and allows you to detect attacks such as infinite loops and memory bombs. This allows you to run externally defined code safely.
I have an object, say o like this:
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
I'd like to be able to run the code in process through JS-Interpreter:
for (let i = 0; i < o.process.length; i++)
interpretWithinContext(o, o.process[i]);
Where interpretWithinContext will create an interpreter using the first argument as the context, i.e. o becomes this, and the second argument is the line of code to run. After running the above code, I would expect o to be:
{
hidden: false,
regex: /^[a-z]+$/i,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: '^[a-z]+$'
}
That is, hidden and regex are now set.
Does anyone know if this is possible in JS-Interpreter?
I’ve spent a while messing around with the JS-Interpreter now, trying to figure out from the source how to place an object into the interpreter’s scope that can be both read and modified.
Unfortunately, the way this library is built, all the useful internal things are minified so we cannot really utilize the internal things and just put an object inside. Attempts to add a proxy object also failed failed since the object just wasn’t used in a “normal” way.
So my original approach to this was to just fall back to providing simple utility functions to access the outside object. This is fully supported by the library and probably the safest way of interacting with it. It does require you to change the process code though, in order to use those functions. But as a benefit, it does provide a very clean interface to communicate with “the outside world”. You can find the solution for this in the following hidden snippet:
function createInterpreter (dataObj) {
function initialize (intp, scope) {
intp.setProperty(scope, 'get', intp.createNativeFunction(function (prop) {
return intp.nativeToPseudo(dataObj[prop]);
}), intp.READONLY_DESCRIPTOR);
intp.setProperty(scope, 'set', intp.createNativeFunction(function (prop, value) {
dataObj[prop] = intp.pseudoToNative(value);
}), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"set('hidden', !get('visible'));",
"set('regex', new RegExp(get('validate'), 'i'));"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
However, after posting above solution, I just couldn’t stop thinking about this, so I dug deeper. As I learned, the methods getProperty and setProperty are not just used to set up the initial sandbox scope, but also as the code is being interpreted. So we can use this to create a proxy-like behavior for our object.
My solution here is based on code I found in an issue comment about doing this by modifying the Interpreter type. Unfortunately, the code is written in CoffeeScript and also based on some older versions, so we cannot use it exactly as it is. There’s also still the problem of the internals being minified, which we’ll get to in a moment.
The overall idea is to introduce a “connected object” into the scope which we will handle as a special case inside the getProperty and setProperty to map to our actual object.
But for that, we need to overwrite those two methods which is a problem because they are minified and received different internal names. Fortunately, the end of the source contains the following:
// Preserve top-level API functions from being pruned/renamed by JS compilers.
// …
Interpreter.prototype['getProperty'] = Interpreter.prototype.getProperty;
Interpreter.prototype['setProperty'] = Interpreter.prototype.setProperty;
So even if a minifier mangles the names on the right, it won’t touch the ones on the left. So that’s how the author made particular functions available for public use. But we want to overwrite them, so we cannot just overwrite the friendly names, we also need to replace the minified copies! But since we have a way to access the functions, we can also search for any other copy of them with a mangled name.
So that’s what I’m doing in my solution at the beginning in patchInterpreter: Define the new methods we’ll overwrite the existing ones with. Then, look for all the names (mangled or not) that refer to those functions, and replace them all with the new definition.
In the end, after patching the Interpreter, we just need to add a connected object into the scope. We cannot use the name this since that’s already used, but we can just choose something else, for example o:
function patchInterpreter (Interpreter) {
const originalGetProperty = Interpreter.prototype.getProperty;
const originalSetProperty = Interpreter.prototype.setProperty;
function newGetProperty(obj, name) {
if (obj == null || !obj._connected) {
return originalGetProperty.call(this, obj, name);
}
const value = obj._connected[name];
if (typeof value === 'object') {
// if the value is an object itself, create another connected object
return this.createConnectedObject(value);
}
return value;
}
function newSetProperty(obj, name, value, opt_descriptor) {
if (obj == null || !obj._connected) {
return originalSetProperty.call(this, obj, name, value, opt_descriptor);
}
obj._connected[name] = this.pseudoToNative(value);
}
let getKeys = [];
let setKeys = [];
for (const key of Object.keys(Interpreter.prototype)) {
if (Interpreter.prototype[key] === originalGetProperty) {
getKeys.push(key);
}
if (Interpreter.prototype[key] === originalSetProperty) {
setKeys.push(key);
}
}
for (const key of getKeys) {
Interpreter.prototype[key] = newGetProperty;
}
for (const key of setKeys) {
Interpreter.prototype[key] = newSetProperty;
}
Interpreter.prototype.createConnectedObject = function (obj) {
const connectedObject = this.createObject(this.OBJECT);
connectedObject._connected = obj;
return connectedObject;
};
}
patchInterpreter(Interpreter);
// actual application code
function createInterpreter (dataObj) {
function initialize (intp, scope) {
// add a connected object for `dataObj`
intp.setProperty(scope, 'o', intp.createConnectedObject(dataObj), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"o.hidden = !o.visible;",
"o.regex = new RegExp(o.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
And that’s it! Note that while that new implementation does already work with nested objects, it may not work with every type. So you should probably be careful what kind of objects you pass into the sandbox. It’s probably a good idea to create separate and explicitly safe objects with only basic or primitive types.
Have not tried JS-Interpreter. You can use new Function() and Function.prototype.call() to achieve requirement
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
for (let i = 0; i < o.process.length; i++)
console.log(new Function(`return ${o.process[i]}`).call(o));
Hi may be interpretWithinContext look like something like that ?
let interpretWithinContext = (function(o, p){
//in dunno for what you use p because all is on object o
o.hidden = (o.hidden === null) ? false : o.hidden;
o.regex = (o.regex === null) ? '/^[a-z]+$/i' : o.regex;
console.log(o);
return o;
});
https://codepen.io/anon/pen/oGwyra?editors=1111

Using elements within API functions in Nightwatch JS

I have a page object and am creating a command for use in my test file. When I use a WebDriver API command like .elements(), the elements that I created are not passed through and cannot be used in the callback function.
Example code:
var commands = {
command1: function () {
var element1 = "div.some-class"; //I end up doing this
this.api
.elements("css selector", "#element1", function (result) {
return this
.click("#element2");
})
}
}
module.exports = {
url: function() {
return this.launchUrl;
},
elements: {
element1: "div.some-class",
element2: "h2[id=some-id]"
},
commands: [commands]
}
I have noticed that calling .api makes it so you cannot use elements, but is there any way around this? I have been making variables for each of my commands, but I feel like that defeats the purpose of having elements.
to make it more generic inside a custom function u can use:
var objectSelector = this.page.pageobject.elements[elementName]
it should return element1 css: div.some-class
if i gona think about better solution will post it here in a comment

JS method calling from object value

I'm working on an emulator. The task at hand is an incoming request on a certain endpoint. The request may contain 1-4 options in the req.body.options. The basic design idea is that an object contains the options and the corresponding method calls (as some sort of a sub-router).
let dataActions = {
option1: optionMethod(param1, param2),
option2: optionMethod2(param1, param2),
option3: optionMethod3(params),
option4: optionMethod4(params)
}
for (key in req.body.options) {
...
}
The for...in should fire the methods (decoupled in other files) when it finds matching in the request with the dataActions keys. Is there a semantical way, or a detailed design pattern to make this work?
The problem is that you already fire the methods yourself.
let dataActions = {
option1: optionMethod(param1, param2) // <-- this is a function call
}
Doing it this way you assign the result of optionMethod() to option1. The above is effectively shorthand for
let dataActions = {};
dataActions.option1 = optionMethod(param1, param2);
If that helps making it more obvious.
You don't want to call the methods immediately. You want to store them for later use. Either store them directly:
let dataActions = {
option1: optionMethod // <-- this is a function reference
}
...or store a function that calls them in some specific way:
let dataActions = {
option1: function () {
return optionMethod('some', 'parameters');
}
}
now you can use them at a separate time, for example like this
Object.keys(dataActions).filter(a => a in req.body.options).forEach(a => {
var optionMethod = dataActions[a];
optionMethod();
});

protractor property of argument "is not a function"

I'm trying to write protractor tests where in some tests XMLHttpRequest needs to be mocked out. I'm trying to do this by passing an imported xhr-moc to the browser using executeScript. The instance is passed to the browser but methods become uncallable as they become string instances.
E.g.:
it('demo', function() {
var x = mock;
browser.executeScript(function (mock) {
mock.setup()
}, mock)
});
Output:
...
Failed: unknown error: mock.setup is not a function
...
When further investigating:
it('demo', function() {
console.log('from spec: ', typeof mock.setup)
browser.executeScript(function (mock) {
return typeof mock.setup
}, mock)
.then(function(output) {
console.log('from browser:', output)
});
});
Output:
...
Started
from spec: function
from browser: string
.
...
Is there a a sane way to pass this object to the browser without having the methods converted to strings?
Or can I serialize the object before sending and deserialize the object in the script to work around this?
Try using the below code.
it('demo', function() {
var x = mock;
browser.executeScript(function (arguments[0]) {
arguments[0].setup()
}, mock)
});
The parameters that you are passing to executeScript method should be accessed using arguments array.and you can also pass any number of arguments and access it using the index.

Dojo: How to load an object (containing other objects) from JSON?

I have an object model that I want to be able to save. I am going to export it to JSON and then read it back in as JSON.
Saving to JSON is easy. Just use this: JSON.stringify(this).
Loading from JSON isn't as simple.
We can't just use this = JSON.parse(someJson) because the methods wont be attached.
Using something like lang.mixin(this, JSON.parse(someJson)) will get the functions but objects that are
Photo Class:
define([...], function(...){
return declare(null, {
name: ..., // String
url:..., // String
complexProperty:..., // Some other class
someFunction1: function(...){..},
someFunction2: function(...){..},
someFunction2: function(...){..}
}
));
Photo Album Class:
define([...], function(...){
return declare(null, {
photos: [], /* Array of type Photo (see above) */
someOtherProperty: ...,
someOtherProperty: ...,
someFunction1: function(...){..},
someFunction2: function(...){..},
someFunction2: function(...){..},
toJson: function(){
return JSON.stringify(this); // From dojo/json
}
loadFromJson: function(jsonIn){
// How to do this?
},
/* This doesn't work because methods will be overridden */
loadFromJson1: function(jsonIn){
this = JSON.parse(someJson);
},
/* This insures that my methods are kept intact but my childrens methods arn't (ie: the array of photos) */
loadFromJson2: function(jsonIn){
lang.mixin(this, JSON.parse(someJson));
},
/* This seems like an aweful lot of work. Any better ways to do this? */
loadFromJson3: function(jsonIn){
this.someOtherProperty = jsonIn.someOtherProperty;
this.someOtherProperty = jsonIn.someOtherProperty;
foreach(jsonIn.photos: photoJson){
var newPhoto = new Photo();
newPhoto.loadfromJson(photoJson);
this.photos.add(newPhoto);
}
... All other properties set recursively. All things in model now need this method ...
}
}
));
I think you would be better off returning a JSON object that contains just the data you need to serialize, not the whole class. Then your loadFromJson method would be a little easier to implement, and you wont be sending unnecessary data over the network. Example toJson():
toJson: function() {
return JSON.stringify({
photos: this.photos,
someImportantProp: this.someImportantProp,
anotherProp: this.anotherProp
});
}
JSON is not the same thing as a JavaScript object, in fact, it's only a subset. JSON only allows arrays, objects and of course basic types like Strings, booleans, numbers and null. You can find the entire specification here.
If you really want to keep the functions you can use the eval() function, but this is not really recommended, because it indeed parses those functions. If the evaluated content contains malicious input, then that is being executed as well.
For example:
eval("myObj = { getSum: function getSum(a, b) { return a + b; } }");
myObj.getSum(1, 2); // Returns 3
You can better attempt to save the state of the object (name and url for example) and rebuild it once you parse it again, that is what happens in other programming languages as well. For example, if you're serializing/deserializing an object in Java.

Categories

Resources