Testing for IE7+ javascript plugins - javascript

(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.

Related

Why dies JQuery throw a syntax error on compound names? [duplicate]

This question already has answers here:
jQuery dot in ID selector? [duplicate]
(6 answers)
Closed 2 years ago.
I'm working on a legacy web app, that's using JQuery.
There's a place where we're trying to save all of the form data to local storage, before we redirect to a different page, so that we can restore it when we return.
This pattern is working on a number of pages:
$(document).ready(function () {
var searchForm = $('form.full-investigation');
var searchFormElements = searchForm.find(':input');
var saveSearchElements = function saveSearchElements() {
var saveData = [];
searchFormElements.each(function(index, element) {
var item = $(element);
var name = element.name;
var value = item.val();
var type = element.type;
var add = true;
if (type === "checkbox") {
value = element.checked;
} else if (type === "radio") {
if (!element.checked) {
add = false;
}
}
if (add) {
saveData.push({ name: name, value: value });
}
});
var serialized = JSON.stringify(saveData);
sessionStorage.setItem('FullInvestigation_criteria', serialized);
};
var loadSearchElements = function loadSearchElements(serializedForm) {
var foundOne = false;
if (serializedForm) {
var saveData = JSON.parse(serializedForm);
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name;
var value = saveData[i].value;
try {
var element = searchForm.find(':input[name=' + key + ']');
if (element.length > 1) {
for (var j = 0; j < element.length; j++) {
var each = element[j];
var type = each.type;
if (type === 'radio' && each.value === value) {
each.checked = true;
foundOne = true;
}
}
} else {
element.val(value);
if (value)
foundOne = true;
}
} catch (e) {
var msg = e;
}
}
}
return foundOne;
};
$("#redirectbutton").on('click',
function(event) {
try {
saveSearchElements();
} catch (e) {
}
});
var fullInvestigation_criteria = sessionStorage.getItem('FullInvestigation_criteria');
loadSearchElements(fullInvesigation_criteria);
sessionStorage.setItem('FullInvesigation_criteria', '{}');
});
As I said, this is working on a number of pages.
But when I try to use it on a different page, where it had not been used before, I'm getting syntax errors. The problem is that on this new page, saveSearchElements() encounters :input elements with dotted names. E.g., ticketAndMarking.actualnearinter. So we're saving name/value pair with a key of "ticketAndMarking.actualnearinter"
So when we process that key in
And then when we call loadSearchElements, and it processes that key, the line:
var element = searchForm.find(':input[name=' + key + ']');
throws an exception with the message:
Syntax error, unrecognized expression: :input[name=ticketAndMarking.actualnearinter]
I was asking this question for the group, but found the answer before I posted.
So here it is, in case anyone else runs into something similar:
jQuery dot in ID selector?
Having a period in an element name is perfectly acceptable. But JQuery selector syntax requires that they be escaped.
The fix in the code above is simple:
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name.replace(".", "\\.");
var value = saveData[i].value;

Recursive function to traverse grid goes crazy

When the user clicks on one of the blocks in the table ( see screenshot ) I want to find all neighbouring blocks with the same color. I am trying to do this recursively, but if I try it with more than three blocks it sometimes goes crazy and calls itself over and over until the program crashes.
As far as I can see, the objects are added to the array, but somehow my tests fails and the same object is added over and over and over.
Any insight on what the problem might be and how to solve it would be much appriciated!
Here's a screenshot
This is the function that is called when the user clicks on a block:
var $matchArray;
$('.block').click(function () {
$matchArray = [$(this)];
var $colorClass;
if ($(this).hasClass('red')) {
$colorClass = 'red';
} else if ($(this).hasClass('green')) {
$colorClass = 'green';
} else if ($(this).hasClass('blue')) {
$colorClass = 'blue';
} else {
$colorClass = 'error';
}
findAllSameColorNeighbours($(this), $colorClass);
});
And this is the recursive method:
findAllSameColorNeighbours = function ($this, $colorClass) {
$this.css('border-style', 'solid');
//LEFT
var $leftBlock = isLeftBlockSameColor($this, $colorClass);
if ($leftBlock != null) {
if (!(arrayContains($matchArray, $leftBlock))) {
$matchArray.push($leftBlock);
findAllSameColorNeighbours($leftBlock, $colorClass);
}
}
//ABOVE
//same as for LEFT
//RIGHT
//same as for LEFT
//BELOW
//same as for LEFT
}
This is how I find the neighboring cells, as far as I can see these work just fine. I have one for each direction:
isLeftBlockSameColor = function ($block, $color) {
var $this = $block;
var $tr = $this.parent().parent();
var col = $tr.children().index($this.parent().prev());
var $leftBlock = $this.parent().siblings().eq(col).children();
var $blockClassMatch = $leftBlock.hasClass($color);
if ($blockClassMatch) {
return $leftBlock;
}
else {
return null;
}
};
Here are some help methods to find out if the object is already in the array or not. I use the index of the row and cell to create a sort of latitude and longditude thing.
arrayContains = function ($array, $object) {
for (i = 0; i < Array.length; i++) {
if (compareIndex($array[i], $object)) {
say('true');
return true;
}
};
return false;
};
compareIndex = function ($obj1, $obj2) {
if ((getRowIndex($obj1)) === (getRowIndex($obj2)) {
if ((getCellIndex($obj1)) === (getCellIndex($obj2)) {
return true;
} else {
return false;
}
} else {
return false;
}
};
getCellIndex = function ($this) {
var $tr = $this.parent().parent();
var index = $tr.children().index($this.parent());
return index;
};
getRowIndex = function ($this) {
var $tr = $this.parent().parent();
var index = $tr.index();
return index;
};
There is a bug in the arrayContains function. The loop will iterates only once, because Array.length is equals to 1(As I tested with chrome browser, but I don't know why). You should use $array.length instead.
arrayContains = function ($array, $object) {
//for (i = 0; i < Array.length; i++) {
for (i = 0; i < $array.length; i++) {
if (compareIndex($array[i], $object)) {
say('true');
return true;
}
};
return false;
};

Get object caller name by function call JavaScript

I'm writing a piece of code to easily save error logs in an object for debugging.
What I'm trying to achieve is to get the Object name from the function it was called from like so:
var MainObject = {
test : function() {
return MainObject.test.caller;
// When called from MainObject.testcaller,
// it should return MainObject.testcaller.
},
testcaller : function() {
return MainObject.test(); // Should return MainObject.testcaller, Returns own function code.
},
anothercaller : function() {
return MainObject.test(); // Should return MainObject.anothercaller, Returns own function code.
}
}
However when I run this code it returns the function code from MainObject.testcaller.
JSFiddle example
Is there any way this is possible?
Update
After looking at Rhumborl's answer, I discovered that assigning the value through another function would lead it to point back at the function name without the object itself.
Code:
(function (name, func) {
MainObject[name] = func;
})('invalid', function() {
return MainObject.test("blah");
});
// This now points at invalid() rather than MainObject.invalid()
Updated fiddle
There is a non–standard caller property of functions that returns the caller function, however that is a pointer to a function object and doesn't tell you the object it was called as a method of, or the object's name. You can get a reference to the function through arguments.callee.
There is also the obsolete arguments.caller, but don't use that. It also provides a reference to the calling function (where supported).
Once you have a reference to the calling function (if there is one), you then have the issue of resolving its name. Given that Functions are Objects, and objects can be referenced by multiple properties and variables, the concept of a function having a particular name is alluvial.
However, if you know that the function is a property of some object, you can iterate over the object's own enumerable properties to find out which one it is.
But that seems to be a rather odd thing to do. What are you actually trying to do? You may be trying to solve a problem that can be worked around in a much more robust and simpler way.
Edit
You can do what you want in a very limited way using the method described above for the case in the OP, however it is not robust or a general solution:
var mainObject = {
test : function() {
var obj = this;
var caller = arguments.callee.caller;
var global = (function(){return this}());
var fnName, objName;
for (var p in global) {
if (global[p] === obj) {
objName = p;
}
}
for (var f in obj) {
if (obj[f] === caller) {
fnName = f;
}
}
return objName + '.' + fnName;
},
testcaller : function() {
return mainObject.test();
},
anothercaller : function() {
return mainObject.test();
}
}
console.log(mainObject.testcaller()); // mainObject.testcaller
console.log(mainObject.anothercaller()); // mainObject.anothercaller
but it's brittle:
var a = mainObject.anothercaller;
console.log(a()); // mainObject.anothercaller
var b = {
foo : mainObject.anothercaller
}
console.log(b.foo()); // mainObject.anothercaller
Oops.
You can use this trick at http://www.eriwen.com/javascript/js-stack-trace/ which throws an error, then parses the stack trace.
I have updated it for the latest versions of Firefox, Chrome and IE. Unfortunately it doesn't work well on my IE9 (and I haven't tested it on Opera).
function getStackTrace() {
var callstack = [];
var isCallstackPopulated = false;
try {
i.dont.exist += 0; //doesn't exist- that's the point
} catch (e) {
if (e.stack) { //Firefox/Chrome/IE11
var lines = e.stack.split('\n');
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i].trim();
if (line.match(/^at [A-Za-z0-9\.\-_\$]+\s*\(/)) {
// Chrome/IE: " at Object.MainObject.testcaller (url:line:char)"
var entry = line.substring(3, line.indexOf('(') - 1);
// Chrome appends "Object." to the front of the object functions, so strip it off
if (entry.indexOf("Object.") == 0) {
entry = entry.substr(7, entry.length);
}
callstack.push(entry);
} else if (line.match(/^[A-Za-z0-9\.\-_\$]+\s*#/)) {
// Firefox: "MainObject.testcaller#url:line:char"
callstack.push(line.substring(0, lines[i].indexOf('#')));
}
}
//Remove call to getStackTrace()
callstack.shift();
isCallstackPopulated = true;
} else if (window.opera && e.message) { //Opera
var lines = e.message.split('\n');
for (var i = 0, len = lines.length; i < len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
var entry = lines[i];
//Append next line also since it has the file info
if (lines[i + 1]) {
entry += lines[i + 1];
i++;
}
callstack.push(entry);
}
}
//Remove call to getStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
}
if (!isCallstackPopulated) { //IE9 and Safari
var currentFunction = arguments.callee.caller;
while (currentFunction) {
var fn = currentFunction.toString();
var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf('')) || 'anonymous';
callstack.push(fname);
currentFunction = currentFunction.caller;
}
}
return callstack;
}
var MainObject = {
test: function (x) {
// first entry is the current function (test), second entry is the caller
var stackTrace = getStackTrace();
var caller = stackTrace[1];
return caller + "()";
},
testcaller: function () {
return MainObject.test(1, null);
}
}
function SomeFunction() {
return MainObject.test("blah");
}
document.body.innerHTML += '<b style="color: red">' + MainObject.testcaller() + '</b>';
document.body.innerHTML += '<div>Calling SomeFunction() returns: <b style="color: red">' + SomeFunction() + '</b></div>';
MainObject.test() should return: <b style="color: blue">MainObject.testcaller()</b>
<hr />
MainObject.test() returns:
Updated fiddle here

JavaScript - jQuery - Is my dataSource() function safe? - How to test

I'm new in StackOverflow and not sure whether I should ask this question here or not, so if I'm asking this question at wrong place, please let me know.
I want to implement dataSource in javascript (like ASP.NET). So I have created a jQuery plugin with these functions:
$.getUniqueString = function (prefix) {
if (!prefix) prefix = "s";
for (var loopIndex = 0; true; loopIndex++) {
if (typeof window[prefix + loopIndex] != "undefined") { // if sourceId exists
continue;
}
prefix = prefix + loopIndex;
break;
}
return prefix;
}
$.fn.dataSource = function (source) {
var sourceId;
if (!source) {
sourceId = $(this).attr("data-source-id");
return window[sourceId];
}
sourceId = $.getUniqueString();
$(this).attr("data-source-id", sourceId);
window[sourceId] = source;
}
This plugin works fine. And till now, I have not faced any difficulty. Here is the link to a working example (fiddle): http://jsfiddle.net/Gu2KQ/
But, my questions are:
Is my code safe enough for the client browser not to crash?
Any suggestion to optimize this code more?
Any other option to implement the same functionality better?
Any help would be appreciated.
Eval is unnecessary here. You can get and set global variables as properties of the window object.
$.getUniqueString = function (prefix) {
if (!prefix) prefix = "s";
for (var loopIndex = 0; true; loopIndex++) {
if (typeof window[prefix + loopIndex] != "undefined") { // if sourceId exists
continue;
}
prefix = prefix + loopIndex;
break;
}
return prefix;
}
$.fn.dataSource = function (source) {
var sourceId;
if (!source) {
sourceId = $(this).attr("data-source-id");
return window[sourceId];
}
sourceId = $.getUniqueString();
$(this).attr("data-source-id", sourceId);
window[sourceId] = source;
}

Null Pointer exception in JavaScript

var Obj = {
StateValues: ['AL','AK','AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA','HI','ID','IL','IN','IA',
'KS','KY','LA','ME','MD','MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND',
'OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VT','VA','WA','WV','WI','WY'],
getItemRow: function(itemValue) {
var myPosition=-1
for (var i=0;i<Obj.StateValues.length;i++) {
if(Obj.StateValues[i]==itemValue) {
myPosition = i;
break;
}
}
return myPosition;
}
}
When i add the function in the code, i get Null Pointer Expection. This piece of code is in a sep file... somename.js and which i include
I am not even using this function anywhere in my other js file... like Obj.getItemRow()
var Obj = new function(){
var StateValues = ['AL','AK','AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA','HI','ID','IL','IN','IA',
'KS','KY','LA','ME','MD','MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND',
'OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VT','VA','WA','WV','WI','WY'];
this.getItemRow = function(itemValue) {
var myPosition=-1
for (var i=0;i<StateValues.length;i++) {
if(StateValues[i]==itemValue) {
myPosition = i;
break;
}
}
return myPosition;
};
}
This is an easier way to create objects.
var blah = 'this is private'
this.blah = 'this is public'
This works for me:
console.debug(Obj.getItemRow("AK"));

Categories