SCRIPT5045: Assignment to read-only properties is not allowed in strict mode - javascript

I'm getting SCRIPT5045: Assignment to read-only properties is not allowed in strict mode in IE 11 (latest Chrome works fine) in reference to the line
A.doc.head = A.doc.getElementsByTagName('HEAD')[0];.
I'm confused on how to fix it. I've included what should be the relevant code below.
(function (win, doc, arg) {
'use strict';
var A = win[arg.prefix] = {
'win': win,
'doc': doc,
'arg': arg,
'stu': {},
'fun': (function () {
return {
init: function () {
var scripts = A.doc.getElementsByTagName('SCRIPT'),
n = scripts.length,
i;
for (i = 0; i < n; i = i + 1) {
if (scripts[i].src.match(A.arg.src)) {
A.arg.script = scripts[i];
A.arg.options = A.fun.options();
break;
}
}
A.doc.head = A.doc.getElementsByTagName('HEAD')[0];
A.fun.structure();
},
// more functions
}())
};
A.fun.init();
}(window, document, {
'prefix': 'accescape_' + new Date().getTime(),
'src': '/widget.js',
'defaults': {
'language': 'en'
}
}));

document.head is a read-only property. If you want to shim it for oldIE, you'd better test for its nonexistence first:
if (!doc.head)
doc.head = doc.getElementsByTagName("head")[0];

Related

Access webpage properties in Share extension

I want to access webpage properties (Title, Meta - description, URL, default image, etc) when user opens Share extension on iOS using javascript file. I am using the following code for javascript (https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW12):
var MyExtensionJavaScriptClass = function() {};
MyExtensionJavaScriptClass.prototype = {
run: function(arguments) {
// Pass the baseURI of the webpage to the extension.
arguments.completionFunction({"url": document.baseURI});
arguments.completionFunction({"host": getHost()});
arguments.completionFunction({"title": document.title});
arguments.completionFunction({"description": getDescription()});
arguments.completionFunction({"image": getImage()});
},
getHost: function() {
var l = document.createElement("a");
l.href = href;
return l.hostname;
},
getDescription: function() {
var metas = document.getElementsByTagName('meta');
for (i=0; i<metas.length; i++) {
if (metas[i].getAttribute("property") == "description") {
return metas[i].getAttribute("content");
}
}
return "";
},
getImage: function() {
// Need to find this out
return "";
},
// Note that the finalize function is only available in iOS.
finalize: function(arguments) {
// arguments contains the value the extension provides in [NSExtensionContext completeRequestReturningItems:completion:].
// In this example, the extension provides a color as a returning item.
document.body.style.backgroundColor = arguments["bgColor"];
}
};
// The JavaScript file must contain a global object named "ExtensionPreprocessingJS".
var ExtensionPreprocessingJS = new MyExtensionJavaScriptClass;
Is this the right way to access Web page properties also what's the best way to fetch the first image in the content.
Any help would be much appreciated.
Here is how i solved this problem.
JS Code:
var MyExtensionJavaScriptClass = function() {};
MyExtensionJavaScriptClass.prototype = {
getDescription: function() {
var metas = document.getElementsByTagName('meta');
for (i=0; i<metas.length; i++) {
if (metas[i].getAttribute("name") == "description") {
return metas[i].getAttribute("content");
}
}
return "";
},
getImage: function() {
var metas = document.getElementsByTagName('meta');
for (i=0; i<metas.length; i++) {
if (metas[i].getAttribute("name") == "og:image" || metas[i].getAttribute("name") == "sailthru.image.full" || metas[i].getAttribute("name") == "twitter:image:src") {
return metas[i].getAttribute("content");
}
}
return "";
},
run: function(arguments) {
// Pass the baseURI of the webpage to the extension.
arguments.completionFunction({"url": document.baseURI, "host": document.location.hostname, "title": document.title, "description": this.getDescription(), "image": this.getImage()});
},
// Note that the finalize function is only available in iOS.
finalize: function(arguments) {
// arguments contains the value the extension provides in [NSExtensionContext completeRequestReturningItems:completion:].
// In this example, the extension provides a color as a returning item.
// document.body.style.backgroundColor = arguments["bgColor"];
}
};
// The JavaScript file must contain a global object named "ExtensionPreprocessingJS".
var ExtensionPreprocessingJS = new MyExtensionJavaScriptClass;
// ExtensionPreprocessingJS.test();
Swift Code:
for item: AnyObject in (self.extensionContext?.inputItems)! {
let inputItem = item as! NSExtensionItem
for provider: AnyObject in inputItem.attachments! {
let itemProvider = provider as! NSItemProvider
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) {
itemProvider.loadItemForTypeIdentifier(kUTTypePropertyList as String, options: nil, completionHandler: { (result: NSSecureCoding?, error: NSError!) -> Void in
if let resultDict = result as? NSDictionary {
self.articleTitle = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["title"] as! String
self.articleHost = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["host"] as! String
self.articleDesc = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["description"] as! String
self.articleImage = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["image"] as! String
self.articleUrl = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["url"] as! String
}
})
}
}
}

Updating values with a function, returning not working

So I am using a function to update my values, but I can't then get them back. I see values don't get updated, but is there any way of saving them as a reference to the return of the function.
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
this.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (mode == "land") {
mode = "water";
}
else if(mode == "water") {
mode = "land";
}
return {
mode: mode
}
}
this.accelerate = function() {
if(this.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(this.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: this.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}
So here I am experiencing problems with changing the mode and the changeMode function expression. Mode in it should refer to this.mode and then I should be able to update the value.
mode and this.mode are not the same. In your functions you are checking/setting values on mode and this.mode, separately.
Either should work fine, as long as you're using one or the other, in the same place, the same way.
Edit
var Amphibia = function (wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
var amphibia = this,
MODES = { LAND : "land", WATER : "water" };
amphibia.getMode = function () { return mode; };
amphibia.setMode = function (val) { mode = val; };
amphibia.changeMode = function () {
amphibia.setMode((mode === MODES.LAND) ? MODES.WATER : MODES.LAND);
};
};
var amphibia = new Amphibia("", "", "", "land");
amphibia.getMode(); // "land"
amphibia.changeMode();
amphibia.getMode(); // "water"
mode is now 100% private, and unique to that instance.
If you don't need it to be, then you can append it to this, if you'd like.
But here's your problem:
var Amphibia = function () {
var amphibia = this,
amphibiaPropeller = new Propeller( );
// mode, getMode, setMode, etc...
amphibia.accelerate = function () {
if (amphibia.getMode() === "water") {
this.speed += amphibiaPropeller.acceleration;
}
};
};
var amphibia = new Amphibia();
var bob = { speed : 0 };
bob.accelerate = amphibia.accelerate;
bob.accelerate();
// if amphibia.mode === "water", bob.speed += amphibiaPropeller.acceleration
bob.speed; // === amphibiaPropeller.acceleration
setTimeout(amphibia.accelerate, 10); // call amphibia.accelerate in ~10ms
// if amphibia.mode === "water", window.speed += amphibiaPropeller.acceleration
window.speed; // === amphibiaPropeller.acceleration
Be consistent in how you refer to things.
Don't mix self and this, unless you intend to get those side-effects...
And unless you have a very, very good reason to do so (like you're building a framework/engine, not the modules/classes of the game/simulation which use the engine; ie: the difference between building jQuery and building something with jQuery), then you should probably avoid doing it.
If you have closure ("private") state that you want to expose to the outside world, all you need is a function that returns that value, and/or one that sets it.
All of a sudden, the differences between self and this and what is which, when, all go away, as long as you are consistent with how you use them, and you know what the value of this is going to be, every time you call the method.
Notice I'm not returning anything...
When I use new, the value of this (amphibia/self) gets returned by default.
If you want to use private values, and return a "Revealing Module" (which is what I typically prefer), then you can simply do this:
var Amphibia = function (mode) {
var getMode = function () { return mode; },
setMode = function (val) { mode = val; },
changeMode = function () {
setMode( mode === "water" ? "land" : "water" );
};
return {
getMode : getMode,
setMode : setMode,
changeMode : changeMode
};
};
var amphibia = new Amphibia("water");
// `new` won't do any harm, but you can also not use it,
// without it saving everything to `window`
amphibia.getMode(); // "water"
amphibia.changeMode();
amphibia.getMode(); // "land"
Or, maybe if you want that to look a little more like a module/component...
return {
mode : { get : getMode, set : setMode, switch : changeMode }
};
var amphibia = Amphibia("land");
amphibia.mode.get(); // "land"
amphibia.mode.switch();
amphibia.mode.get(); // "water"
var bob = { };
bob.switchAmphibiaMode = amphibia.mode.switch;
bob.switchAmphibiaMode();
amphibia.mode.get(); // "land"
setTimeout(amphibia.mode.switch, 10);
setTimeout(function () { console.log(amphibia.mode.get()); }, 20);
// 10ms amphibia.mode.switch();
// 20ms console.log(amphibia.mode.get());
// > "water"
...or whatever other structure you'd like.
You don't need a this at all.
But this is something to be very, very careful with in JavaScript, because the meaning of this changes every time you call a function, and if half of the code uses this and half uses self, you're bound for some surprises.
I managed to find the answer myself! :) So basicly this in the function constructor refers to Amphibia and this in the this.changeMode function expression refers to object window. Therefore we can define a variable self = this; in the constructor, so we can refer to the same thing in the function expression, as in the function. I explained it a bit awful, but here is my fixed code ;)
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
var self = this;
self.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (self.mode == "land") {
self.mode = "water";
}
else if(self.mode == "water") {
self.mode = "land";
}
}
this.accelerate = function() {
if(self.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(self.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: self.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}

namespace aliasing in Javascript

Can someone advise me on below Javascript -
1) How can I use the "Base" variable?
2) In callShowMsg function, a local variable "ns" is used to alias the namespace.
Is it possible to use a global variable to alias the namespace? It will avoid the need to declare local variable in each function.
Thanks in advance.
My code is,
var Base = namespace("MyCo.MyApp.Myprogram");
MyCo.MyApp.Myprogram =
{
showMsg: function (pMsg)
{
alert(pMsg);
},
callShowMsg: function (pMsg)
{
var ns = MyCo.MyApp.Myprogram;
ns.showMsg('Hello');
}
}
something like this: (YUI with some fallback for custom namespace). Though I believe you do not have to "namespace" or reference the obj. Just refer to it as "this".
So, if you are within the obj, you can call the methods like so: this.showMsg('somevalue')
function createNamespace() {
var uniqueNS = "MyCo";
var a = arguments, o, i = 0, j, d, arg,
ns = this,
PERIOD = ".";
// force namespace to MyCo
ns.uniqueNS = ns.uniqueNS || {};
ns = ns.uniqueNS;
for (; i < a.length; i++) {
o = ns; //Reset base object per argument or it will get reused from the last
arg = a[i];
if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
d = arg.split(PERIOD);
for (j = (d[0] == uniqueNS) ? 1 : 0; j < d.length; j++) {
o[d[j]] = o[d[j]] || {};
o = o[d[j]];
}
} else {
o[arg] = o[arg] || {};
o = o[arg]; //Reset base object to the new object so it's returned
}
}
return o;
}
var Base = createNamespace("MyCo.MyApp.Myprogram");
Base =
{
showMsg: function (pMsg)
{
alert(pMsg);
},
callShowMsg: function (pMsg)
{
this.showMsg(pMsg);
}
}
Base.showMsg('ok');
I dont think there is some function like namespace like you wrote above,
You can do something like that:
var MYAPPLICATION = {
calculateVat: function (base) {
return base * 1.21;
},
product: function (price) {
this.price = price;
this.getPrice = function(){
return this.price;
};
},
doCalculations: function () {
var p = new MYAPPLICATION.product(100);
alert(this.calculateVat(p.getPrice()));
}
}
Or If you want to use nested namespaces you can try this:
var MYAPPLICATION = {
MODEL: {
product: function (price) {
this.price = price;
this.getPrice = function(){
return this.price;
};
}
},
LOGIC: {
calculateVat: function (base) {
return base * 1.21;
},
doCalculations: function () {
var p = new MYAPPLICATION.MODEL.product(100);
alert(this.calculateVat(p.getPrice()));
}
}
}
How can I use the "Base" variable?
That is going to depend on what value got returned by the namespace function. This is not a standard JS function and its probably specific to the libraries you are using so I cant answer.
Is it possible to use a global variable to alias the namespace?
Of course.
var ns = {
callShowMsg: function (pMsg)
{
ns.showMsg('Hello');
}
}
MyCo.MyApp.Myprogram = ns;
You can also make ns into a local function instead of a global by putting it inside an initialization functions intead of putting it on the script toplevel. The most common way of doing that is using an immediately invoked anonymous function:
(function(){
var ns = {
callShowMsg: function (pMsg)
{
ns.showMsg('Hello');
}
}
MyCo.MyApp.Myprogram = ns;
}());

Testing for IE7+ javascript plugins

(function (window, undefined){
var _eles = [],
_target, source, mobile, destory;
if (!document.getElementsByClassName) {
document.getElementsByClassName = function (classname) {
var elArray = [];
var tmp = document.getElementsByTagName("*");
var regex = new RegExp("(^|\\s)" + classname + "(\\s|$)");
for (var i = 0; i < tmp.length; i++) {
if (regex.test(tmp[i].className)) {
elArray.push(tmp[i]);
}
}
return elArray;
};
}
//if ((/msie 7/gi).test(navigator.appVersion)) {
// console.log('true')
//}
var uTube = {
init: function (opts) {
var nodes = ["www.youtube.com/watch?v=", "youtu.be/", "www.youtube.com/embed/", "www.youtube.com/v/", "youtube.com/watch?feature"],
vers = opts.version,
i;
switch (vers) {
case "phpbb3":
vers = 'content';
break;
case "phpbb2":
vers = 'postbody';
break;
case "punbb":
vers = 'entry-content';
break;
case "invision":
vers = 'postbody';
break;
}
_target = document.getElementsByClassName('post');
for (i = 0; i < _target.length; i++) {
_eles.push(_target[i].getElementsByClassName(vers));
}
console.log(_eles);
return {
source: function (opt) {
console.log(_eles);
},
mobile: function (opt) {
console.log('we are now' + opt.text);
return {
destroy: function () {
console.log('destroyed');
}
};
}
};
}
};
return (window.utube = window._$ = uTube.init);
})(window);
I am trying to find a way to test my code on browsers that may not support some of my methods. for when I try in IE7 and 8 I get an error saying Unable to get property 'mobile' of undefined or null reference
Code Initiation looks like this:
_$({
version:"phpbb3"
}).mobile({text:"mobile version"}).destroy();
Right now the properties are just logging certain things for testing purposes. Though like I said it's not working in IE7 or 8, haven't tested 9 yet until 7 and 8 are done. Is there something in particular that I should change for IE7+ in my code that you can see off hand if not is there a site that can give me a close range of what is wrong?
I think you mean to put break instead of return in the switch blocks.

MVC3 application and javascripts issue

I have the following problem:
A ASP.NET MVC3 application, and in _Layout.cshtml, in header section, I have referenced several javascript scripts, as follows:
<script src="#Url.Content("~/Scripts/app/app.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/app/listEnveloppe.js")" type="text/javascript"></script>
In app.js I have defined App object as follows:
var App = {
init: function () {
if (window.console == undefined) {
window.console = {
log: function () {
var str = '';
for (var i in arguments[0]) {
str += i + ':\t' + arguments[0][i] + '\n';
}
alert(str);
}
};
}
/* ....*/
}
Then App object is referenced in listEnveloppe.js as below
App.listEnveloppe = new Function;
The problem is, this code works on FF and Chrome, but not in IE8
Does anyone knows what can be wrong?
Thank you
Maybe a lack of parenthesis in the Function constructor?
App.listEnveloppe = new Function(); // <----- missing () ?
As that wasn't the case, try declaring (and referring to) App as a property of window. And do it in an agnostic way relative to the order of declaration of the scripts:
// In app.js:
var appInstance = window.App || {};
appInstance.init = function () {
};
// In listEnveloppe.js:
var appInstance = window.App || {};
appInstance.listEnveloppe = new Function();
You have some unclosed parenthesis. Try fixing your javascript:
var App = {
init: function () {
if (window.console == undefined) {
window.console = {
log: function () {
var str = '';
for (var i in arguments[0]) {
str += i + ':\t' + arguments[0][i] + '\n';
}
alert(str);
}
};
}
}
/* ....*/
};

Categories