Unable to get property of undefined or null reference - javascript

This is similar to my last question but the problem is different. I use a separate javascript file for all of my javascript functions. That file is called by my main window, and is also called in a separate instance by my child windows. My code works with every browser except IE 9 and 10. I have not tested earlier versions of IE.
IE says the offending line is window.opener.savetoparent($targetval); My previous code was opener.savetoparent($targetval); and before that I simply made the changes to the parent from the child directly. I have also gone into IE and enabled protected mode as suggested in another article with no change in behavior. Savetoparent() is available to both the child and the parent so I must call it with opener for it to run in the parent.
The error I am getting is : Unable to get property 'savetoparent' of undefined or null reference. Here is the code:
function saveandclose($wintype, $propid) {
switch($wintype) {
case 'ccdetail':
var $targetval = $('#cc-total').val();
var $fieldname = 'closingcoststotal';
break;
}
window.opener.savetoparent($targetval);
closewindow();
}
The safe to parent function is:
function savetoparent($targetval) {
$('#' + $parentloc).val($targetval);
var $name = $('#' + $parentloc).attr("name");
var $rawtargetval = jsstrtonum($targetval);
processrvsave($propertyid, $name, $rawtargetval);
calcrvtotals();
}
Any light you can shed on this would be greatly appreciated.
window is launched like this
if(window.showModalDialog) {
window.showModalDialog($childname + '.php?ploc=' + $parentloc + '&propid=' + $propid, '', 'dialogWidth: ' + $winwidth + 'px; dialogHeight: ' + $winheight + 'px;')
}
else {
window.open($childname + '.php?ploc=' + $parentloc + '&propid=' + $propid, '', 'width=' + $winwidth + ', height=' + $winheight + ', modal=yes');
}

There is no opener in showModalDialog. Use the returnValue
Also there has not been a modal parameter on window.open in many years..
Here is how to use returnValue
if(window.showModalDialog) {
$targetval = window.showModalDialog($childname + '.php?ploc=' + $parentloc + '&propid=' + $propid,
window,
'dialogWidth: ' + $winwidth + 'px; dialogHeight: ' + $winheight + 'px;'))
if(targetval) savetoparent($targetval);
}
else {
window.open($childname + '.php?ploc=' + $parentloc + '&propid=' + $propid, '', 'width=' + $winwidth + ', height=' + $winheight + ', modal=yes');
}
then
function saveandclose($wintype, $propid) {
var $targetval ="";
switch($wintype) {
case 'ccdetail':
$targetval = $('#cc-total').val();
// var $fieldname = 'closingcoststotal'; I do not see this used anywhere
break;
}
if (window.opener) window.opener.savetoparent($targetval);
else returnValue = $targetval;
closewindow();
}

Related

JavaScript and extending 3rd party API

I'm updating my knowledge about JavaScript and I stuck on one lesson task.
I have API that is returning string...
API.workerName = function (worker) {
return worker.firstName + ' ' + worker.lastName;
};
The task is to prefix returning string and not change API, but extend it. I also have to avoid copying & pasting code, because 3rd party code can change. I should re-use it instead.
What I did is change this function after loading API...
API.workerName = function (worker) {
return '(' + worker.position + ') ' + worker.firstName + ' ' + worker.lastName;
};
... but I think I did it wrong.
To extend the method, you should save the old definition and call it from your extension:
API.oldWorkerName = API.workerName;
API.workerName = function(worker) {
return '(' + worker.position + ')' + API.oldWorkerName(worker);
};
Or maybe this is what your lesson is looking for:
API.workerPositionAndName = function(worker) {
return '(' + worker.position + ')' + API.workerName(worker);
};
Another neat way to save the old definition and also make it unavailable to anybody else, would be to do something like this using IIFE to create a closure:
API.workerName = (function() {
var old = API.workerName; // this old version is only available inside your new function
return function(worker) {
return '(' + worker.position + ')' + old(worker);
}
})();
Here's an example:
API = {
workerName: function (worker) {
return worker.firstName + ' ' + worker.lastName;
}
};
API.workerName = (function () {
var old = API.workerName;
return function (worker) {
return '(' + worker.position + ')' + old(worker);
};
})();
alert(API.workerName({firstName: "Joe", lastName: "Blogs", position: "Lackey" }));

ContextMenuItem context function is not executing

I want my context menu item to be visible only if the clicked node is a link i.e. and href is either a magnet link or a torrent link. But item is visible for all the links because context function is not executing, can anybody help why context function is not executing?
Here is the code:
exports.main = function() {
var cm = require("sdk/context-menu");
var contextCode = ' self.on("context", function (node) { '+
' while(node.nodeName!="A") { node = node.parentNode; } '+
' var pat_magnet = /^magnet:/i; ' +
' var pat_torrent = /.torrent$/i; ' +
' if(pat_torrent.test(node.href) || pat_magnet.test(node.href)) { return true; } '+
' else { return false; } '+
' }); ';
var clickCode = ' self.on("click", function(node,data){ '+
' while(node.nodeName!="A") { node = node.parentNode; } '+
' var pat_hash = /[0-9abcdef]{32,40}/i; ' +
' var result = node.href.match(pat_hash); '+
' var hash = "" '
' if(result != null) { hash=result[0]; } '+
' var xhr = new XMLHttpRequest(); '+
' if(hash != "") { '+
' var apiCall = "https://www.furk.net/api/dl/add?api_key=*************&info_hash="+hash; '+
' } '+
' else{ '+
' var apiCall = "https://www.furk.net/api/dl/add?api_key=*************&url="+encodeURI(node.href); '+
' } '+
' xhr.open("GET",apiCall,true); '+
' xhr.onreadystatechange = function(){ if(xhr.readyState = 4) { if (xhr.response.status = "ok") { alert("Torrent added to Furk."); } else { alert("Torrent could not be added to Furk."); } } } '+
' xhr.send(null); '+
' });';
cm.Item({
label: "Add to Furk",
context: cm.SelectorContext("a[href]"),
contentScript: contextCode + clickCode
});
};
Please always post self-containied examples that can be directly tried in the future.
Now back to your problem: The content script actually has a syntax error.
The following line:
' var pat_torrent = /.torrent$/i ' +
lacks a semicolon, and should be:
' var pat_torrent = /.torrent$/i; ' +
The reason automatic semicolon insertion (ASI) does not work here is: The "code" is actually a string that has no newlines in it whatsoever. If there were newlines, then ASI would have worked.
Anway, another reason not to have complex content script inline. Have a look at contentScriptFile.
This error is actually logged, but the presentation sucks. In the Browser Console:
[20:57:51.707] [object Error] (expandable)
In terminal:
console.error: context-magnet:
Message: SyntaxError: missing ; before statement
Here is a fixed, reproducible sample:
var cm = require("sdk/context-menu");
var contextCode = ' self.on("context", function (node) { '+
' while(node.nodeName!="A") { node = node.parentNode; } '+
' var pat_magnet = /^magnet:/i; ' +
' var pat_torrent = /.torrent$/i; ' +
' if(pat_torrent.test(node.href) || pat_magnet.test(node.href)) { return true; } '+
' else { return false; } '+
' }); ';
cm.Item({
label: "magnet test",
context: cm.SelectorContext("a[href]"),
contentScript: contextCode
});
Edit ' var hash = "" ' has the same problem, and there are might be other such errors that I missed skimming this new code.
As I already said, please use contentScriptFile and not contentScript for long-ish scripts.
Another edit
Here is a builder using contentScriptFile, where I also fixed a couple of other errors, the most important of which are:
Use permissions so that the XHR will work.
Correctly set up the XHR to use responseType and overrideMimeType().
Use onload/onerror instead of onreadystatechange.

jQuery "Unexpected token ILLEGAL"

I have two functions, that are for showing and hiding elements by class:
if (typeof showClass != 'function') {
function showClass(trClass, buttonId, hideMessage, showMessage) {
var button = '#' + buttonId;
var value = hideMessage;
$(button).attr("value", value);
$(button).attr("onclick", "hideClass('" + trClass + "', '" + buttonId + "', '" + showMessage + "', '" + hideMessage + ");");
var classToShow = '.' + trClass;
$(classToShow).css('visibility', 'visible');
}
}
if (typeof hideClass != 'function') {
function hideClass(trClass, buttonId, showMessage, hideMessage) {
var button = '#' + buttonId;
var value = showMessage;
$(button).attr("value", value);
$(button).attr("onclick", "showClass('" + trClass + "', '" + buttonId + "', '" + hideMessage + "', '" + showMessage + ");");
var classToHide = '.' + trClass;
$(classToHide).css('visibility', 'hidden');
}
}
showClass works as excepted, but hideClass causes error "Unexpected token ILLEGAL" in Chrome. With FireFox I don't get any errors, but the function doesn't work with either of the browsers. I tried with different editors to find some illegal characters etc., but no luck. What could be the cause for this?
You're apparently trying to set up a toggling button, but it's the most convoluted mess of jQuery and inline event handlers I've ever seen.
Try this:
function setupToggle(trigger, target, hideMessage, showMessage) {
var state = false; // true means button says "show", target is hidden
var $el = $(trigger);
function update() {
$el.attr('value', state ? showMessage : hideMessage);
$(target).css('visibility', state ? 'hidden' : 'visible');
}
update(); // set initial state
$el.on('click', function() {
state = !state; // on click, flick state and refresh
update();
});
}
usage:
setupToggle('#mybutton', '.mytr', 'Hide it', 'Show it');
The code above may require minor tweaks depending on whether the default state is "hidden" or "shown".

Put the validation error text below input field [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I don't really understand Javascript and I tried everything but can't find solution to my problem.
I'm using this plugin for validation, it works perfectly but just one small problem is that the error text it writes keeps displaying next to input field, I want it to show bellow the input field. Anyone can modify this script for that? Thank you very much :)
;(function($, window, document, undefined){
// our plugin constructor
var SimpleValidate = function(elem, options) {
this.elem = elem;
this.$elem = $(elem);
this.options = options;
this.metadata = this.$elem.data('plugin-options');
this.$requiredInputs = this.$elem.find(':input.required');
};
// the plugin prototype
SimpleValidate.prototype = {
defaults: {
errorClass: 'error',
errorText: 'Please fill out this field.',
emailErrorText: 'Please enter a valid E-mail',
errorElement: 'strong',
removeLabelChar: '*',
inputErrorClass: 'input-error',
completeCallback: '',
ajaxRequest: false
},
init: function() {
var self = this;
// Introduce defaults that can be extended either
// globally or using an object literal.
self.config = $.extend({}, self.defaults, self.options, self.metadata);
// What type of error message is it
self.errorMsgType = self.config.errorText.search(/{label}/);
self.emailErrorMsgType = self.config.emailErrorText.search(/{label}/);
self.$elem.on('submit.simpleValidate', $.proxy(self.handleSubmit, self));
return this;
},
checkField: function(index) {
var self = this;
var $field = self.$requiredInputs.eq(index);
var fieldValue = $.trim($field.val());
var labelText = $field.siblings('label').text().replace(self.config.removeLabelChar, '');
var errorMsg = '';
//Check if it's empty or an invalid email and format the error message
if(fieldValue === '') {
errorMsg = self.formatErrorMsg(self.config.errorText, labelText, self.errorMsgType);
self.hasError = true;
} else if($field.hasClass('email')) {
if(!(/^([_a-z0-9-]+)(\.[_a-z0-9-]+)*#([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/.test(fieldValue.toLowerCase()))) {
errorMsg = self.formatErrorMsg(self.config.emailErrorText, labelText, self.emailErrorMsgType);
self.hasError = true;
}
}
//If there is an error, display it
if(errorMsg !== '') {
$field.addClass(self.config.inputErrorClass).after('<' + self.config.errorElement + ' class="' + self.config.errorClass + '">' + errorMsg + '</' + self.config.errorElement + '>');
}
},
formatErrorMsg: function(errorText, labelText, errorMsgType) {
return (errorMsgType > -1 ) ? errorText.replace('{label}', labelText) : errorText;
},
handleSubmit: function(e) {
var self = this;
// We are just starting, so there are no errors yet
this.hasError = false;
// Reset existing displayed errors
self.$elem.find(self.config.errorElement + '.' + self.config.errorClass).remove();
self.$elem.find(':input.' + self.config.inputErrorClass).removeClass(self.config.inputErrorClass);
// Check each field
self.$requiredInputs.each($.proxy(self.checkField, self));
// Don't submit the form if there are errors
if(self.hasError) {
e.preventDefault();
} else if(self.config.completeCallback !== '') { // If there is a callback
self.config.completeCallback(self.$elem);
// If AJAX request
if(self.config.ajaxRequest) {
e.preventDefault();
}
}
}
};
SimpleValidate.defaults = SimpleValidate.prototype.defaults;
$.fn.simpleValidate = function(options) {
return this.each(function() {
new SimpleValidate(this, options).init();
});
};
})( jQuery, window , document );
Add this to your CSS:
.error { display: block; }
Or change ErrorElement to div.
new SimpleValidate(this, {errorElement: 'div'}).init();
just replace
$field.addClass(self.config.inputErrorClass).after('<' + self.config.errorElement + ' class="' + self.config.errorClass + '">' + errorMsg + '</' + self.config.errorElement + '>')
with:
$field.addClass(self.config.inputErrorClass).after('<p><' + self.config.errorElement + ' class="' + self.config.errorClass + '">' + errorMsg + '</' + self.config.errorElement + '></p>')
A simple solution might be to change errorElement: 'strong' to a block element, like errorElement: 'p'. You'll also want to make sure you style the elements properly with CSS.
If you'd like to learn JavaScript, I'd suggest taking a look at Eloquent JavaScript.
When you're calling this, just pass in the parameter : errorElement: 'p'. The default is to use strong, which is an inline element.
Unfortunately, I can not reproduce your code and therefore it is hard for me to say exactly what to do. However, it seems to me you should work around this piece of code:
$field.addClass(self.config.inputErrorClass).after('<' + self.config.errorElement + ' class="' + self.config.errorClass + '">' + errorMsg + '</' + self.config.errorElement + '>');
If I understood right, it adds the error message right after your input. Maybe you can use something like:
$field.addClass(self.config.inputErrorClass).after('<br>').after('<' + self.config.errorElement + ' class="' + self.config.errorClass + '">' + errorMsg + '</' + self.config.errorElement + '>');

How would I detect CSS Transition support on :before pseudo-elements with javascript?

I'm trying to use CSS Transitions with a :before selector and currently the only browser that supports this is Firefox. I can create a jQuery fallback with no problem, but I'm not sure how to do feature detection with a pseudo-element like that.
Here's a JSBin which shows the HTML and CSS that I'm working with.
(... and here's a similar SO question, but about using regular elements.)
Update: wow, even the platform preview of IE10 has support for this, what's up with that webkit?!
(Edit: solutions moved to answer below)
I know the recommendation states that you should use fallbacks and not polyfills, but just between you and me, using unconditional polyfills isn't all that awful for bleeding edge stuff like CSS3.
If you must know the feature status, you could use Modernizr, but if you're using a library anyway you might as well just use Selectivizr and get full CSS support cross browser.
Aha! Here is a very nice fiddle from the Modernizr folks over at github. Basically it checks if the computed style value for a pseudoelement has changed from its original value within a timespan that is shorter than the transition duration. The problem, of course, is the unreliability of using setTimeouts (syncing problems) and the fact that you need to postpone everything until the setTimeout test is complete. Check your console to see whether the browser has pseudoelement transitions or not.
To be fair, upcoming IE10 does support transitions on generated content (tested myself on Windows 8 Enterprise trial).
Actually, I'm sure there is no need for detection of this type of things. Transitions are just slight improvement, not a critical functionality. So it's perfectly OK to have transitions working in more advanced browsers while not having it in less advanced ones.
But if you need to detect it, considering this cannot be reliably detected directly, you could use browser engine detection by testing existence of standard global JS objects. For example, since we know IE10 has support for transitioning generated content, we can quite future-proofly filter IE9 and older IEs with document.all && !window.atob condition. Opera can be detected by testing existence of window.opera, so when Opera will fix this issue, we could use window.opera && !someGlobalObjectAddedInFixedOpera condition to detect older versions. It's possible that WebKit can be detected some similar way.
Thanks to #Asad for digging up some handy code, I was able to come up with a nice solution here's the jQuery version:
$(function() {
var isTransitionSupported = (function (pseudo, transProp, transPropStart, transPropEnd) {
var id = pseudo + transProp + '-' + (new Date()).valueOf(),
prefixes = ['o', 'ms', 'moz', 'webkit'],
prop = "transition: " + transProp + " 99s linear;",
allprops = (function () {
var props = "";
for (var l = prefixes.length; l--;) {
props += "-" + prefixes[l] + "-" + prop;
}
return props + prop;
}()),
$css = $("<style>" +
"#" + id + "{position:absolute;left:-999em;}" +
"#" + id + ":" + pseudo + "{display:block;content:'M';" + transProp + ":" + transPropStart + ";}" +
"#" + id + ".t:" + pseudo + "{" + allprops + transProp + ":" + transPropEnd + ";}" +
"</style>"),
$bct = $('<div id="' + id + '" />');
$css.appendTo("head");
$bct.appendTo("body");
try {
// get style value before any changes
window.getComputedStyle($bct[0], ':' + pseudo).getPropertyValue(transProp);
$bct.addClass("t");
// test style after changes
return (window.getComputedStyle($bct[0], ':' + pseudo).getPropertyValue(transProp) !== transPropEnd);
} catch (e) {}
return false;
}("before", "width", "0px", "1000px"));
});
Here's a version that doesn't use jQuery:
var isTransitionSupported = (function (pseudo, transProp, transPropStart, transPropEnd) {
var ticks = (new Date()).valueOf(),
id = pseudo + transProp + '-' + ticks,
prefixes = ['o', 'ms', 'moz', 'webkit'],
prop = "transition: " + transProp + " 99s linear;",
allprops = (function () {
var props = "";
for (var l = prefixes.length; l--;) {
props += "-" + prefixes[l] + "-" + prop;
}
return props + prop;
}()),
body = document.body || document.createElement('body'),
node = document.createElement('div'),
css = "<style>" +
"#" + id + "{position:absolute;left:-999em;}" +
"#" + id + ":" + pseudo + "{display:block;content:'M';" + transProp + ":" + transPropStart + ";}" +
"#" + id + ".t" + ticks + ":" + pseudo + "{" + allprops + transProp + ":" + transPropEnd + ";}" +
"</style>",
bct = document.createElement('div'),
isSupported = false;
bct.id = id;
node.innerHTML += css;
node.appendChild(bct);
body.appendChild(node);
try {
// get style value before any changes
window.getComputedStyle(bct, ':' + pseudo).getPropertyValue(transProp);
bct.className += "t" + ticks;
// test style after changes
isSupported = (window.getComputedStyle(bct, ':' + pseudo).getPropertyValue(transProp) !== transPropEnd);
} catch (e) {}
node.parentNode.removeChild(node);
return isSupported;
}("before", "width", "0px", "1000px"));
document.documentElement.className += ' ' + (isTransitionSupported ? '' : 'no-') + "pseudo-trans";
Here's all that code in a gist on github, if anyone wants to fork and improve it.

Categories