Negative ranges mess up noUiSlider - javascript

Below is my use of noUiSlider, which I love because of it lacks jQuery. However, the slider's set function seems to be broken whenever I use a range that starts in the negatives. I am assuming it is an actual issue with noUiSlider, but would love to check that I did not make a mistake.
Codepen:
http://codepen.io/anon/pen/avpvVz
Dependency:
https://github.com/leongersen/noUiSlider
HTML:
<div class="slider" start="10" range="-50, 50" step="1"></div>
<br>
<br>
<br>
<div class="slider" start="0, 50" range="-100, 100" step="1"></div>
JS:
var sliders = document.getElementsByClassName('slider');
var countSliderUpdates = 0;
var countSliderUpdatesRan = 0;
function updateTextValue(maxLabel, minLabel) {
return function (values, handle) {
countSliderUpdatesRan = countSliderUpdatesRan + 1;
if (countSliderUpdatesRan > countSliderUpdates) {
maxLabel.parentNode.classList.remove("text--before");
};
if ( handle ) {
maxLabel.value = values[handle];
} else {
minLabel.value = values[handle];
}
}
}
function updateSliderValue(minLabel, maxLabel, slider) {
return function (values, handle) {
maxLabel.parentNode.classList.remove("text--before");
slider.noUiSlider.set([Number(maxLabel.value), Number(minLabel.value)]);
}
}
var styleSliders = function() {
var sliderLabels = [];
var sliderLabelsMin = [];
var sliderLabelsMax = [];
for (var i = 0; i < sliders.length; ++i) {
sliders[i].classList.add("text--before");
var start = sliders[i].getAttribute('start');
var range;
var step = undefined;
if(sliders[i].getAttribute('range')) {
range = JSON.parse('[' + sliders[i].getAttribute('range') + ']');
} else if(start.indexOf(',') > -1) {
range = JSON.parse("[" + start + "]");
} else {
range = [0, Number(start)];
};
console.log(range);
var connect = 'lower';
if (start.indexOf(',') > -1) {
start = JSON.parse("[" + start + "]");
connect = true;
}
if(sliders[i].getAttribute('step')) {
step = Number(sliders[i].getAttribute('step'));
};
noUiSlider.create(sliders[i], {
start: start,
connect: connect,
range: {
'min': range[0],
'max': range[1]
},
step: step,
format: {
to: function ( value ) {
return value;
},
from: function ( value ) {
return value;
}
}
});
if (start.constructor === Array) {
sliderLabelsMin[i] = document.createElement('input');
sliderLabelsMin[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabelsMin[i].className = 'text--dark text--slider';
} else {
sliderLabelsMin[i].className = 'text--light text--slider';
}
sliderLabelsMin[i].title = 'Range Minimum';
sliderLabelsMin[i].placeholder = 'Range Minimum';
sliderLabelsMin[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabelsMin[i]);
sliderLabelsMax[i] = document.createElement('input');
sliderLabelsMax[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabelsMax[i].className = 'text--dark text--right text--slider';
} else {
sliderLabelsMax[i].className = 'text--light text--right text--slider';
}
sliderLabelsMax[i].title = 'Range Maximum';
sliderLabelsMax[i].placeholder = 'Range Maximum';
sliderLabelsMax[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabelsMax[i]);
countSliderUpdates = countSliderUpdates + 2;
sliders[i].noUiSlider.on('update', updateTextValue(sliderLabelsMax[i], sliderLabelsMin[i]));
sliderLabelsMax[i].addEventListener('change', updateSliderValue(sliderLabelsMax[i], sliderLabelsMin[i], sliders[i]));
sliderLabelsMin[i].addEventListener('change', updateSliderValue(sliderLabelsMax[i], sliderLabelsMin[i], sliders[i]));
} else {
sliderLabels[i] = document.createElement('input');
sliderLabels[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabels[i].className = 'text--dark text--slider';
} else {
sliderLabels[i].className = 'text--light text--slider';
}
sliderLabels[i].title = 'Range Amount Choice';
sliderLabels[i].placeholder = 'Range Amount Choice';
sliderLabels[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabels[i]);
countSliderUpdates = countSliderUpdates + 1;
sliders[i].noUiSlider.on('update', updateTextValue(sliderLabels[i], sliderLabels[i]));
sliderLabels[i].addEventListener('change', updateSliderValue(sliderLabels[i], sliderLabels[i], sliders[i]));
}
};
};
styleSliders();

I can confirm your code only works with non-negative slider values.
Though, if you remove the format part in your initialiser it will also work with negative numbers :)
format: {
to: function ( value ) {
return value;
},
from: function ( value ) {
return value;
}
}
Regards,
Frank

Alternatively, if you need the formatting, make sure the 'from' function returns a number. It is passed a string, but if you return a number, it works again with negative values. (The 'to' function is passed a number, but you can let that one return a (formatted) string.
Example:
var useFloat = false;
...
format: {
to: function (value) {
return useFloat ? value.toFixed(1) : value.toFixed(0);
},
from: function (value) {
return useFloat ? parseFloat(value) : parseInt(value);
}
}

Related

JavaScript array has elements but length is zero

I've done some searching around the web and nothing seems to solve my problem. I have the following jQuery code:
function youtube_data_parser(data) {
//---> parse video data - start
var qsToJson = function(qs) {
var res = {};
var pars = qs.split('&');
var kv, k, v;
for (i in pars) {
kv = pars[i].split('=');
k = kv[0];
v = kv[1];
res[k] = decodeURIComponent(v);
}
return res;
}
//---> parse video data - end
var get_video_info = qsToJson(data);
if (get_video_info.status == 'fail') {
return {
status: "error",
code: "invalid_url",
msg: "check your url or video id"
};
} else {
// remapping urls into an array of objects
//--->parse > url_encoded_fmt_stream_map > start
//will get the video urls
var tmp = get_video_info["url_encoded_fmt_stream_map"];
if (tmp) {
tmp = tmp.split(',');
for (i in tmp) {
tmp[i] = qsToJson(tmp[i]);
}
get_video_info["url_encoded_fmt_stream_map"] = tmp;
}
//--->parse > url_encoded_fmt_stream_map > end
//--->parse > player_response > start
var tmp1 = get_video_info["player_response"];
if (tmp1) {
get_video_info["player_response"] = JSON.parse(tmp1);
}
//--->parse > player_response > end
//--->parse > keywords > start
var keywords = get_video_info["keywords"];
if (keywords) {
key_words = keywords.replace(/\+/g, ' ').split(',');
for (i in key_words) {
keywords[i] = qsToJson(key_words[i]);
}
get_video_info["keywords"] = {
all: keywords.replace(/\+/g, ' '),
arr: key_words
};
}
//--->parse > keywords > end
//return data
return {
status: 'success',
raw_data: qsToJson(data),
video_info: get_video_info
};
}
}
function getVideoInfo() {
var get_video_url = $('#ytdlUrl').val();
var get_video_id = getUrlVars(get_video_url)['v'];
var video_arr_final = [];
var ajax_url = "video_info.php?id=" + get_video_id;
$.get(ajax_url, function(d1) {
var data = youtube_data_parser(d1);
var video_data = data.video_info;
var player_info = data.video_info.player_response;
var video_title = player_info.videoDetails.title.replace(/\+/g, ' ');
var fmt_list = video_data.fmt_list.split(',');
var video_thumbnail_url = video_data.thumbnail_url;
var video_arr = video_data.url_encoded_fmt_stream_map;
//create video file array
$.each(video_arr, function(i1, v1) {
var valueToPush = {};
valueToPush.video_url = v1.url;
valueToPush.video_thumbnail_url = video_thumbnail_url;
valueToPush.video_title = video_title;
$.each(fmt_list, function(i2, v2) {
var fmt = v2.split('/');
var fmt_id = fmt[0];
var fmt_quality = fmt[1];
if (fmt_id == v1.itag) {
valueToPush.fmt_id = fmt_id;
valueToPush.fmt_quality = fmt_quality;
}
});
video_arr_final.push(valueToPush);
});
});
return video_arr_final;
}
function getUrlVars(url) {
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
vars[key] = value;
});
return vars;
}
function fillInOptions(ytOptions) {
//console.log(ytOptions);
//alert(ytOptions[0]);
var ytFill = ytOptions;
console.log(ytFill);
//ytFill.forEach(function(i,v) {
var ytdlOptions = $('#ytdlOptions');
ytFill.forEach(function(i,v) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
return true;
}
function showYTDLLoader() {
$('#ytdlInput').fadeOut(1000, function() {
$('#ytdlLoader').fadeIn(500);
});
var options = getVideoInfo();
//console.log(options);
if (fillInOptions(options) == true) {
//do rest
}
}
function showYTDLOptions() {
return true;
}
function startDownload() {
showYTDLLoader();
}
function hideYTDLLoader() {
$('#ytdlLoader').fadeOut(500);
}
function animateCSS(element, animationName, callback) {
const node = $(element);
node.addClass(animationName);
function handleAnimationEnd() {
node.removeClass(animationName);
node.animationend = null;
if (typeof callback === 'function') callback();
}
node.animationend = handleAnimationEnd();
}
When my button is clicked, I call showYTDLLoader() which gets an array of objects from the YouTube API that looks like this:
[
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=22&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&ratebypass=yes&dur=917.768&lmt=1572418007364260&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5535432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRgIhAIp-4gyUTLoXFetbY0ha_YnR7DJqsp_MNjjIxqDdfPZJAiEA_WPd21jgX9broBcigf8rcSEVoJb2_NX7t3XZQqytsSM%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "22",
"fmt_quality": "1280x720"
},
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=18&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&gir=yes&clen=44248820&ratebypass=yes&dur=917.768&lmt=1572416976690256&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5531432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cgir%2Cclen%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIhANTZJlBHFWQWCnfK11yvLiPUV26c6NzvqIMKjDwmsByMAiBUSy0ZJMo4GdHSiRU4xBDDLxLtzwKZAqAKCiB-1aViDQ%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "18",
"fmt_quality": "640x360"
}
]
But when I try and loop through each entry with fillInOptions(), my loop is never completed because the length is apparently zero. However, when I dump the array using console.log() it tells me the length is 2, and displays the above. I need to be able to add each option to my dropdown.
Thankyou!
UPDATE: Added full code, sorry!
It looks like your .forEach() is the root of the problem. The parameters of a forEach are currentValue, index like this: array.forEach(function(currentValue, index) {}); but it looks like you're using them in the opposite way
Try rewriting that iteration to this:
ytFill.forEach(function(v, i) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
Notice the difference in the order of v and i in the parameters.

JavaScript: multiple instances wrong reference to private property

In the fiddle is a "class" I have written to manage navigation over the data model and a test which shows that multiple instances (starting from second) of this "class" are referencing something wrong.
https://jsfiddle.net/btvmnaxc/
(outputs to console)
Expected output would be
[{"name":"xx"}]
[{"name":"yy"}]
But after setting Elements via setElements, in other methods Elements is empty, strangely only after creating the second instance. I could think that setElements overwrites the reference, but why other methods keep this old reference instead of getting a new one from the var.
Could somebody explain this behavior?
P.S. I probably can think on a solution, as packing vars in a property which is an object.
function Pagination() {
var props = {Elements:[], ...}
}
P.S.S
function Pagination() {
var that = this;
var Elements = [0,1];
var Frame = [];
var FrameNumber = 0;
var EntitiesPerFrame = 25;
var FrameChangedCB = [];
this.subscribeFrameChange = function(cb) {
if (typeof cb === "function") {
FrameChangedCB.push(cb);
} else {
throw new Error("Not a function");
}
}
this.setEntitiesPerFrame = function(entities_per_frame) {
entities_per_frame = parseInt(entities_per_frame);
if (entities_per_frame > 0) {
EntitiesPerFrame = entities_per_frame;
while (!this.canDisplayFrame(FrameNumber) && FrameNumber > 0) {
FrameNumber--;
}
calculateFrame();
}
}
frameChanged = function() {
FrameChangedCB.forEach(function(cb) {
cb();
});
}
this.setElements = function(elements) {
if (Array.isArray(elements)) {
Elements = elements;
calculateFrame();
console.log("qq");
} else {
throw new Error("Can only work with arrays");
}
}
this.getStart = function() {
return FrameNumber * EntitiesPerFrame;
}
this.getEnd = function() {
var end = (FrameNumber + 1) * EntitiesPerFrame;
return end > Elements.length ? Elements.length : end;
}
this.getEntitiesPerFrame = function() {
return EntitiesPerFrame;
}
calculateFrame = function() {
var start = that.getStart();
var end = that.getEnd();
if (that.canDisplayFrame(FrameNumber)) {
Frame = Elements.slice(
start,
end
);
frameChanged();
} else {
throw new Error("Boundaries");
}
}
this.canDisplayFrame = function(nr) {
nr = parseInt(nr);
var can = false;
var start = nr * EntitiesPerFrame
var end = (nr + 1) * EntitiesPerFrame;
if (start <= Elements.length && nr >= 0) {
can = true;
}
return can;
}
this.getFrame = function() {
return Frame;
}
this.next = function() {
return this.goto(FrameNumber + 1);
}
this.prev = function() {
return this.goto(FrameNumber - 1);
}
this.goto = function(frame_nr) {
var changed = false;
if (that.canDisplayFrame(frame_nr)) {
FrameNumber = parseInt(frame_nr);
calculateFrame();
changed = true;
}
return changed;
}
this.getLength = function() {
return Elements.length;
}
}
var b = new Pagination();
var a = new Pagination();
a.setElements([{name: 'xx'}]);
b.setElements([{name: 'yy'}]);
console.log(JSON.stringify(a.getFrame()));
console.log(JSON.stringify(b.getFrame()));
This is happening because you are abusing implicit globals.
Your Pagination function contains two places where a function is assigned to an identifier without using var:
calculateFrame = function() {
var start = that.getStart();
var end = that.getEnd();
if (that.canDisplayFrame(FrameNumber)) {
Frame = Elements.slice(
start,
end
);
frameChanged();
} else {
throw new Error("Boundaries");
}
}
This will assign this function to a global variable named calculateFrame and any call to calculateFrame() will be calling whichever of those was assigned last (and therefore be using whatever scope it has access to).
To fix this, use var:
var calculateFrame = function() {
var start = that.getStart();
var end = that.getEnd();
if (that.canDisplayFrame(FrameNumber)) {
Frame = Elements.slice(
start,
end
);
frameChanged();
} else {
throw new Error("Boundaries");
}
}
Or better yet, use a named function declaration:
function calculateFrame() {
var start = that.getStart();
var end = that.getEnd();
if (that.canDisplayFrame(FrameNumber)) {
Frame = Elements.slice(
start,
end
);
frameChanged();
} else {
throw new Error("Boundaries");
}
}
After fixing the two places where you have this issue, the snippet outputs the expected result.
function Pagination() {
var that = this;
var Elements = [0, 1];
var Frame = [];
var FrameNumber = 0;
var EntitiesPerFrame = 25;
var FrameChangedCB = [];
this.subscribeFrameChange = function(cb) {
if (typeof cb === "function") {
FrameChangedCB.push(cb);
} else {
throw new Error("Not a function");
}
}
this.setEntitiesPerFrame = function(entities_per_frame) {
entities_per_frame = parseInt(entities_per_frame);
if (entities_per_frame > 0) {
EntitiesPerFrame = entities_per_frame;
while (!this.canDisplayFrame(FrameNumber) && FrameNumber > 0) {
FrameNumber--;
}
calculateFrame();
}
}
function frameChanged() {
FrameChangedCB.forEach(function(cb) {
cb();
});
}
this.setElements = function(elements) {
if (Array.isArray(elements)) {
Elements = elements;
calculateFrame();
console.log("qq");
} else {
throw new Error("Can only work with arrays");
}
}
this.getStart = function() {
return FrameNumber * EntitiesPerFrame;
}
this.getEnd = function() {
var end = (FrameNumber + 1) * EntitiesPerFrame;
return end > Elements.length ? Elements.length : end;
}
this.getEntitiesPerFrame = function() {
return EntitiesPerFrame;
}
function calculateFrame() {
var start = that.getStart();
var end = that.getEnd();
if (that.canDisplayFrame(FrameNumber)) {
Frame = Elements.slice(
start,
end
);
frameChanged();
} else {
throw new Error("Boundaries");
}
}
this.canDisplayFrame = function(nr) {
nr = parseInt(nr);
var can = false;
var start = nr * EntitiesPerFrame
var end = (nr + 1) * EntitiesPerFrame;
if (start <= Elements.length && nr >= 0) {
can = true;
}
return can;
}
this.getFrame = function() {
return Frame;
}
this.next = function() {
return this.goto(FrameNumber + 1);
}
this.prev = function() {
return this.goto(FrameNumber - 1);
}
this.goto = function(frame_nr) {
var changed = false;
if (that.canDisplayFrame(frame_nr)) {
FrameNumber = parseInt(frame_nr);
calculateFrame();
changed = true;
}
return changed;
}
this.getLength = function() {
return Elements.length;
}
}
var b = new Pagination();
var a = new Pagination();
a.setElements([{
name: 'xx'
}]);
b.setElements([{
name: 'yy'
}]);
console.log(a.getFrame());
console.log(b.getFrame());

element null in Magento

I upgrade magento from 1.8.1 to 1.9.0, and I have a problem with one js file:
TypeError: $(...) is null
$('product_addtocart_form').getElements().each(function(el) {
simple_product_pricing.js (line 1131, col 5)
I think this file is related to the Ayasoftware_SimpleProductPricing, maybe someone can help me to solve this. Before upgrade in 1.8.1 version everything was fine, in 1.9.0 version I have this error.
I will add here the entire js:
/*
Some of these override earlier varien/product.js methods, therefore
varien/product.js must have been included prior to this file.
some of these functions were initially written by Matt Dean ( http://organicinternet.co.uk/ )
*/
Product.Config.prototype.getMatchingSimpleProduct = function(){
var inScopeProductIds = this.getInScopeProductIds();
if ((typeof inScopeProductIds != 'undefined') && (inScopeProductIds.length == 1)) {
return inScopeProductIds[0];
}
return false;
};
/*
Find products which are within consideration based on user's selection of
config options so far
Returns a normal array containing product ids
allowedProducts is a normal numeric array containing product ids.
childProducts is a hash keyed on product id
optionalAllowedProducts lets you pass a set of products to restrict by,
in addition to just using the ones already selected by the user
*/
Product.Config.prototype.getInScopeProductIds = function(optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var allowedProducts = [];
if ((typeof optionalAllowedProducts != 'undefined') && (optionalAllowedProducts.length > 0)) {
allowedProducts = optionalAllowedProducts;
}
for(var s=0, len=this.settings.length-1; s<=len; s++) {
if (this.settings[s].selectedIndex <= 0){
break;
}
var selected = this.settings[s].options[this.settings[s].selectedIndex];
if (s==0 && allowedProducts.length == 0){
allowedProducts = selected.config.allowedProducts;
} else {
allowedProducts = allowedProducts.intersect(selected.config.allowedProducts).uniq();
}
}
//If we can't find any products (because nothing's been selected most likely)
//then just use all product ids.
if ((typeof allowedProducts == 'undefined') || (allowedProducts.length == 0)) {
productIds = Object.keys(childProducts);
} else {
productIds = allowedProducts;
}
return productIds;
};
Product.Config.prototype.getProductIdOfCheapestProductInScope = function(priceType, optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var productIds = this.getInScopeProductIds(optionalAllowedProducts);
var minPrice = Infinity;
var lowestPricedProdId = false;
//Get lowest price from product ids.
for (var x=0, len=productIds.length; x<len; ++x) {
var thisPrice = Number(childProducts[productIds[x]][priceType]);
if (thisPrice < minPrice) {
minPrice = thisPrice;
lowestPricedProdId = productIds[x];
}
}
return lowestPricedProdId;
};
Product.Config.prototype.getProductIdOfMostExpensiveProductInScope = function(priceType, optionalAllowedProducts) {
var childProducts = this.config.childProducts;
var productIds = this.getInScopeProductIds(optionalAllowedProducts);
var maxPrice = 0;
var highestPricedProdId = false;
//Get highest price from product ids.
for (var x=0, len=productIds.length; x<len; ++x) {
var thisPrice = Number(childProducts[productIds[x]][priceType]);
if (thisPrice >= maxPrice) {
maxPrice = thisPrice;
highestPricedProdId = productIds[x];
}
}
return highestPricedProdId;
};
Product.OptionsPrice.prototype.updateSpecialPriceDisplay = function(price, finalPrice) {
var prodForm = $('product_addtocart_form');
jQuery('p.msg').hide();
jQuery('div.price-box').show();
var specialPriceBox = prodForm.select('p.special-price');
var oldPricePriceBox = prodForm.select('p.old-price, p.was-old-price');
var magentopriceLabel = prodForm.select('span.price-label');
if (price == finalPrice) {
//specialPriceBox.each(function(x) {x.hide();});
magentopriceLabel.each(function(x) {x.hide();});
oldPricePriceBox.each(function(x) { x.hide();
// x.removeClassName('old-price');
// x.addClassName('was-old-price');
});
jQuery('.product-shop').removeClass('sale-product') ;
}else{
specialPriceBox.each(function(x) {x.show();});
magentopriceLabel.each(function(x) {x.show();});
oldPricePriceBox.each(function(x) { x.show();
x.removeClassName('was-old-price');
x.addClassName('old-price');
});
jQuery('.product-shop').addClass('sale-product') ;
}
};
//This triggers reload of price and other elements that can change
//once all options are selected
Product.Config.prototype.reloadPrice = function() {
var childProductId = this.getMatchingSimpleProduct();
var childProducts = this.config.childProducts;
var usingZoomer = false;
if(this.config.imageZoomer){
usingZoomer = true;
}
if(childProductId){
var price = childProducts[childProductId]["price"];
var finalPrice = childProducts[childProductId]["finalPrice"];
optionsPrice.productPrice = finalPrice;
optionsPrice.productOldPrice = price;
optionsPrice.reload();
optionsPrice.reloadPriceLabels(true);
optionsPrice.updateSpecialPriceDisplay(price, finalPrice);
if(this.config.updateShortDescription) {
this.updateProductShortDescription(childProductId);
}
if(this.config.updateDescription) {
this.updateProductDescription(childProductId);
}
if(this.config.updateProductName) {
this.updateProductName(childProductId);
}
if(this.config.customStockDisplay) {
this.updateProductAvailability(childProductId);
}
this.showTierPricingBlock(childProductId, this.config.productId);
if (usingZoomer) {
this.showFullImageDiv(childProductId, this.config.productId);
} else {
if(this.config.updateproductimage) {
this.updateProductImage(childProductId);
}
}
} else {
var cheapestPid = this.getProductIdOfCheapestProductInScope("finalPrice");
var price = childProducts[cheapestPid]["price"];
var finalPrice = childProducts[cheapestPid]["finalPrice"];
optionsPrice.productPrice = finalPrice;
optionsPrice.productOldPrice = price;
optionsPrice.reload();
optionsPrice.reloadPriceLabels(false);
if(this.config.updateProductName) {
this.updateProductName(false);
}
if(this.config.updateShortDescription) {
this.updateProductShortDescription(false);
}
if(this.config.updateDescription) {
this.updateProductDescription(false);
}
if(this.config.customStockDisplay) {
this.updateProductAvailability(false);
}
optionsPrice.updateSpecialPriceDisplay(price, finalPrice);
this.showTierPricingBlock(false);
this.showCustomOptionsBlock(false, false);
if (usingZoomer) {
this.showFullImageDiv(false, false);
} else {
if(this.config.updateproductimage) {
this.updateProductImage(false);
}
}
}
};
Product.Config.prototype.updateProductImage = function(productId) {
var imageUrl = this.config.imageUrl;
if(productId && this.config.childProducts[productId].imageUrl) {
imageUrl = this.config.childProducts[productId].imageUrl;
}
if (!imageUrl) {
return;
}
if($('image')) {
$('image').src = imageUrl;
} else {
$$('#product_addtocart_form p.product-image img').each(function(el) {
var dims = el.getDimensions();
el.src = imageUrl;
el.width = dims.width;
el.height = dims.height;
});
}
};
Product.Config.prototype.updateProductName = function(productId) {
var productName = this.config.productName;
if (productId && this.config.ProductNames[productId].ProductName) {
productName = this.config.ProductNames[productId].ProductName;
}
$$('#product_addtocart_form div.product-name h1').each(function(el) {
el.innerHTML = productName;
});
var productSku = this.config.sku ;
if (productId && this.config.childProducts[productId].sku) {
productSku = this.config.childProducts[productId].sku ;
}
jQuery('.sku span').text(productSku) ;
var productDelivery = this.config.delivery;
if (productId && this.config.childProducts[productId].delivery) {
productDelivery = this.config.childProducts[productId].delivery ;
}
jQuery('.delivery-info').html(productDelivery) ;
var productReturns = this.config.returns;
if (productId && this.config.childProducts[productId].returns) {
productReturns = this.config.childProducts[productId].returns ;
}
jQuery('.returns-info').html(productReturns) ;
var productDownloads = this.config.downloads;
if (productId && this.config.childProducts[productId].downloads) {
productDownloads = this.config.childProducts[productId].downloads;
}
if (productDownloads) jQuery('.downloads-info').html(productDownloads) ;
else jQuery('.downloads-info').html('There are no downloads for this product') ;
var productAttribs = this.config.attributesTable;
if (productId && this.config.childProducts[productId].attributesTable) {
productAttribs = this.config.childProducts[productId].attributesTable ;
}
jQuery('.attribs-info').html(productAttribs) ;
decorateTable('product-attribute-specs-table') ;
if (productId && this.config.childProducts[productId].isNew) {
jQuery('.product-image .new-label').show() ;
} else {
jQuery('.product-image .new-label').hide() ;
}
if (productId && this.config.childProducts[productId].isOnSale) {
jQuery('.product-image .sale-label').show() ;
} else {
jQuery('.product-image .sale-label').hide() ;
}
if (productId) jQuery('input[name="pid"]').val(productId) ;
};
Product.Config.prototype.updateProductAvailability = function(productId) {
var stockInfo = this.config.stockInfo;
var is_in_stock = false;
var stockLabel = '';
if (productId && stockInfo[productId]["stockLabel"]) {
stockLabel = stockInfo[productId]["stockLabel"];
stockQty = stockInfo[productId]["stockQty"];
is_in_stock = stockInfo[productId]["is_in_stock"];
}
$$('#product_addtocart_form p.availability span').each(function(el) {
if(is_in_stock) {
$$('#product_addtocart_form p.availability').each(function(es) {
es.removeClassName('availability out-of-stock');
es.addClassName('availability in-stock');
});
el.innerHTML = /*stockQty + ' ' + */stockLabel;
} else {
$$('#product_addtocart_form p.availability').each(function(ef) {
ef.removeClassName('availability in-stock');
ef.addClassName('availability out-of-stock');
});
el.innerHTML = stockLabel;
}
});
};
Product.Config.prototype.updateProductShortDescription = function(productId) {
var shortDescription = this.config.shortDescription;
if (productId && this.config.shortDescriptions[productId].shortDescription) {
shortDescription = this.config.shortDescriptions[productId].shortDescription;
}
$$('#product_addtocart_form div.short-description div.std').each(function(el) {
el.innerHTML = shortDescription;
});
};
Product.Config.prototype.updateProductDescription = function(productId) {
var description = this.config.description;
if (productId && this.config.Descriptions[productId].Description) {
description = this.config.Descriptions[productId].Description;
}
$$('#product_tabs_description_tabbed_contents div.std').each(function(el) {
el.innerHTML = description;
});
};
Product.Config.prototype.updateProductAttributes = function(productId) {
var productAttributes = this.config.productAttributes;
if (productId && this.config.childProducts[productId].productAttributes) {
productAttributes = this.config.childProducts[productId].productAttributes;
}
//If config product doesn't already have an additional information section,
//it won't be shown for associated product either. It's too hard to work out
//where to place it given that different themes use very different html here
console.log(productAttributes) ;
$$('div.product-collateral div.attribs-info').each(function(el) {
el.innerHTML = productAttributes;
decorateTable('product-attribute-specs-table');
});
};
Product.Config.prototype.showCustomOptionsBlock = function(productId, parentId) {
var coUrl = this.config.ajaxBaseUrl + "co/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
if ($('SCPcustomOptionsDiv')==null) {
return;
}
Effect.Fade('SCPcustomOptionsDiv', { duration: 0.5, from: 1, to: 0.5 });
if(productId) {
//Uncomment the line below if you want an ajax loader to appear while any custom
//options are being loaded.
//$$('span.scp-please-wait').each(function(el) {el.show()});
//prodForm.getElements().each(function(el) {el.disable()});
new Ajax.Updater('SCPcustomOptionsDiv', coUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
$$('span.scp-please-wait').each(function(el) {el.hide()});
Effect.Fade('SCPcustomOptionsDiv', { duration: 0.5, from: 0.5, to: 1 });
//prodForm.getElements().each(function(el) {el.enable()});
}
});
} else {
$('SCPcustomOptionsDiv').innerHTML = '';
try{window.opConfig = new Product.Options([]);} catch(e){}
}
};
Product.OptionsPrice.prototype.reloadPriceLabels = function(productPriceIsKnown) {
var priceFromLabel = '';
var prodForm = $('product_addtocart_form');
if (!productPriceIsKnown && typeof spConfig != "undefined") {
priceFromLabel = spConfig.config.priceFromLabel;
}
var priceSpanId = 'configurable-price-from-' + this.productId;
var duplicatePriceSpanId = priceSpanId + this.duplicateIdSuffix;
if($(priceSpanId) && $(priceSpanId).select('span.configurable-price-from-label'))
$(priceSpanId).select('span.configurable-price-from-label').each(function(label) {
label.innerHTML = priceFromLabel;
});
if ($(duplicatePriceSpanId) && $(duplicatePriceSpanId).select('span.configurable-price-from-label')) {
$(duplicatePriceSpanId).select('span.configurable-price-from-label').each(function(label) {
label.innerHTML = priceFromLabel;
});
}
};
//SCP: Forces the 'next' element to have it's optionLabels reloaded too
Product.Config.prototype.configureElement = function(element) {
this.reloadOptionLabels(element);
if(element.value){
this.state[element.config.id] = element.value;
if(element.nextSetting){
element.nextSetting.disabled = false;
this.fillSelect(element.nextSetting);
this.reloadOptionLabels(element.nextSetting);
this.resetChildren(element.nextSetting);
}
}
else {
this.resetChildren(element);
}
this.reloadPrice();
};
//SCP: Changed logic to use absolute price ranges rather than price differentials
Product.Config.prototype.reloadOptionLabels = function(element){
var selectedPrice;
var childProducts = this.config.childProducts;
var stockInfo = this.config.stockInfo;
//Don't update elements that have a selected option
if(element.options[element.selectedIndex].config){
return;
}
for(var i=0;i<element.options.length;i++){
if(element.options[i].config){
var cheapestPid = this.getProductIdOfCheapestProductInScope("finalPrice", element.options[i].config.allowedProducts);
var mostExpensivePid = this.getProductIdOfMostExpensiveProductInScope("finalPrice", element.options[i].config.allowedProducts);
var cheapestFinalPrice = childProducts[cheapestPid]["finalPrice"];
var mostExpensiveFinalPrice = childProducts[mostExpensivePid]["finalPrice"];
var stock = '';
if(cheapestPid == mostExpensivePid ){
if(stockInfo[cheapestPid]["stockLabel"] != '') {
stock = '( ' +stockInfo[cheapestPid]["stockLabel"] + ' )';
}
}
if (this.config.showOutOfStock){
if(this.config.disable_out_of_stock_option ) {
if(!stockInfo[cheapestPid]["is_in_stock"] ) {
if(cheapestPid == mostExpensivePid ){
element.options[i].disabled=true;
var stock = '( ' +stockInfo[cheapestPid]["stockLabel"] + ' )';
}
}
}
}
var tierpricing = childProducts[mostExpensivePid]["tierpricing"];
element.options[i].text = this.getOptionLabel(element.options[i].config, cheapestFinalPrice, mostExpensiveFinalPrice, stock , tierpricing);
}
}
};
Product.Config.prototype.showTierPricingBlock = function(productId, parentId) {
var coUrl = this.config.ajaxBaseUrl + "co/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
if(productId) {
new Ajax.Updater('sppTierPricingDiv', coUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
$$('span.scp-please-wait').each(function(el) {el.hide()});
}
});
} else {
$('sppTierPricingDiv').innerHTML = '';
}
};
//SCP: Changed label formatting to show absolute price ranges rather than price differentials
Product.Config.prototype.getOptionLabel = function(option, lowPrice, highPrice, stock, tierpricing){
var str = option.label;
if(tierpricing > 0 && tierpricing < lowPrice) {
var tierpricinglowestprice = ': As low as (' + this.formatPrice(tierpricing,false) + ')';
} else {
var tierpricinglowestprice = '';
}
if (!this.config.showPriceRangesInOptions) {
return str;
}
if (!this.config.showOutOfStock){
stock = '';
}
lowPrices = this.getTaxPrices(lowPrice);
highPrices = this.getTaxPrices(highPrice);
if (this.config.hideprices) {
if (this.config.showOutOfStock){
return str + ' ' + stock + ' ';
} else {
return str;
}
}
var to = ' ' + this.config.rangeToLabel + ' ';
var separator = ': ( ';
if(lowPrice && highPrice){
if (this.config.showfromprice) {
this.config.priceFromLabel = this.config.priceFromLabel; //'From: ';
}
if (lowPrice != highPrice) {
if (this.taxConfig.showBothPrices) {
str+= separator + this.formatPrice(lowPrices[2], false) + ' (' + this.formatPrice(lowPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str+= to + this.formatPrice(highPrices[2], false) + ' (' + this.formatPrice(highPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str += " ) ";
} else {
str+= separator + this.formatPrice(lowPrices[0], false);
str+= to + this.formatPrice(highPrices[0], false);
str += " ) ";
}
} else {
if (this.taxConfig.showBothPrices) {
str+= separator + this.formatPrice(lowPrices[2], false) + ' (' + this.formatPrice(lowPrices[1], false) + ' ' + this.taxConfig.inclTaxTitle.replace('Tax','VAT') + ')';
str += " ) ";
str += stock;
str += tierpricinglowestprice;
} else {
if(tierpricing == 0 ) {
str+= separator + this.formatPrice(lowPrices[0], false);
str += " ) ";
}
str += tierpricinglowestprice;
str += ' ' + stock;
}
}
}
return str;
};
//SCP: Refactored price calculations into separate function
Product.Config.prototype.getTaxPrices = function(price) {
var price = parseFloat(price);
if (this.taxConfig.includeTax) {
var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
var excl = price - tax;
var incl = excl*(1+(this.taxConfig.currentTax/100));
} else {
var tax = price * (this.taxConfig.currentTax / 100);
var excl = price;
var incl = excl + tax;
}
if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
price = incl;
} else {
price = excl;
}
return [price, incl, excl];
};
//SCP: Forces price labels to be updated on load
//so that first select shows ranges from the start
document.observe("dom:loaded", function() {
//Really only needs to be the first element that has configureElement set on it,
//rather than all.
if (typeof opConfig != "undefined") {
spConfig.reloadPrice();
}
$('product_addtocart_form').getElements().each(function(el) {
if(el.type == 'select-one') {
if(el.options && (el.options.length > 1)) {
el.options[0].selected = true;
spConfig.reloadOptionLabels(el);
}
}
});
});
Thank you
The version 1.5.11 is not compatible w/ Magento 1.9 according to the extension version on Magento connect. Please obtain the newest version of the extension and/or ask the creator to give you support. As far as I can see 1.9 support is support with 1.11.6, released 11th March 2015. The infos on their homepage and Magento connect are different - not good. On the homepage it says Works with Magento 1.9.0.X . tested 15 May 2014.

Convert string to object hierarchy

I have the following string returned from an API and I want to convert it to an object hierarchy using javascript.
The string received is:
"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"
I want to convert it to a javascript object like:
{
paymentInfoList: {
PaymentInfo: [{
receiver: {
amount: 12.0
}
}]
}
}
I could write my own parser but wonder if there is some code already out there.
Update
Based on the answer from #JasonCust here is a parser to parse a full response from the PayPal Adaptive Payments Pay method:
https://github.com/danielflippance/paypal-ap-parser
I don't know of an existing parser that handles that format. Maybe something on Paypal's developer site? If you roll your own you could do so using a recursive function like the example below. I haven't tested it thoroughly but it's a POC that it's easy enough to do.
function setObjVal(obj, paths, val) {
var path;
var arrayInfo;
if (paths.length === 0) {
return val;
}
obj = obj || {};
path = paths.shift();
arrayInfo = path.match(arrayRegExp);
if (arrayInfo) {
path = arrayInfo[1];
if (!Array.isArray(obj[path])) {
obj[path] = [];
}
obj[path][arrayInfo[2]] = setObjVal(obj[path][arrayInfo[2]], paths, val);
}
else {
obj[path] = setObjVal(obj[path], paths, val);
}
return obj;
}
var arrayRegExp = /^(\w+)\((\d+)\)$/;
var input = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var pair = input.split(':').map(function (str) { return str.replace(/"/g, ''); });
var newObj = setObjVal({}, pair[0].split('.'), pair[1]);
function setObjVal(obj, paths, val) {
var path;
var arrayInfo;
if (paths.length === 0) {
return val;
}
obj = obj || {};
path = paths.shift();
arrayInfo = path.match(arrayRegExp);
if (arrayInfo) {
path = arrayInfo[1];
if (!Array.isArray(obj[path])) {
obj[path] = [];
}
obj[path][arrayInfo[2]] = setObjVal(obj[path][arrayInfo[2]], paths, val);
}
else {
obj[path] = setObjVal(obj[path], paths, val);
}
return obj;
}
document.write('<pre>' + JSON.stringify(newObj, null, 4) + '</pre>');
Alternatively if you want to use lodash you could use _.set():
var newObj = _.set({}, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);
var input = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var pair = input.split(':').map(function (str) { return str.replace(/"/g, ''); });
var newObj = _.set({}, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);
document.write('<pre>' + JSON.stringify(newObj, null, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
Since I can't resist a little puzzle, here's a clean recursive solution that works for the input you've given (scroll down and view the snippet for a little playground):
function objectFromExpression(expression, value) {
if (!expression) {
return value;
}
var obj = {};
var matchKeyIdxRest = /^(\w+)(?:\((\d+)\))?(?:\.(.+))?$/;
var matches = expression.match(matchKeyIdxRest);
if (!matches) {
throw new Error('Oops! There\'s a problem with the expression at "' + expression + '"');
}
var key = matches[1];
var idx = matches[2];
var rest = matches[3];
var next = objectFromExpression(rest, value);
if (idx) {
var arr = [];
arr[ parseInt(idx) ] = next;
obj[key] = arr;
} else {
obj[key] = next;
}
return obj;
}
function keyValueExpressionToKeyValue(str) {
var matchKeyVal = /^"([^"]+)":"([^"]+)"$/;
var matches = str.match(matchKeyVal);
if (!matches) {
throw new Error('Oops! Couldn\'t extract key and value from input!');
}
return matches.slice(1);
}
var input = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var keyAndValue = keyValueExpressionToKeyValue(input);
var key = keyAndValue[0]; // => paymentInfoList.paymentInfo(0).receiver.amount
var value = keyAndValue[1]; // => 12.00
objectFromExpression(key, value);
// => { paymentInfoList:
// { paymentInfo:
// [ { receiver:
// { amount: "12.00" }
// }
// ]
// }
// }
function objectFromExpression(expression, value) {
if (!expression) {
return value;
}
var obj = {};
var matchKeyIdxRest = /^(\w+)(?:\((\d+)\))?(?:\.(.+))?$/;
var matches = expression.match(matchKeyIdxRest);
if (!matches) {
throw new Error('Oops! There\'s a problem with the expression at "' + expression + '"');
}
var key = matches[1];
var idx = matches[2];
var rest = matches[3];
var next = objectFromExpression(rest, value);
if (idx) {
var arr = [];
arr[ parseInt(idx) ] = next;
obj[key] = arr;
} else {
obj[key] = next;
}
return obj;
}
function keyValueExpressionToKeyValue(str) {
var matchKeyVal = /^"([^"]+)":"([^"]+)"$/;
var matches = str.match(matchKeyVal);
if (!matches) {
throw new Error('Oops! Couldn\'t extract key and value from input!');
}
return matches.slice(1);
}
var inputEl = document.getElementById('input');
function onKeyUp() {
var outputEl = document.getElementById('output');
var input = inputEl.value.trim();
try {
var keyAndValue = keyValueExpressionToKeyValue(input);
var key = keyAndValue[0];
var value = keyAndValue[1];
var output = objectFromExpression(key, value);
outputEl.value = JSON.stringify(output, null, 2);
} catch (ex) {
outputEl.value = ex.toString();
}
}
inputEl.addEventListener('keyup', onKeyUp);
inputEl.dispatchEvent(new Event('keyup'));
label, textarea, input { display: block; }
label { font-family: sans-serif; }
input, textarea { font-family: monospace; width: 100%; margin-bottom: 1em; }
textarea { height: 15em; }
<label for="input">Input (type to see changes)</label>
<input id="input" value='"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"'/>
<label for="output">Output</label>
<textarea id="output">Click the "Parse!" button!</textarea>

Firefox Addon Development : Detecting non-compatible addons?

Few addons are not compatible with mine, so how to detect their presence and inform the user.
Thanks
OK got it here is how this is done :
function isExtEnabled(){
if(!Application.extensions.has('EXTENSION_ID_HERE')) {
return false;
}
return true;
}
Here is an example from the evil noscript-1.9.2.xpi which modified adblock plugin settings
function MRD(ns) {
this.enabled = ns.getPref("mrd", true);
if (!this.enabled) return;
var c = CC[this.id];
if (c) {
this.ns = ns;
this.c = c.createInstance().wrappedJSObject;
this._w._mrd = this;
var eh = this.c["elemhide"];
eh.watch("url", this._w);
eh.apply();
ns.mrd = this;
ns.initContentPolicy();
} else this.enabled = false;
}
MRD.prototype = {
id: "#mozilla.org/adblockplus;1",
_nobind: "{-moz-binding: none !important}",
_ms: null,
_w: function(p, o, n) {
if (!n) return n;
var mrd = arguments.callee._mrd;
var u = decodeURIComponent(n.spec);
var mm = u.match(/#-moz-document\s+domain[^\)]*?(?:(?:noscript|flashgot|hackademix)\.net|informaction\.com|googlesyndication\.com)[^\}]*\}/g);
if (mm) {
var ns = mrd.ns;
mrd._ms = mm.join('').replace(/(\{[^\{\}]*)\{[^\}]*/g, '$1' + mrd._nobind);
}
/*
var uu = n.spec.split(',');
uu[1] = encodeURIComponent(decodeURIComponent(uu[1]).replace(/#-moz-document\s+domain[^\)]*?(?:(?:noscript|flashgot|hackademix)\.net|informaction\.com|googlesyndication\.com)[^\}]*\}/g, ''));
n.spec = uu.join(',');
*/
mrd.ns.delayExec(function() { mrd.apply(); }, 0);
return n;
},
_dd: function(a, s) {
return "#-moz-document domain(" + a.join("),domain(") + "){" + s + "} ";
},
get _def() {
delete this.__proto__._def;
return this.__proto__._def = this.ns.prefService.getDefaultBranch(this.ns.prefs.root).getCharPref("default");
},
get _wl() {
delete this.__proto__._wl;
return this.__proto__._wl = this._def.match(/\w+[^r].\.n\w+|in\w+on\.c\w+/g).concat(this.ns.getPref("xblHack", "").split(/\s+/));
},
get _wlrx() {
delete this.__proto__._wlrx;
return this.__proto__._wlrx = new RegExp("^(?:[\\w\\-\\.]*\\.)?(?:" + this._wl.join("|").replace(/\./g, "\\.").concat(")$"));
},
get _es() {
delete this.__proto__._es;
try {
var ss = [], lastS = '';
for(var j = 0; j < 5; j++) {
ss.push(lastS += " #k" + j);
}
es = this._dd(this._wl, ss.join(' *,') + ' *' + this._nobind) +
this._dd(this._def.match(/\w+[^r].\.n\w+|\w+on\.c\w+/g), "#a\u0064s, #\u0061ds .ad" + this._nobind);
} catch (e) {
if (this.ns.consoleDump) this.ns.dump("MRD ES Error: " + e);
}
return this.__proto__._es = es;
},
apply: function() {
var ns = this.ns;
for each(var s in [this._es, this._ms]){
if (s) {
ns.updateStyleSheet(s, false);
ns.updateStyleSheet(s, true);
}
}
},
attach: function() {
if (!this.enabled) return false;
try {
var p = this.c.policy;
var ns = this.ns;
var wlrx = this._wlrx;
if (!wlrx) return false;
ns._mrd_shouldLoad = ns.shouldLoad;
ns.shouldLoad = function(ct, cl, ro, ctx, mm, internal) {
if (!internal) try {
var w = ctx && (ctx.defaultView || ctx.ownerDocument && ctx.ownerDocument.defaultView || ctx);
if (w) {
l = w.top.location;
if (!(/^https?/.test(l.protocol) && wlrx.test(l.hostname))) {
var res = p.shouldLoad(ct, cl, ro, ctx, mm, internal);
if (res != CP_OK) return res;
}
}
} catch(e) {
if (ns.consoleDump) ns.dump(e);
}
return ns._mrd_shouldLoad(ct, cl, ro, ctx, mm, internal);
};
} catch(e) {
if (this.ns.consoleDump) this.ns.dump("MRD Attach Error: " + e);
return false;
}
return true;
}
}

Categories

Resources