I have created an object of available_categories({category: coats-and-jackets}) and another object category_names_for_display({coats-and-jackets:Coats and Jackets}).
The intention is to use the 'key' (coats-and-jackets) from the loop of available_categories, to get the category_name_for_display (Coats & Jackets) from the second object.
// build array of available categories
var obj = available_categories.find(o=>o.category === cat);
if (!(obj) && cat && cat.length > 0) {
available_categories.push({
category: cat
});
}
//console.log('ac=' + available_categories);
// build array of category_names_for_display
var obj = category_names_for_display.find(o=>o.cat === category_name_for_display);
if (!obj && cat && cat.length > 0 && category_name_for_display) {
console.log('cat = ' + cat + 'cnfd= ' + category_name_for_display);
var arr = {};
arr[cat] = category_name_for_display;
category_names_for_display.push(arr);
new_var = category_names_for_display['cat'];
console.log('this ' + new_var);
}
if (available_categories.length > 0) {
//loop through the array to output more data
$.each(available_categories, function(k , v)
{
$.each(this, function(k , v)
{
var checked_status = '';
var selected_option_number = '';
var undo_label = '';
console.log('k= ' + k + 'V= ' + v);
// here is where I have something wrong :(
var catego = category_names_for_display['v'];
}
}
}
I am only getting the console to show the value is undefined. I need the category_name_for_display to be Coats & Jackets.
Just try to create a object and push.
if ( !obj && cat && cat.length > 0 && category_name_for_display )
{
var arr = {};
arr[cat] = category_name_for_display;
category_names_for_display.push(arr);
}
category_names_for_display is an array and the mistake is you are trying to access category_names_for_display as an object
You can modify you code as shown below to make your var catego store corect thing
$.each(this, function(k , v)
{
var checked_status = '';
var selected_option_number = '';
var undo_label = '';
console.log('k= ' + k + 'V= ' + v);
var catego = category_names_for_display.find(item => item === v);
}
Related
I need to store a large json into a cell of a spreadsheet. Since there's a 50k character limit I thought of compressing the json string. I've managed to store the compressed blob as a base64 encoded string, but I'm failing to restore it to the original json. When the readLargeJson function is called I get the following error: "Blob object must have non-null content type for this operation".
The insertLargeJson function below seems to be working correctly.
I tried also storing without the base64 encoding, but didn't help.
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getDataAsString());
activeSheet.getRange(1, 1).setValue(encoded);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var values = activeSheet.getSheetValues(1, 1, 1, 1);
var value = values[0, 0];
var decoded = Utilities.base64Decode(value);
var blob = Utilities.newBlob(decoded);
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped.getDataAsString());
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
I don't necessarily need to use the blob interface to compress the json, any solution that would compress the json string and that would be storable in a cell for later retrieving the original json would work.
It is an interesting concept so I search a bit and get something working.
In your code you have to use compressedBlob.getBytes() to encode data and not compressedBlob.getDataAsString(). To create a blob in your read function you must use bytes in input.
Then in your read function the unzip return an array and before to get the data you have to use the getAs() function. So you must have unzipped[0].getAs('application/octet-stream').getDataAsString() and not unzipped.getDataAsString()
I made a single function to ease testing, so you just have to split it depending your need.
function insertReadLargeJson(){
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
// Logger.log(obj)
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getBytes());
activeSheet.getRange(1, 1).setValue(encoded);
var decoded = Utilities.base64Decode(encoded);
var blob = Utilities.newBlob(decoded,'application/zip');
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped[0].getAs('application/octet-stream').getDataAsString());
// Logger.log(JSON.stringify(obj))
Logger.log(obj.dummy.length)
// Logger.log('Test Json array size', "" + obj["dummy"].length)
}
I was able to do it with the help of an external library.
I converted the code to be readable by Apps Script:
JSONPACK.gs
var TOKEN_TRUE = -1;
var TOKEN_FALSE = -2;
var TOKEN_NULL = -3;
var TOKEN_EMPTY_STRING = -4;
var TOKEN_UNDEFINED = -5;
function pack(json, options) {
// Canonizes the options
options = options || {};
// A shorthand for debugging
var verbose = options.verbose || false;
verbose && console.log('Normalize the JSON Object');
// JSON as Javascript Object (Not string representation)
json = typeof json === 'string' ? this.JSON.parse(json) : json;
verbose && console.log('Creating a empty dictionary');
// The dictionary
var dictionary = {
strings : [],
integers : [],
floats : []
};
verbose && console.log('Creating the AST');
// The AST
var ast = (function recursiveAstBuilder(item) {
verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item));
// The type of the item
var type = typeof item;
// Case 7: The item is null
if (item === null) {
return {
type : 'null',
index : TOKEN_NULL
};
}
//add undefined
if (typeof item === 'undefined') {
return {
type : 'undefined',
index : TOKEN_UNDEFINED
};
}
// Case 1: The item is Array Object
if ( item instanceof Array) {
// Create a new sub-AST of type Array (#)
var ast = ['#'];
// Add each items
for (var i in item) {
if (!item.hasOwnProperty(i)) continue;
ast.push(recursiveAstBuilder(item[i]));
}
// And return
return ast;
}
// Case 2: The item is Object
if (type === 'object') {
// Create a new sub-AST of type Object ($)
var ast = ['$'];
// Add each items
for (var key in item) {
if (!item.hasOwnProperty(key))
continue;
ast.push(recursiveAstBuilder(key));
ast.push(recursiveAstBuilder(item[key]));
}
// And return
return ast;
}
// Case 3: The item empty string
if (item === '') {
return {
type : 'empty',
index : TOKEN_EMPTY_STRING
};
}
// Case 4: The item is String
if (type === 'string') {
// The index of that word in the dictionary
var index = indexOf.call(dictionary.strings, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.strings.push(encode(item));
index = dictionary.strings.length - 1;
}
// Return the token
return {
type : 'strings',
index : index
};
}
// Case 5: The item is integer
if (type === 'number' && item % 1 === 0) {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.integers, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.integers.push(base10To36(item));
index = dictionary.integers.length - 1;
}
// Return the token
return {
type : 'integers',
index : index
};
}
// Case 6: The item is float
if (type === 'number') {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.floats, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
// Float not use base 36
dictionary.floats.push(item);
index = dictionary.floats.length - 1;
}
// Return the token
return {
type : 'floats',
index : index
};
}
// Case 7: The item is boolean
if (type === 'boolean') {
return {
type : 'boolean',
index : item ? TOKEN_TRUE : TOKEN_FALSE
};
}
// Default
throw new Error('Unexpected argument of type ' + typeof (item));
})(json);
// A set of shorthands proxies for the length of the dictionaries
var stringLength = dictionary.strings.length;
var integerLength = dictionary.integers.length;
var floatLength = dictionary.floats.length;
verbose && console.log('Parsing the dictionary');
// Create a raw dictionary
var packed = dictionary.strings.join('|');
packed += '^' + dictionary.integers.join('|');
packed += '^' + dictionary.floats.join('|');
verbose && console.log('Parsing the structure');
// And add the structure
packed += '^' + (function recursiveParser(item) {
verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item));
// If the item is Array, then is a object of
// type [object Object] or [object Array]
if ( item instanceof Array) {
// The packed resulting
var packed = item.shift();
for (var i in item) {
if (!item.hasOwnProperty(i))
continue;
packed += recursiveParser(item[i]) + '|';
}
return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']';
}
// A shorthand proxies
var type = item.type, index = item.index;
if (type === 'strings') {
// Just return the base 36 of index
return base10To36(index);
}
if (type === 'integers') {
// Return a base 36 of index plus stringLength offset
return base10To36(stringLength + index);
}
if (type === 'floats') {
// Return a base 36 of index plus stringLength and integerLength offset
return base10To36(stringLength + integerLength + index);
}
if (type === 'boolean') {
return item.index;
}
if (type === 'null') {
return TOKEN_NULL;
}
if (type === 'undefined') {
return TOKEN_UNDEFINED;
}
if (type === 'empty') {
return TOKEN_EMPTY_STRING;
}
throw new TypeError('The item is alien!');
})(ast);
verbose && console.log('Ending parser');
// If debug, return a internal representation of dictionary and stuff
if (options.debug)
return {
dictionary : dictionary,
ast : ast,
packed : packed
};
return packed;
};
function unpack(packed, options) {
// Canonizes the options
options = options || {};
// A raw buffer
var rawBuffers = packed.split('^');
// Create a dictionary
options.verbose && console.log('Building dictionary');
var dictionary = [];
// Add the strings values
var buffer = rawBuffers[0];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the strings dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push((buffer[i]));
}
}
// Add the integers values
buffer = rawBuffers[1];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the integers dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(base36To10(buffer[i]));
}
}
// Add the floats values
buffer = rawBuffers[2];
if (buffer !== '') {
buffer = buffer.split('|')
options.verbose && console.log('Parse the floats dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(parseFloat(buffer[i]));
}
}
// Free memory
buffer = null;
options.verbose && console.log('Tokenizing the structure');
// Tokenizer the structure
var number36 = '';
var tokens = [];
var len=rawBuffers[3].length;
for (var i = 0; i < len; i++) {
var symbol = rawBuffers[3].charAt(i);
if (symbol === '|' || symbol === '$' || symbol === '#' || symbol === ']') {
if (number36) {
tokens.push(base36To10(number36));
number36 = '';
}
symbol !== '|' && tokens.push(symbol);
} else {
number36 += symbol;
}
}
// A shorthand proxy for tokens.length
var tokensLength = tokens.length;
// The index of the next token to read
var tokensIndex = 0;
options.verbose && console.log('Starting recursive parser');
return (function recursiveUnpackerParser() {
// Maybe '$' (object) or '#' (array)
var type = tokens[tokensIndex++];
options.verbose && console.log('Reading collection type ' + (type === '$' ? 'object' : 'Array'));
// Parse an array
if (type === '#') {
var node = [];
for (; tokensIndex < tokensLength; tokensIndex++) {
var value = tokens[tokensIndex];
options.verbose && console.log('Read ' + value + ' symbol');
if (value === ']')
return node;
if (value === '#' || value === '$') {
node.push(recursiveUnpackerParser());
} else {
switch(value) {
case TOKEN_TRUE:
node.push(true);
break;
case TOKEN_FALSE:
node.push(false);
break;
case TOKEN_NULL:
node.push(null);
break;
case TOKEN_UNDEFINED:
node.push(undefined);
break;
case TOKEN_EMPTY_STRING:
node.push('');
break;
default:
node.push(dictionary[value]);
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
// Parse a object
if (type === '$') {
var node = {};
for (; tokensIndex < tokensLength; tokensIndex++) {
var key = tokens[tokensIndex];
if (key === ']')
return node;
if (key === TOKEN_EMPTY_STRING)
key = '';
else
key = dictionary[key];
var value = tokens[++tokensIndex];
if (value === '#' || value === '$') {
node[key] = recursiveUnpackerParser();
} else {
switch(value) {
case TOKEN_TRUE:
node[key] = true;
break;
case TOKEN_FALSE:
node[key] = false;
break;
case TOKEN_NULL:
node[key] = null;
break;
case TOKEN_UNDEFINED:
node[key] = undefined;
break;
case TOKEN_EMPTY_STRING:
node[key] = '';
break;
default:
node[key] = dictionary[value];
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
throw new TypeError('Bad token ' + type + ' isn\'t a type');
})();
}
function indexOfDictionary (dictionary, value) {
// The type of the value
var type = typeof value;
// If is boolean, return a boolean token
if (type === 'boolean')
return value ? TOKEN_TRUE : TOKEN_FALSE;
// If is null, return a... yes! the null token
if (value === null)
return TOKEN_NULL;
//add undefined
if (typeof value === 'undefined')
return TOKEN_UNDEFINED;
if (value === '') {
return TOKEN_EMPTY_STRING;
}
if (type === 'string') {
value = encode(value);
var index = indexOf.call(dictionary.strings, value);
if (index === -1) {
dictionary.strings.push(value);
index = dictionary.strings.length - 1;
}
}
// If has an invalid JSON type (example a function)
if (type !== 'string' && type !== 'number') {
throw new Error('The type is not a JSON type');
};
if (type === 'string') {// string
value = encode(value);
} else if (value % 1 === 0) {// integer
value = base10To36(value);
} else {// float
}
// If is number, "serialize" the value
value = type === 'number' ? base10To36(value) : encode(value);
// Retrieve the index of that value in the dictionary
var index = indexOf.call(dictionary[type], value);
// If that value is not in the dictionary
if (index === -1) {
// Push the value
dictionary[type].push(value);
// And return their index
index = dictionary[type].length - 1;
}
// If the type is a number, then add the '+' prefix character
// to differentiate that they is a number index. If not, then
// just return a 36-based representation of the index
return type === 'number' ? '+' + index : index;
};
function encode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/[\+ \|\^\%]/g, function(a) {
return ({
' ' : '+',
'+' : '%2B',
'|' : '%7C',
'^' : '%5E',
'%' : '%25'
})[a]
});
};
function decode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/\+|%2B|%7C|%5E|%25/g, function(a) {
return ({
'+' : ' ',
'%2B' : '+',
'%7C' : '|',
'%5E' : '^',
'%25' : '%'
})[a]
})
};
function base10To36(number) {
return Number.prototype.toString.call(number, 36).toUpperCase();
};
function base36To10(number) {
return parseInt(number, 36);
};
function indexOf(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) {
return i;
}
}
return -1;
};
With that, your script can now be:
Code.gs
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var packed = pack(obj);
var value = JSON.stringify(packed);
activeSheet.getRange(1, 1).setValue(value);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var value = activeSheet.getRange(1,1).getValue();
var packed = JSON.parse(value);
var obj = unpack(packed);
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
Hope this helps!
On a MouseEvent instance, we have a property called path, it might look like this:
Does anybody know if there is a reliable way to translate this path array into an XPath? I assume that this path data is the best data to start from? Is there a library I can use to do the conversion?
This library looks promising, but it doesn't use the path property of an event: https://github.com/johannhof/xpath-dom
There's not a unique XPath to a node, so you'll have to decide what's the most appropriate way of constructing a path. Use IDs where available? Numeral position in the document? Position relative to other elements?
See getPathTo() in this answer for one possible approach.
PS: Taken from Javascript get XPath of a node
Another option is to use SelectorGadget from below link
https://dv0akt2986vzh.cloudfront.net/unstable/lib/selectorgadget.js
The actual code for the DOM path is at
https://dv0akt2986vzh.cloudfront.net/stable/lib/dom.js
Usage: on http://google.com
elem = document.getElementById("q")
predict = new DomPredictionHelper()
predict.pathOf(elem)
// gives "body.default-theme.des-mat:nth-child(2) div#_Alw:nth-child(4) form#f:nth-child(2) div#fkbx:nth-child(2) input#q:nth-child(2)"
predict.predictCss([elem],[])
// gives "#q"
CODE if link goes down
// Copyright (c) 2008, 2009 Andrew Cantino
// Copyright (c) 2008, 2009 Kyle Maxwell
function DomPredictionHelper() {};
DomPredictionHelper.prototype = new Object();
DomPredictionHelper.prototype.recursiveNodes = function(e){
var n;
if(e.nodeName && e.parentNode && e != document.body) {
n = this.recursiveNodes(e.parentNode);
} else {
n = new Array();
}
n.push(e);
return n;
};
DomPredictionHelper.prototype.escapeCssNames = function(name) {
if (name) {
try {
return name.replace(/\s*sg_\w+\s*/g, '').replace(/\\/g, '\\\\').
replace(/\./g, '\\.').replace(/#/g, '\\#').replace(/\>/g, '\\>').replace(/\,/g, '\\,').replace(/\:/g, '\\:');
} catch(e) {
console.log('---');
console.log("exception in escapeCssNames");
console.log(name);
console.log('---');
return '';
}
} else {
return '';
}
};
DomPredictionHelper.prototype.childElemNumber = function(elem) {
var count = 0;
while (elem.previousSibling && (elem = elem.previousSibling)) {
if (elem.nodeType == 1) count++;
}
return count;
};
DomPredictionHelper.prototype.pathOf = function(elem){
var nodes = this.recursiveNodes(elem);
var self = this;
var path = "";
for(var i = 0; i < nodes.length; i++) {
var e = nodes[i];
if (e) {
path += e.nodeName.toLowerCase();
var escaped = e.id && self.escapeCssNames(new String(e.id));
if(escaped && escaped.length > 0) path += '#' + escaped;
if(e.className) {
jQuery.each(e.className.split(/ /), function() {
var escaped = self.escapeCssNames(this);
if (this && escaped.length > 0) {
path += '.' + escaped;
}
});
}
path += ':nth-child(' + (self.childElemNumber(e) + 1) + ')';
path += ' '
}
}
if (path.charAt(path.length - 1) == ' ') path = path.substring(0, path.length - 1);
return path;
};
DomPredictionHelper.prototype.commonCss = function(array) {
try {
var dmp = new diff_match_patch();
} catch(e) {
throw "Please include the diff_match_patch library.";
}
if (typeof array == 'undefined' || array.length == 0) return '';
var existing_tokens = {};
var encoded_css_array = this.encodeCssForDiff(array, existing_tokens);
var collective_common = encoded_css_array.pop();
jQuery.each(encoded_css_array, function(e) {
var diff = dmp.diff_main(collective_common, this);
collective_common = '';
jQuery.each(diff, function() {
if (this[0] == 0) collective_common += this[1];
});
});
return this.decodeCss(collective_common, existing_tokens);
};
DomPredictionHelper.prototype.tokenizeCss = function(css_string) {
var skip = false;
var word = '';
var tokens = [];
var css_string = css_string.replace(/,/, ' , ').replace(/\s+/g, ' ');
var length = css_string.length;
var c = '';
for (var i = 0; i < length; i++){
c = css_string[i];
if (skip) {
skip = false;
} else if (c == '\\') {
skip = true;
} else if (c == '.' || c == ' ' || c == '#' || c == '>' || c == ':' || c == ',') {
if (word.length > 0) tokens.push(word);
word = '';
}
word += c;
if (c == ' ' || c == ',') {
tokens.push(word);
word = '';
}
}
if (word.length > 0) tokens.push(word);
return tokens;
};
DomPredictionHelper.prototype.decodeCss = function(string, existing_tokens) {
var inverted = this.invertObject(existing_tokens);
var out = '';
jQuery.each(string.split(''), function() {
out += inverted[this];
});
return this.cleanCss(out);
};
// Encode css paths for diff using unicode codepoints to allow for a large number of tokens.
DomPredictionHelper.prototype.encodeCssForDiff = function(strings, existing_tokens) {
var codepoint = 50;
var self = this;
var strings_out = [];
jQuery.each(strings, function() {
var out = new String();
jQuery.each(self.tokenizeCss(this), function() {
if (!existing_tokens[this]) {
existing_tokens[this] = String.fromCharCode(codepoint++);
}
out += existing_tokens[this];
});
strings_out.push(out);
});
return strings_out;
};
DomPredictionHelper.prototype.simplifyCss = function(css, selected_paths, rejected_paths) {
var self = this;
var parts = self.tokenizeCss(css);
var best_so_far = "";
if (self.selectorGets('all', selected_paths, css) && self.selectorGets('none', rejected_paths, css)) best_so_far = css;
for (var pass = 0; pass < 4; pass++) {
for (var part = 0; part < parts.length; part++) {
var first = parts[part].substring(0,1);
if (self.wouldLeaveFreeFloatingNthChild(parts, part)) continue;
if ((pass == 0 && first == ':') || // :nth-child
(pass == 1 && first != ':' && first != '.' && first != '#' && first != ' ') || // elem, etc.
(pass == 2 && first == '.') || // classes
(pass == 3 && first == '#')) // ids
{
var tmp = parts[part];
parts[part] = '';
var selector = self.cleanCss(parts.join(''));
if (selector == '') {
parts[part] = tmp;
continue;
}
if (self.selectorGets('all', selected_paths, selector) && self.selectorGets('none', rejected_paths, selector)) {
best_so_far = selector;
} else {
parts[part] = tmp;
}
}
}
}
return self.cleanCss(best_so_far);
};
DomPredictionHelper.prototype.wouldLeaveFreeFloatingNthChild = function(parts, part) {
return (((part - 1 >= 0 && parts[part - 1].substring(0, 1) == ':') &&
(part - 2 < 0 || parts[part - 2] == ' ') &&
(part + 1 >= parts.length || parts[part + 1] == ' ')) ||
((part + 1 < parts.length && parts[part + 1].substring(0, 1) == ':') &&
(part + 2 >= parts.length || parts[part + 2] == ' ') &&
(part - 1 < 0 || parts[part - 1] == ' ')));
};
DomPredictionHelper.prototype.cleanCss = function(css) {
return css.replace(/\>/, ' > ').replace(/,/, ' , ').replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '').replace(/,$/, '');
};
DomPredictionHelper.prototype.getPathsFor = function(arr) {
var self = this;
var out = [];
jQuery.each(arr, function() {
if (this && this.nodeName) {
out.push(self.pathOf(this));
}
})
return out;
};
DomPredictionHelper.prototype.predictCss = function(s, r) {
var self = this;
if (s.length == 0) return '';
var selected_paths = self.getPathsFor(s);
var rejected_paths = self.getPathsFor(r);
var css = self.commonCss(selected_paths);
var simplest = self.simplifyCss(css, selected_paths, rejected_paths);
// Do we get off easy?
if (simplest.length > 0) return simplest;
// Okay, then make a union and possibly try to reduce subsets.
var union = '';
jQuery.each(s, function() {
union = self.pathOf(this) + ", " + union;
});
union = self.cleanCss(union);
return self.simplifyCss(union, selected_paths, rejected_paths);
};
DomPredictionHelper.prototype.fragmentSelector = function(selector) {
var self = this;
var out = [];
jQuery.each(selector.split(/\,/), function() {
var out2 = [];
jQuery.each(self.cleanCss(this).split(/\s+/), function() {
out2.push(self.tokenizeCss(this));
});
out.push(out2);
});
return out;
};
// Everything in the first selector must be present in the second.
DomPredictionHelper.prototype.selectorBlockMatchesSelectorBlock = function(selector_block1, selector_block2) {
for (var j = 0; j < selector_block1.length; j++) {
if (jQuery.inArray(selector_block1[j], selector_block2) == -1) {
return false;
}
}
return true;
};
// Assumes list is an array of complete CSS selectors represented as strings.
DomPredictionHelper.prototype.selectorGets = function(type, list, the_selector) {
var self = this;
var result = true;
if (list.length == 0 && type == 'all') return false;
if (list.length == 0 && type == 'none') return true;
var selectors = self.fragmentSelector(the_selector);
var cleaned_list = [];
jQuery.each(list, function() {
cleaned_list.push(self.fragmentSelector(this)[0]);
});
jQuery.each(selectors, function() {
if (!result) return;
var selector = this;
jQuery.each(cleaned_list, function(pos) {
if (!result || this == '') return;
if (self._selectorGets(this, selector)) {
if (type == 'none') result = false;
cleaned_list[pos] = '';
}
});
});
if (type == 'all' && cleaned_list.join('').length > 0) { // Some candidates didn't get matched.
result = false;
}
return result;
};
DomPredictionHelper.prototype._selectorGets = function(candidate_as_blocks, selector_as_blocks) {
var cannot_match = false;
var position = candidate_as_blocks.length - 1;
for (var i = selector_as_blocks.length - 1; i > -1; i--) {
if (cannot_match) break;
if (i == selector_as_blocks.length - 1) { // First element on right.
// If we don't match the first element, we cannot match.
if (!this.selectorBlockMatchesSelectorBlock(selector_as_blocks[i], candidate_as_blocks[position])) cannot_match = true;
position--;
} else {
var found = false;
while (position > -1 && !found) {
found = this.selectorBlockMatchesSelectorBlock(selector_as_blocks[i], candidate_as_blocks[position]);
position--;
}
if (!found) cannot_match = true;
}
}
return !cannot_match;
};
DomPredictionHelper.prototype.invertObject = function(object) {
var new_object = {};
jQuery.each(object, function(key, value) {
new_object[value] = key;
});
return new_object;
};
DomPredictionHelper.prototype.cssToXPath = function(css_string) {
var tokens = this.tokenizeCss(css_string);
if (tokens[0] && tokens[0] == ' ') tokens.splice(0, 1);
if (tokens[tokens.length - 1] && tokens[tokens.length - 1] == ' ') tokens.splice(tokens.length - 1, 1);
var css_block = [];
var out = "";
for(var i = 0; i < tokens.length; i++) {
if (tokens[i] == ' ') {
out += this.cssToXPathBlockHelper(css_block);
css_block = [];
} else {
css_block.push(tokens[i]);
}
}
return out + this.cssToXPathBlockHelper(css_block);
};
// Process a block (html entity, class(es), id, :nth-child()) of css
DomPredictionHelper.prototype.cssToXPathBlockHelper = function(css_block) {
if (css_block.length == 0) return '//';
var out = '//';
var first = css_block[0].substring(0,1);
if (first == ',') return " | ";
if (jQuery.inArray(first, [':', '#', '.']) != -1) {
out += '*';
}
var expressions = [];
var re = null;
for(var i = 0; i < css_block.length; i++) {
var current = css_block[i];
first = current.substring(0,1);
var rest = current.substring(1);
if (first == ':') {
// We only support :nth-child(n) at the moment.
if (re = rest.match(/^nth-child\((\d+)\)$/))
expressions.push('(((count(preceding-sibling::*) + 1) = ' + re[1] + ') and parent::*)');
} else if (first == '.') {
expressions.push('contains(concat( " ", #class, " " ), concat( " ", "' + rest + '", " " ))');
} else if (first == '#') {
expressions.push('(#id = "' + rest + '")');
} else if (first == ',') {
} else {
out += current;
}
}
if (expressions.length > 0) out += '[';
for (var i = 0; i < expressions.length; i++) {
out += expressions[i];
if (i < expressions.length - 1) out += ' and ';
}
if (expressions.length > 0) out += ']';
return out;
};
I am doing the following:
<p>1983 (on television), 1984 (in theatres)</p>
The I run
var d;
var dateText = $("p").text().split(/\s+/g);
for(var i = 0; i < dateText.length; i++) {
d += dateText[i] + ' ';
}
var words = d.replace("–", " ").replace("-", " ").replace(",", " ").replace("/", " ").split(' ');
words = $.grep(words, function(n, i){
return (n !== "" && n != null);
});
var array = words;
var newArray = array.filter(function(v){return v!==''});
console.log(newArray);
["undefined1983", "(on", "television)", "1984", "(in", "theatres)"]
I shouldn't have undefined1983 but 1983
jsFiddle
Also if I do:
var d;
var spacetime = [];
spacetime.push({
Title : [],
Space : [],
Time : {
days : [],
months : [],
years : [],
suffixes : []
},
articleIdPush : [],
originalFullDate : [],
curArtLangPrefix : ["en"],
SingleTranslatedArticle : [],
});
var dateText = $("p").text().split(/\s+/g);
for(var i = 0; i < dateText.length; i++) {
d += dateText[i] + ' ';
}
var words = d.replace("–", " ").replace("-", " ").replace(",", " ").replace("/", " ").split(' ');
words = $.grep(words, function(n, i){
return (n !== "" && n != null);
});
var array = words;
var newArray = array.filter(function(v){return v!==''});
for (const word of newArray) {
if (months.has(word)) {
spacetime[counter].Time.months.push(word);
} else if (+word < 32) {
spacetime[counter].Time.days.push(+word);
} else if (+word < 2200) {
spacetime[counter].Time.years.push(+word);
} else if (/\w+/.test(word)) {
spacetime[counter].Time.suffixes.push(word);
}
}
console.log(spacetime);
I get
(index):90 Uncaught ReferenceError: months is not defined
I should have the defined array with the correct objects in it.
jsFiddle 2
The problem was with:
var d;
For the first iteration of your loop where you concatenate d onto itself with d +=, d is undefined. When I specified var d = ''; it works as expected.
Here's the working jsFiddle.
My goal is to efficiently apply a dynamically chosen set of transforms to each element of a matrix. I store the selected functions in an array, then apply each of them in a single pass thru the matrix.
My question is, how can I dynamically create the name of a function that I add to the array of functions?
This fiddle contains my attempt. My question is included in the comment block.
function dynam () {
var prepend = 'before - ';
var append = ' - after';
var whichCase = 'Upper';
var functionsToApply = [];
var matrix = [
['aBc', 'DeF'],
['ghi', 'JKL'],
];
var out = 'Initial: ' + matrix.join(' | ');
document.getElementById('output').innerHTML = out + '\n';
console.log(out);
// Set up transforms
if (whichCase == 'Lower') {
functionsToApply.push(function(v) {return v.toLowerCase();});
} else if (whichCase == 'Upper'){
functionsToApply.push(function(v) {return v.toUpperCase();});
}
// How can the function be defined dynamically?
// Perhaps something like:
// if(['Lower','Upper'].indexOf(whichCase) != -1) {
// functionsToApply.push(function(v) {'return v.to' + which + 'Case();'});
// }
if (prepend && prepend.length > 0 && prepend != 'none') {
functionsToApply.push(function(v) {return prepend + v;});
}
if (append && append.length > 0 && append != 'none') {
functionsToApply.push(function(v) {return v + append;});
}
// Apply all of the transforms to each of the elements of the matrix
matrix = matrix.map(function(row){
return row.map(function(val) {
for (var fn = 0; fn < functionsToApply.length; fn++) {
val = functionsToApply[fn](val);
}
return val;
})
});
out = 'Final: ' + matrix.join(' | ');
document.getElementById('output').innerHTML += out + '\n';
console.log(out);
}
I like to declare my functions in a hash in this case, then you can call them based on the value passed in, which is the key to the hash.
Updated: I've added a way to get the lower/upper function dynamically, and call it.
function dynam(whichCase, prepend, append, matrix) {
var functionHash = {
"Lower" : function(v) {return v.toLowerCase();},
"Upper" : function(v) {return v.toUpperCase();},
"Prepend" : function(v) {return prepend + v;},
"Append": function(v) {return v + append;}
}
// to actually get the case function based on the word passed in,
// you can do it this way.
var lowerUpperFunction = String.prototype['to' + whichCase + 'Case'];
var str = lowerUpperFunction.call("xyz");
console.log(str);
var functionsToApply = [];
var out = 'Initial: ' + matrix.join(' | ');
console.log(out);
// see how we just take the whichCase and make that a call to the hash?
functionsToApply.push(functionHash[whichCase]);
if (prepend && prepend.length > 0 && prepend != 'none') {
functionsToApply.push(functionHash["Prepend"]);
}
if (append && append.length > 0 && append != 'none') {
functionsToApply.push(functionHash["Append"]);
}
// Apply all of the transforms to each of the elements of the matrix
matrix = matrix.map(function(row){
return row.map(function(val) {
for (var fn = 0; fn < functionsToApply.length; fn++) {
console.log("applying function to val" + val );
val = functionsToApply[fn](val);
}
return val;
})
});
out = 'Final: ' + matrix.join(' | ');
return out;
}
var p = 'before - ';
var a = ' - after';
var w = 'Upper';
var m = [
['aBc', 'DeF'],
['ghi', 'JKL'],
];
console.log( dynam(w, p, a, m) );
I use this small class function for my javascript code; actually it is somehow altered in the way it 'implements' other classes so that it 'inherets' only functions and not properties (see it at: https://github.com/centurianii/g3OO).
The problem is that it:
1) doesn't give a <object>.constructor.name, see No.3 and 4 at http://jsfiddle.net/A8SkN/3/ (eventually what I want is somehow to have the name of the new class which is stored in a variable-I know it's a complete madness compared with proper OO languages) and
2) doesn't pass any specific static property with name name (but it sees everything else as long as it has a different name!), see No.6 at jsfiddle above.
Here is the Class code:
(function(window, document, undefined){
// Namespace object
var g3;
// Return as AMD module or attach to head object
if (typeof define !== 'undefined')
define([], function () {
g3 = g3 || {};
return g3;
});
else if (typeof window !== 'undefined')
g3 = window.g3 = window.g3 || {};
else{
g3 = g3 || {};
module.exports = g3;
}
g3.Class = function () {
var len = arguments.length;
if(len === 0 || (len === 1 && arguments[0] === null))
return function() {};
var body = arguments[len - 1],
SuperClass = len > 1 ? arguments[0] : null,
implementClasses = len > 2,
Class,
SuperClassEmpty,
i;
//we expect last object to override 'constructor' otherwise the new is empty!
if (body.constructor === Object) {
Class = function() {};
} else {
Class = body.constructor;
delete body.constructor;
}
//'Class.Super' is a reserved word for g3.Class!
if (SuperClass) {
SuperClassEmpty = function() {};
SuperClassEmpty.prototype = SuperClass.prototype;
Class.prototype = new SuperClassEmpty();
Class.prototype.constructor = Class;
//doesn't work!
//Class.prototype.constructor.name = Class.prototype.toString();
Class.Super = SuperClass;
extend(Class, SuperClass, false); //works for static members!
}
if (implementClasses)
for (i = 1; i < len - 1; i++)
if(typeof arguments[i] === 'object')
extend(Class.prototype, arguments[i], false, 'function');
else
extend(Class.prototype, arguments[i].prototype, false);
extendClass(Class, body);
return Class;
};
function extendClass(Class, extension, override) {
//'STATIC' is a reserved word from last argument of g3.Class!
if (extension.STATIC) {
extend(Class, extension.STATIC, override); //overwrites previous parent's static members
delete extension.STATIC;
}
extend(Class.prototype, extension, override);
};
var extend = g3.Class.extend = function (obj, extension, override, type) {
var prop;
if (override === false) {
for (prop in extension)
if (!(prop in obj))
if(!type)
obj[prop] = extension[prop];
else if(typeof extension[prop] === type)
obj[prop] = extension[prop];
} else {
for (prop in extension)
if(!type)
obj[prop] = extension[prop];
else if(typeof extension[prop] === type)
obj[prop] = extension[prop];
if (extension.toString !== Object.prototype.toString)
obj.toString = extension.toString;
}
};
}(window, document));
Let's test Class:
///////TESTS///////
function Person(name){
this.name = name;
}
//Class Dreamer extends Person
var Dreamer = g3.Class(Person, {
STATIC: {
dreams: [],
name: 'Dreamer'
},
constructor: function(name, dream) {
//Explicit call to Dreamer.Super === Person
Dreamer.Super.call(this, name);
this.dream = dream;
},
add: function() {
Dreamer.dreams.push(this.dream);
},
toString: function(){
return 'Dreamer';
}
});
var poet = new Dreamer('Hary', 'I\'ll write a poem today!');
poet.add();
/////PRINT/////
var tests = '<ol><li>poet.toString() = ' + poet.toString() + '</li>';
tests += '<li>poet.constructor = ' + poet.constructor + '</li>';
tests += '<li>poet.constructor.name = ' + poet.constructor.name + '</li>';
tests += '<li>poet.constructor.name == \'\' : ' + (poet.constructor.name === '')+ '</li>';
tests += '<li>poet.prototype = ' + poet.prototype + '</li>';
if(poet.prototype)
tests += '<li>poet.prototype.constructor = ' + poet.prototype.constructor + '</li>';
tests += '<li>Dreamer.name = ' + Dreamer.name + '</li>';
tests += '<li>Dreamer.dreams = ' + Dreamer.dreams + '</li>';
document.getElementById('class').innerHTML = tests + '</ol>';
The results:
1. poet.toString() = Dreamer
2. poet.constructor = function (name, dream)...
3. poet.constructor.name =
4. poet.constructor.name == '' : true //empty string!
5. poet.prototype = undefined
6. Dreamer.name = //empty string!
7. Dreamer.dreams = I'll write a poem today!
Any ideas?
Thanks.