I have a test i'm writing which reads in a string and then takes that string and applies it to a switch statement. I then match the string to the case and set an integer value which I pass back to the spec page which then passes the int value to another test that I use for an if statement. I cannot get the int to pass so the if statement will not work properly.
The object for switch:
var appsNotPurchased = 0;
this.checksHomeSublevel = function(mmCode) {
browser.get('https://iplan-qa.meetingmatrix.com/Home/Index/' + mmCode);
marketingObjects.level.getText().then(function(text) {
var homeText = text;
browser.get('https://iplan-qa.meetingmatrix.com/Home/Apps/' + mmCode);
expect($('div.apps-subscription > span').getText()).toEqual('iPlan Level: ' + homeText);
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = 6;
return appsNotPurchased;
break;
case 'Content':
console.log(homeText);
appsNotPurchased = 0 || 1 || 2 || 3 || 4 || 5 || 6;
return appsNotPurchased;
break;
}
});
the testSpec describe function:
describe('should upload media: ', function() {
it('should select add media', function() {
var mmCode = "ACC0572";
var appsNotPurchased = appsObjects.checksHomeSublevel(mmCode);
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
});
The object I am passing the value to:
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
You should be returning an object instead of || statement. Also return statement should be written outside switch rather than inside it.
Simplest solution would be to use a global variable appsNotPurchased which stores the value and then you can use it in your test specs without returning. But that would be a poor coding standard.
Second solution would be to return a promise of the function as protractor executes asynchronously.
Here's an example of second solution -
this.checksHomeSublevel = function(mmCode) {
var getval = marketingObjects.level.getText().then(function(text) {
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = [6];
break;
case 'Content':
console.log(homeText);
appsNotPurchased = [0, 1, 2, 3, 4, 5, 6]; //either use array or object
break;
default:
console.log("Default");
}
return appsNotPurchased;
});
return protractor.promise.fulfilled(getval);
};
and then use it like a promise in your spec -
appsObjects.checksHomeSublevel(mmCode).then(function(appsNotPurchased){
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
Use above result in your function now -
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased[i]) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
Hope it helps.
Related
I have a Google Docs document with a PARAGRAPH followed by a TABLE followed by a TABLE. Visually there is a PARAGRAPH between the two TABLEs. Programatically, however, using the following code, the run log demonstrates that there is no PARAGRAPH, viz
[1] PARAGRAPH {'LEFT_TO_RIGHT' : true, 'LINE_SPACING' : 1.15, 'SPACING_AFTER' : 0, 'SPACING_BEFORE' : 0, 'INDENT_FIRST_LINE' : 0, 'INDENT_END' : 0, 'INDENT_START' : 0}
[1/1] TEXT {} perth influencer
[2] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'}
[3] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} Keyword Research Volume
...
According to the Google Apps Script documentation for appendTable:
This method will also append an empty paragraph after the table, since Google Docs documents cannot end with a table.
This paragraph can be seen with the eyes but the script as it stands cannot "see" it. That is, stepping through the child elements of the document's body fails to detect the presence of the automatically-inserted paragraph. This is a problem because I want to reduce the point size of that paragraph.
This may be a known limitation of Google Docs via Google Apps Script. Or it may be my bad code, so below are the functions that I base my assertion on. They do nothing other than report on what they find but even so, maybe I'm missing something.
The output above was generated by coding LogChildren with a parameter of type GoogleAppsScript.Document.Body and referring to the body of the generated document.
String.prototype.quoted = function () {
return "'" + this.replace(/'/g,"\\'") + "'";
}
Number.prototype.quoted = function () {
return String(this);
}
Boolean.prototype.quoted = function () {
return this ? "true" : "false";
}
function getInnerText(child) {
switch (child.getType().toString()) {
case "BODY_SECTION":
return child.asBody().getText();
break;
case "EQUATION":
return child.asEquation().getText();
break;
case "EQUATION_FUNCTION":
return child.asEquationFunction().getText();
break;
case "FOOTER_SECTION":
return child.asFooterSection().getText();
break;
case "FOOTNOTE_SECTION":
return child.asFootnoteSection().getText();
break;
case "HEADER_SECTION":
return child.asHeaderSection().getText();
break;
case "LIST_ITEM":
return child.asListItem().getText();
break;
case "PARAGRAPH":
return "";
break;
case "TABLE":
return child.asTable().getText();
break;
case "TABLE_CELL":
return child.asTableCell().getText();
break;
case "TABLE_OF_CONTENTS":
return child.asTableOfContents().getText();
break;
case "TABLE_ROW":
return child.asTableRow().getText();
break;
case "TEXT":
return child.asText().getText();
break;
case "PAGE_BREAK":
return "";
break;
case "INLINE_IMAGE":
return child.asInlineImage().getLinkUrl();
break;
default:
return child.asText().getText();
break;
}
}
function getStyles(child) {
const attribs = child.getAttributes();
const attribList = [];
for (let att in attribs) {
try {
if (null !== attribs[att])
attribList.push(att.quoted() + " : " + attribs[att].quoted());
}
catch (E) { }
}
return "{" + attribList.join(", ") + "}";
}
function LogChild(index, child) {
Logger.log("[%s] %s %s %s", index, child.getType().toString(), getStyles(child), getInnerText(child));
}
function LogChildren(body) {
function LogDeeper(cc, child) {
const childCount = child.getNumChildren();
for (let c = 0; c < childCount; c++) {
LogChild(String(cc) + "/" + String(c + 1), child.getChild(c));
}
}
const childCount = body.getNumChildren();
for (let c = 0; c < childCount; c++) {
const child = body.getChild(c);
LogChild(String(c + 1), child);
if (isParagraph(child)) {
LogDeeper(c + 1, child.asParagraph());
}
else if (isListItem(child)) {
LogDeeper(c + 1, child.asListItem());
}
}
}
function isPageBreak(elem) {
return elem.getType() === DocumentApp.ElementType.PAGE_BREAK;
}
function isText(elem) {
return elem.getType() === DocumentApp.ElementType.TEXT;
}
function isParagraph(elem) {
return elem.getType() === DocumentApp.ElementType.PARAGRAPH;
}
function isListItem(elem) {
return elem.getType() === DocumentApp.ElementType.LIST_ITEM;
}
function isTable(elem) {
return elem.getType() === DocumentApp.ElementType.TABLE;
}
Use google-docs-api 's Document#get to retrieve the document structure and if there is a intervening paragraph recorded between the two tables, issue UpdateParagraphStyleRequest to modify that paragraph.
You can access the api from apps script through Advanced Google services
I'm trying to test some JavaScript functions that are part of a larger React app. They make heavy use of the module pattern, which I suspect may be what I'm not understanding correctly. Here is the script I'm testing (nearly identical to the one actually used in the real app except that GetFeedData.getFeedData in the real one makes a call to an external API):
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function (sub) {
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
},
getFeedData: function () {
if (feedId === 2) {
feed = require('./MockData');
}
},
feed: feed
};
})();
const ReverseStop = (function () {
let stopIdN, stopIdS;
const stopData = require('../utils/stops');
return {
reverseStop: function (sub, stop) {
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && typeof item.stop_id === 'string' && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries ++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
},
stopIdN: stopIdN,
stopIdS: stopIdS
};
})();
export const IsDelayN = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
export const IsDelayS = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
What I'm attempting to do is separate out my functions so I have several shorter ones I can call in the exported functions, rather than one or two extremely long functions. Because I need to call a couple variables - GetFeedData.feed, ReverseStop.stopIdN, and ReverseStop.stopIdS in the exported functions, I am assuming that the module pattern is a better way to go than using callbacks. I could totally be wrong.
In my tests, I try log noDelay, nextArrival, and delay to the console to see if they are defined. I'm using Jest, if that information is helpful. I'll omit the other parts of my test for now because they don't seem relevant (please correct me if that's wrong), but here is that section:
it('correctly takes input at beginning of api logic and outputs expected values at end', () => {
IsDelayN.isDelay('L', 'Lorimer St');
IsDelayS.isDelay('L', 'Lorimer St');
expect(IsDelayN.noDelay).toBeTruthy();
expect(IsDelayN.yesDelay).toBeFalsy();
expect(IsDelayS.noDelay).toBeTruthy();
expect(IsDelayS.yesDelay).toBeFalsy();
console.log('IsDelayN noDelay: ' + IsDelayN.noDelay);
console.log('IsDelayN nextArrival: ' + IsDelayN.nextArrival);
console.log('IsDelayN delay: ' + IsDelayN.delay);
console.log('IsDelayS noDelay: ' + IsDelayS.noDelay);
console.log('IsDelayS nextArrival: ' + IsDelayS.nextArrival);
console.log('IsDelayS delay: ' + IsDelayS.delay);
});
The tests prior to my console.log()s are all passing, but every console.log() is turning up undefined. Also, the script that's actually being called by my React components is coming up with the same results. I have my component set to render null if these variables aren't defined, and that's exactly what's happening.
Any help with understanding this is greatly appreciated.
You do not set the modules correctly, when setting a member value you should mutate the object, now you just set a variable value.
The following should work for you:
var module = (function(){
const ret = {
mutateSomething:function(value){
//set otherValue on the object returned (mutate ret)
ret.otherValue = value;
}
,otherValue:undefined
};//create the object first
return ret;//then return the object
}())//IIFE
console.log("before mutate:",module.otherValue);
module.mutateSomething("Hello World");
console.log("after mutate:",module.otherValue);
Suppose I have following piece of code that contains an infinite loop:
function infiniteLoop() {
while(true) {
//do something, eg.
document.getElementById("someID").innerHTML = "Blah";
}
}
If we execute this code in an online compiler, browser will crash. I want to prevent that from happening. So I tried following code following this answer:
function willNotCrash() {
myVar = setInterval(infiniteLoop, 5000);
setTimeout(function(){
clearInterval(myVar);
}, 4000);
}
This code doesn't make the browser to crash, because I am stopping the execution before infiniteLoop() gets called by clearInterval(myVar).
My question is how do I stop executing such functions if they don't response within some period of time (eg. after 5 seconds or before the browser is crashed).
For example, if we copy paste following java code in https://www.compilejava.net/
public class HelloWorld {
public static void main(String[] args) {
while(true) {
System.out.println("Blah");
}
}
}
we get a nice output saying,
Script was taking longer than 5 seconds to execute so it was killed.
Here is my current code: http://js.do/code/106546
This is a bit tricky but perfectly doable. You need to tokenize the script and then rebuild it but insert a counter increment in every loop and function call. If the counter goes above some threshold, then bomb out. I did it here: https://littleminigames.com/
You can see the source at https://bitbucket.org/cskilbeck/littleminigames/src
The interesting bits are in wrapper.js (https://bitbucket.org/cskilbeck/littleminigames/src/ac29d0d0787abe93c75b88520050a6792c04d34d/public_html/static/js/wrapper.js?at=master&fileviewer=file-view-default)
Google escodegen, estraverse and esprima
I relied heavily on this: https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
wrapper.js, as requested:
// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
(function(mainApp) {
'use strict';
var esprima = window.esprima,
estraverse = window.estraverse,
escodegen = window.escodegen,
errors = [],
eng,
Syntax = estraverse.Syntax;
// This implements the jankiest possible "source map", where we keep an array
// of [generatedLine, knownSourceLine]. Seems to essentially work.
function SourceNode(line, col, _sourceMap, generated) {
this.line = line;
this.col = col;
this.generated = generated;
}
SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
var code = [];
var mapLines = {};
var map = [];
// assumes that wrapCode adds two lines
var line = 3;
var lastMapLine = null;
function walk(node) {
if (typeof(node) === "string") {
if (node) {
code.push(node);
var matches = node.match(/\n/g);
if (matches !== null) {
line += matches.length;
}
}
} else if (node instanceof SourceNode) {
if (node.line !== null) {
if (!mapLines[line]) {
map.push([line, node.line]);
mapLines[line] = node.line;
}
}
walk(node.generated);
} else {
node.forEach(walk);
}
}
walk(this);
return {
code: code.join(''),
map: map
};
};
SourceNode.prototype.toString = function toString() {
return this.toStringWithSourceMap().code;
};
// This is used by escodegen
window.sourceMap = {
SourceNode: SourceNode
};
// TODO (chs): add in all the things that need to be masked
function runWrapper($userCode, __sys) {
var clear = __sys.clear,
setpixel = __sys.setpixel,
rectangle = __sys.rectangle,
box = __sys.box,
line = __sys.line,
getpixel = __sys.getpixel,
getpixeli = __sys.getpixeli,
keypress = __sys.keypress,
keyrelease = __sys.keyrelease,
keyheld = __sys.keyheld,
reset = __sys.reset;
__sys.userFunction = __sys.catchErrors($userCode);
}
function extractCode(fn) {
var code = fn.toString();
return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
}
function makeOneLine(code) {
return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
}
var runTemplate = makeOneLine(extractCode(runWrapper));
function wrapCode(code, template, functionName, postCode) {
// avoid interpretation of the replacement string by using a fun.
// otherwise mo' $ mo problems.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
return ("'use strict';" + template.replace(/\$userCode/, function() {
return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
}));
}
var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];
function CallExpression(callee, args) {
this.callee = callee;
this.arguments = args;
}
CallExpression.prototype.type = Syntax.CallExpression;
function Identifier(name) {
this.name = name;
}
Identifier.prototype.type = Syntax.Identifier;
function BlockStatement(body) {
this.body = body;
}
BlockStatement.prototype.type = Syntax.BlockStatement;
function ReturnStatement(argument) {
this.argument = argument;
}
ReturnStatement.prototype.type = Syntax.ReturnStatement;
function FunctionExpression(id, params, body) {
this.id = id;
this.params = params;
this.body = body;
this.defaults = [];
this.expression = false;
this.generator = false;
this.rest = null;
}
FunctionExpression.prototype.type = Syntax.FunctionExpression;
function wrapId(node, defaultName) {
if (node.loc) {
var id = (node.id || {
name: null,
loc: null
});
var loc = id.loc || node.loc;
var name = id.name || defaultName;
return new Identifier(name + '$' + loc.start.line);
} else {
return node.id;
}
}
function instrumentAST(ast) {
var identifierStack = [];
function pushIdentifier(s) {
identifierStack[identifierStack.length - 1].push(s);
}
function popIdentifierStack() {
identifierStack.pop();
}
function pushIdentifierStack() {
identifierStack.push([]);
}
function peekLastIdentifier() {
var lastStackIdx = identifierStack.length - 1;
if (lastStackIdx >= 0) {
var stack = identifierStack[lastStackIdx];
if (stack.length) {
return stack[stack.length - 1];
}
}
return '';
}
pushIdentifierStack();
return estraverse.replace(ast, {
enter: function enterAST(node) {
switch (node.type) {
case Syntax.VariableDeclarator:
if (node.id.type === Syntax.Identifier) {
pushIdentifier(node.id.name);
}
break;
case Syntax.MemberExpression:
if (node.object.type === Syntax.Identifier) {
var id = node.object.name;
if (node.property.type === Syntax.Identifier) {
id += '__dot__' + node.property.name; // huh? why mangle these?
// console.log(id);
}
pushIdentifier(id);
} else if (node.property.type === Syntax.Identifier) {
pushIdentifier(node.property.name);
}
break;
case Syntax.FunctionDeclaration:
pushIdentifierStack();
break;
case Syntax.FunctionExpression:
pushIdentifierStack();
break;
default:
break;
}
return node;
},
leave: function leaveAST(node) {
switch (node.type) {
case Syntax.DoWhileStatement:
break;
case Syntax.ForStatement:
break;
case Syntax.FunctionDeclaration:
break;
case Syntax.FunctionExpression:
break;
case Syntax.WhileStatement:
break;
default:
return estraverse.SKIP;
}
// modify the BlockStatement in-place to inject the instruction counter
if(node.body.body === undefined) {
// they have used a non-block statement as the body of a function or loop construct
// not allowed for function declarations - should never get here
if(node.type === Syntax.FunctionDeclaration) {
errors.push({
message: "Missing {",
line: node.loc.start.line,
column: node.loc.start.column
});
}
else {
// otherwise insert the test
var newBody = angular.copy(injectElseStatement);
newBody.alternate = node.body;
node.body = newBody;
}
return estraverse.SKIP;
}
node.body.body.unshift(injectStatement);
if (node.type === Syntax.FunctionExpression) {
popIdentifierStack();
// __catchErrors(node)
node.id = wrapId(node, peekLastIdentifier());
return new CallExpression(
new Identifier("__sys.catchErrors"), [node]);
}
if (node.type === Syntax.FunctionDeclaration) {
popIdentifierStack();
// modify the BlockStatement in-place to be
// return __catchErrors(function id() { body });
var funBody = node.body;
node.body = new BlockStatement([
new ReturnStatement(
new CallExpression(
new CallExpression(
new Identifier("__sys.catchErrors"), [new FunctionExpression(
wrapId(node, peekLastIdentifier()), [],
funBody)]), []))
]);
}
return node;
}
});
}
// mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code
// give it the source code as a string
mainApp.sandbox = function(code) {
var rc = {};
this.errors = [];
try {
this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
}
catch(e) {
this.errors.push({
message: e.description,
line: e.lineNumber,
column: e.column
});
}
if(this.code) {
this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
}
};
mainApp.sandbox.prototype.searchMap = function(needle) {
// binary search
var lo = 0;
var hi = this.map.map.length;
var mid, here;
while (true) {
mid = lo + ((hi - lo) >> 1);
here = this.map.map[mid];
if (mid === lo || here[0] === needle) {
return here[1];
} else if (here[0] > needle) {
hi = mid;
} else {
lo = mid;
}
}
};
})(mainApp);
Typically all JavaScript runs in one thread, so it is impossible to run any JavaScript that could stop your loop while your loop is running. Using HTML5 web workers, you can run the infinite loop in a separate thread, and then you can terminate it:
var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
myWorker.terminate( );
}, 5000 );
However your web worker won't have access to the DOM, so the contents of your infinite loop would need to be different that what you have in your question.
I found exactly what I was looking for in Bergi's comment,
Alternatively, place a if (Date.now() > dateAtStartOfExecution+5000) return; in every loop body.
So now my code looks like:
function infiniteLoop() {
dateAtStartOfExecution = Date.now();
while(true) {
//do something
document.getElementById("someID").innerHTML = "Blah";
if (Date.now() > dateAtStartOfExecution+5000) {
alert("Taking too much time. Killing.");
return;
}
}
}
If I run this code after 5 seconds I will get an alert and the execution will stop. Try this:
http://js.do/code/106565
This is how everything should work when the iFrameOn function runs:
Turn the designMode of all iFrames on
Find the three "buttons" ('a' link elements) - that when clicked affect its corresponding iFrame - depending on its className
Put those "buttons" into a multidimensional array/object i.e target.rtfID.x
Whenever a "button" is clicked, find its corresponding iFrame through the object and send the iFrame's id as an argument for another function.
Currently, however, whenever any of the buttons are clicked they all affect the same iFrame. I realize this is likely due to my usage of the loops, but I can't figure out how to make it all work. There are no errors in the console.
function iFrameOn() {
var rtfContainer, rtContainer, richTxt, richTxtId,
rtf = document.querySelectorAll('div > form > iframe'), //Rich Text Field
newPost = document.getElementById('richTextField').contentDocument.body,
target = {}, rtfIndex = 0;
//Turn iFrames On
while (rtfIndex < rtf.length) {
rtfID = rtf[rtfIndex].id;
if (rtf[rtfIndex].contentDocument.designMode != 'On') {
rtf[rtfIndex].contentDocument.designMode = 'On';
}
newPost.innerHTML = "<i style=\"color:#DDDDDD;\">What's up?</i>";
newPost.addEventListener('blur', function() {
if (newPost.innerHTML == '') {
newPost.innerHTML = "<i style=\"color:#DDDDDD;\">What's up?</i>";
}
}, false);
document.getElementById('richTextField').contentWindow.addEventListener(
'focus',
function() {
if (newPost.innerHTML == "<i style=\"color:#DDDDDD;\">What's up?</i>") {
newPost.innerHTML = '';
}
},
false
);
rtContainer = rtf[rtfIndex].nextElementSibling; //Next Element Sibling should be a div
console.log('rtContainer is: '+rtContainer);
richTxt = rtContainer.childNodes;
console.log('richTxt is: '+richTxt);
for (var i = 0; i < richTxt.length; i++) {
if (richTxt[i].nodeType != 1 ||
(richTxt[i].nodeType == 1 &&
(richTxt[i].className == 'submit_button sbmtPost'
|| richTxt[i].className == "")
)
) {
continue;
}
richTxtId = richTxt[i].id;
target.rtfID = {};
switch (richTxt[i].className) {
case 'richText bold':
if (target.rtfID.bold != richTxtId) {
target.rtfID.bold = richTxtId;
console.log(target.rtfID.bold+' is associated with: '+rtfID);
}
break;
case 'richText underline':
if (target.rtfID.underline != richTxtId) {
target.rtfID.underline = richTxtId;
console.log(target.rtfID.underline+' is associated with: '+rtfID);
}
break;
case 'richText italic':
if (target.rtfID.italic != richTxtId) {
target.rtfID.italic = richTxtId;
console.log(target.rtfID.italic+' is associated with: '+rtfID);
}
break;
default:
console.log('Error with commenting system!');
break;
}
}
var obj = target.rtfID;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + obj[prop]);
switch(prop) {
case 'bold':
document.getElementById(obj[prop]).addEventListener(
'click',
function() {
bold(obj[prop]);
},
false
);
break;
case 'underline':
document.getElementById(obj[prop]).addEventListener(
'click',
function() {
Underline(obj[prop]);
},
false
);
break;
case 'italic':
document.getElementById(obj[prop]).addEventListener(
'click',
function() {
Italic(obj[prop]);
},
false
);
break;
default:
console.log('Error in for...in loop');
}
} else {console.log('error');}
}
rtfIndex++;
}
}
You can do things like this:
function createBolder (val) {
return function () {
bold(val);
};
}
document.getElementById(obj[prop]).addEventListener(
'click',
createBolder(obj[prop]),
false
);
or if you really want to keep things inline:
document.getElementById(obj[prop]).addEventListener(
'click',
(function (val) {
return function () {
bold(val);
};
}(obj[prop])), // This function call executes immediately (i.e., while still
// going through the loop, so the current value of obj[prop]
// will be stored inside this function with its own local copy
// rather than using the value of obj and prop by the time
// the function is executed (probably the completion of the loop))
false
);
I'm trying to get this to work:
function whatever(arg) {
eval(arg) + '_group' = [];
}
The purpose is to have only 1 function instead having three with basically the same content but with different variable names.
At the end I want to have something like:
a_group = [];
b_group = [];
Doing this way, I'm getting the error:
ReferenceError: Invalid left-hand side in assignment
EDIT
Here is the original function that I'm trying to make work. But it won't work.
function collect_all_values_for(field_name) {
switch(field_name) {
case 'states':
use = 'state';
case 'cities':
use = 'city';
case 'neighborhoods':
use = 'neighborhood';
}
window[field_name + '_group'] = [];
n_fields = $('[id^=' + use + '_]').length-1;
i = 0;
field_value = 0;
for (i = 0; i<= n_fields; i++) {
if (i == 0) {
field_value = $('#' + use).val();
}else{
field_value = $('#' + use + '_id' + i).val();
}
//states_group.push(field_value);
window[field_name + '_group'].push(field_value);
}
}
Looking on the console output:
states_group
[undefined, undefined, undefined]
And then I should be able to call it as:
collect_all_values_for('states');
collect_all_values_for('cities');
collect_all_values_for('neighborhoods');
Thanks in advance.
function whatever(arg) {
window[arg + '_group'] = [];
}
This will set a_group, b_group as global variable.
To access those variable use:
window['a_group'], window['b_group'] and so on.
According to edit
In your switch you should use break;.
switch(field_name) {
case 'states':
use = 'state';
break;
case 'cities':
use = 'city';
break;
case 'neighborhoods':
use = 'neighborhood';
break;
}
Using local Object (without window object) and better
var myObject = {};
function whatever(arg) {
myObject[arg + '_group'] = [];
// output: { 'a_group' : [], 'b_group' : [], .. }
}
// to set value
myObject[arg + '_group'].push( some_value );
// to get value
myObject[arg + '_group'];
Although you really shouldn't use eval this should help
eval(arg + '_group') = [];
Just to increase #theparadox's answer.
I prefer to use the following way to make a switch.
var options = {
'states' : 'state',
'cities': 'city',
'neighborhoods': 'neighborhood'
};
use = options[field_name];
demo
Or if you just want to remove the last letter, you can do this.
use = field_name.slice(0,-1);
demo