Javascript workaround for firefox iframe getComputedStyle bug - javascript

I'm trying to use the following workaround for the hidden iframe/getComputedSytle firefox bug 548397.
if (/firefox/i.test(navigator.userAgent)){
window.oldGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = function (element, pseudoElt) {
var t = window.oldGetComputedStyle(element, pseudoElt);
if (t === null) {
return {};
} else{
return t;
}
};
}
However in my case I also need getComputedSytle.getPropertyValue i.e. I get the following error:
TypeError: my_window.getComputedStyle(...).getPropertyValue is not a function
How can I add getPropertyValue to the above workaround?

You can just create an empty function:
if (/firefox/i.test(navigator.userAgent)){
window.oldGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = function (element, pseudoElt) {
var t = window.oldGetComputedStyle(element, pseudoElt);
if (t === null) {
return {
getPropertyValue: function(){}
};
} else{
return t;
}
};
}

I think a better solution would be this one
function setFirefoxPolyfill() {
if (/firefox/i.test(navigator.userAgent)){
window.oldGetComputedStyle = window .getComputedStyle;
window.getComputedStyle = function (element, pseudoElt) {
var t = window.oldGetComputedStyle(element, pseudoElt);
if (t === null) {
return element.style;
} else{
return t;
}
};
}
}
in case of null response you just return element styles with all prototyped methods and fields

Related

Chain delayed function using vanilla Javascript ES6

How do you implement delay like the jQuery Library? - I know this question has been asked so many times, but haven't seen anyone implement it using async/await or ES6 stylistics. let me know if you have ideas
//create a jquery like library
class DOM {
constructor(selector){
this.elements = [];
if(!selector){
return;
} else if(selector === 'document' || selector === 'window'){
this.elements = [selector];
} else {
this.elements = Array.from(document.querySelectorAll(selector));
}
}
on(){
console.log('on');
return this;
}
get(){
console.log('get');
return this;
}
delay(ms, callback){
//how to implement this? how to chain result of callback onto next chain?
console.log('delay');
const promise = Promise.resolve();
return promise.then(function(resolve) {
setTimeout(function(){
resolve(this);
}, ms);
});
}
}
const $ = function(selector) {
return new DOM(selector);
}
$('document').on().delay(10000).get()
You probably don't need promises or async/await at all, I think you can create a Proxy object that intercepts subsequent call.
The idea is that, when .delay(duration) is called, it'll return a proxy object instead of the class instance. This proxy object will intercept a method call, set time out for duration, then call the method with the original class instance.
class J {
constructor(selector) {
this.$element = document.querySelector(selector)
}
delay(duration) {
const proxy = new Proxy(this, {
get: (target, prop) => {
const f = target[prop]
return (...args) => {
setTimeout(() => {
return f.apply(target, [...args])
}, duration)
// return the class instance again, so subsequent call & delay still works
return this
}
}
})
return proxy
}
text(content) {
this.$element.textContent = content
return this
}
}
const $ = selector => new J(selector)
$('#test').text('hello').delay(1000).text('world')
<div id="test"></div>
You could maintain a queue of functions still to execute on the selected element(s). That way you can allow multiple delays in the chain and also allow the client to stop the action.
A proxy can be used to "decorate" the methods which make sense to be delayed, so that they can be put in the queue instead of executed whenever a timer is still active.
Here is how that could look:
class DOM {
constructor(selector) {
this.elements = typeof selector === "object" ? [selector]
: selector === 'document' || selector === 'window' ? [document]
: Array.from(document.querySelectorAll(selector));
this.delayed = false;
this.queue = [];
const proxy = new Proxy(this, {
get(obj, prop) {
return !["css","show","hide","delay"].includes(prop) || !obj.delayed ? obj[prop]
: function (...args) {
obj.queue.push(() => proxy[prop](...args));
return this;
}
}
});
return proxy;
}
each(cb) {
this.elements.forEach(cb);
return this;
}
css(name, value) {
return this.each(elem => elem.style[name] = value);
}
show() {
return this.css("display", "");
}
hide() {
return this.css("display", "none");
}
on(eventType, cb) {
return this.each(elem => elem.addEventListener(eventType, cb.bind(elem)));
}
delay(ms) {
this.delayed = true;
setTimeout(() => {
this.delayed = false;
while (this.queue.length && !this.delayed) this.queue.shift()();
}, ms);
return this;
}
stop() {
this.queue.length = 0;
return this;
}
}
const $ = selector => new DOM(selector);
const $span = $('#demo').hide();
for (let i = 0; i < 100; i++) {
$span.delay(500).show()
.delay(500).css("color", "red")
.delay(500).css("color", "blue")
.delay(500).hide();
}
$("#stop").on("click", function () {
$span.stop();
$(this).hide();
});
<div>This is a <span id="demo">colorful </span>demo</div>
<button id="stop">Stop</button>

Javascript object not recognizing function

I have a Javascript class defined as below:
function Node(init, parent) {
this.value = init;
this.children = [];
this.updateChildren(this.value);
}
Node.prototype.updateChildren = function(value) {
this.children.push(value);
};
When I run it.. i receive the error,
this.updateChildren() is not defined.
Any clue what I am missing here ?
Full code here :
'use strict';
var millionNumbers = [];
for (var i = 2; i< 1000000; i++) {
if (!millionNumbers[i]) {
millionNumbers[i] = new Node(i, null);
}
}
function Node(init, parent) {
this.value = init;
this.children = [];
if (parent) {
this.parent = parent;
}
var newValue;
if (isEven(this.value)) {
newValue = this.value/2;
} else {
newValue = (this.value * 3) + 1;
}
//whether newValue is 1 or something else, we still have add it to the children list
this.updateChildren(newValue);
if (millionNumbers[newValue]) {
var chainedNode = millionNumbers[newValue];
this.children.concat(chainedNode.children);
}
if (newValue === 1) {
this.endChain();
} else {
new Node(newValue, this);
}
}
Node.prototype.updateChildren = function(value) {
this.children.push(value);
if(this.parent) {
this.parent.updateChildren(value);
}
};
Node.prototype.endChain = function() {
if (!millionNumbers[this.value]) {
millionNumbers[this.value] = this;
this.parent = null;
}
};
function isEven(value) {
if (value % 2 === 0) {
return true;
} else {
return false;
}
}
The for loop instantiates Node objects before Node.prototype.updateChildren is set, so within the Node constructor, this.updateChildren is still undefined.
To fix the problem, just move the for loop to the end of the file.
Also: Best of luck with the Collatz conjecture!
think you are calling these classes without defining them first.
You can try this way:
function updateChildren(value) {
this.children.push(value);
};
function Node(init, parent) {
this.value = init;
this.children = [];
this.updateChildren(value);
}
Node.prototype.updateChildren(value);

Knockotjs Validation. Passing function gives undefined, because of property order inside VM

validation works fine if validation properties are placed after "HasError" property in VM.
In the case that the property placed before HasError I will get "parameters.hasError" as undefined. I think it's because the property "HasError" is not defined to that time.
Is there any solution without changing the order of the properties inside VM to make it work.
Thanks!
self._BusTypeDefault = function(param) {
var ret = param.BusType;
if(typeof(ret)==='undefined') {
ret = '';
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.BusType = ko.observable(self._BusTypeDefault(init)).extend({maxLength: {message: $Resources.PCIBUSError(), maxFieldLength: 255,hasError: self.HasError }});
self._HasErrorDefault = function(param) {
var ret = param.HasError;
if(typeof(ret)==='undefined') {
ret = false;
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.HasError = ko.observable(self._HasErrorDefault(init)).extend({errorAggregation: {}});
ko.extenders.maxLength = function (target, parameters) {
//add some sub-observables to our observable
target.hasMaxLengthError = ko.observable();
target.validationMessageMaxError = ko.observable();
//define a function to do validation
function validate(newValue) {
var preValue = target.hasMaxLengthError();
if (newValue.length >= parameters.maxFieldLength) {
target.hasMaxLengthError(true);
target.validationMessageMaxError(parameters.message || "This field is required");
}
else {
target.hasMaxLengthError(false);
target.validationMessageMaxError("");
}
if (parameters.hasError != null && target.hasMaxLengthError() !== preValue && typeof preValue !== 'undefined') {
parameters.hasError(target.hasMaxLengthError());
}
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
You can use a function to delay the interpretation of hasError:
this.myObservable = ko.observable(1).extend({ myExtender : { hasError: function () { return self.hasError } } });
Then in the extender you'll need to call the function to actually get the observable behind:
ko.extenders.myExtender = function (target, params) {
function validate(newValue) {
alert("New Value: " + newValue + " ; Has Error: " + params.hasError()());
}
target.subscribe(validate);
}
See this example: http://jsfiddle.net/7ywLN/

Is there any method to change the priority of the two assignment methods?

This is an interview questions, Asked to write a Man class to let the following code can run properly:
var me =new Man();
//method one:
me.attr("fullname", "tom");
//method two:
me.fullname = "jim";
console.info("my name is:" + me.attr("fullname"));
/*------[result is]------
my name is:tom
------------------*/
my answer is:
var Man=function(){
};
Man.prototype.attr=function(attr,val){
if(val){
this[attr]=val;
}
else{
return this[attr];
}
}
The results of my code to run is:
/*------[result is]------
my name is:jim
------------------*/
who can help me? thanks
You could make a second dictionary:
function Man() {
this.dictionary = {};
}
Man.prototype.attr = function(attr, val) {
if(arguments.length > 1) {
this.dictionary[attr] = val;
} else {
return this.dictionary[attr];
}
};
You could use a closed variable:
function Man() {
var dictionary = {};
this.attr = function(attr, val) {
if(arguments.length > 1) {
dictionary[attr] = val;
} else {
return dictionary[attr];
}
};
}
You could use a closed fullname variable, and ignore everything except 'fullname':
function Man() {
var fullname;
this.attr = function(attr, val) {
if(attr === 'fullname') {
if(arguments.length > 1) {
fullname = val;
} else {
return fullname;
}
}
};
}
You could also return "tom" every single time, or pretend all the attributes are "fullname", or both. You could ROT13 property names before assigning them. You could add underscores. You could create a property instead that throws away values beginning with "j". The possibilities are limitless, actually.
Use a property to save attributes.
var Man=function(){
this.attributes = {};
};
Man.prototype.attr=function(attr,val){
if(val){
this.attributes[attr] = val;
}
else{
return this.attributes[attr];
}
}

JS: How to return 'undefined' instead of throwing error 'cannot read property x of undefined'

What is the best way to have js return undefined rather than throw an error when a parent property does not exist?
Example
a = {}
b = a.x.y.z
// Error: Cannot read property 'value' of undefined
// Target result: b = undefined
You have to check for the existence of each property:
var b;
if (a.x && a.x.y && a.x.y.z) {
b = a.x.y.z
}
Or, simliar to another poster's "safeGet" function:
var get = function (obj, ns) {
var y = ns.split('.');
for(var i = 0; i < y.length; i += 1) {
if (obj[y[i]]) {
obj = obj[y[i]];
} else {
return;
}
}
return obj;
};
Use:
var b = get(a, 'x.y.z');
try {
a = {}
b = a.x.y.z
}
catch (e) {
b = void 0;
}
I would go for slightly verbose:
var b = ((a.x || {}).y || {}).z
you could write a safeGet helper function, something like:
edited for drilldown as suggested in comments by arcyqwerty
var getter = function (collection, key) {
if (collection.hasOwnProperty(key)) {
return collection[key];
} else {
return undefined;
}
};
var drillDown = function (keys, currentIndex, collection) {
var max = keys.length - 1;
var key = keys[currentIndex];
if (typeof collection === 'undefined') {
return undefined;
}
if (currentIndex === max) {
return getter(collection, key);
} else {
return drillDown(keys, currentIndex + 1,
getter(collection, key));
}
};
var safeGet = function (collection, key) {
if (key.indexOf(".") !== -1) {
return drillDown(key.split("."), 0, collection);
} else {
return getter(collection, key);
}
};
a = { x: 1 };
b = safeGet(a, 'x.y.z');
http://jsfiddle.net/YqdWH/2/

Categories