How to concatenate two NodeList objects into one, avoiding duplicates - javascript

I am writing a few functions to simplify my interaction with Javascript Nodes, here is the source-code so far:
Node.prototype.getClasses = function() {
return this.className ? this.className.split(" ") : "";
};
Node.prototype.hasClass = function(c) {
return this.getClasses().indexOf(c) >= 0;
};
Node.prototype.addClass = function(c) {
if (!this.hasClass(c)) {
this.className += " " + c;
}
return this;
};
Node.prototype.removeClass = function(c) {
if (this.hasClass(c)) {
var classes = this.getClasses();
var newClasses = [];
for (var index = 0; index < classes.length; index++) {
if (classes[index] !== c) {
newClasses.push(classes[index]);
}
}
this.className = newClasses.join(" ");
}
return this;
};
function NodeCollection(nodes) {
this.nodes = nodes;
this.addClass = (c) => {
for (var nodeIndex = 0; nodeIndex < this.nodes.length; nodeIndex++) {
this.nodes[nodeIndex].addClass(c);
}
return this.nodes;
};
this.removeClass = (c) => {
for (var nodeIndex = 0; nodeIndex < this.nodes.length; nodeIndex++) {
this.nodes[nodeIndex].removeClass(c);
}
return this.nodes;
};
this.getHTML = () => {
var output = "";
for (var nodeIndex = 0; nodeIndex < this.nodes.length; nodeIndex++) {
output += this.nodes[nodeIndex].outerHTML;
}
return output;
};
this.each = (f) => {
for (var nodeIndex = 0; nodeIndex < this.nodes.length; nodeIndex++) {
f(this.nodes[nodeIndex]);
}
return this.nodes;
};
}
Node.prototype.query = function(s) {
return new NodeCollection(this.querySelectorAll(s));
};
Node.prototype.siblings = function(s) {
var rawSiblings = this.parentNode.querySelectorAll(s);
var output = [];
for (var siblingIndex = 0; siblingIndex < rawSiblings.length; siblingIndex++) {
if ((rawSiblings[siblingIndex].parentNode === this.parentNode) && (rawSiblings[siblingIndex] !== this)) {
output.push(rawSiblings[siblingIndex]);
}
}
return new NodeCollection(output);
};
Everything is working great and I am quite content with these functions, I have managed to prevent a lot of headaches without the usage of Javascript frameworks (a hobby project).
Now, I would like to be able to write a query function for NodeCollection as well, however, I am not quite aware of how should I concatenate the nodes members of the NodeCollection objects, which are instances of NodeList. I would like to write something like this as a member function of NodeCollection:
this.query = (s) => {
//create an empty NodeList
for (var index = 0; index < this.nodes.length; index++) {
//concat this[nodes][index] to the node list created outside the
//cycle avoiding possible duplicates
}
//return the concatenated NodeList
};
How can I achieve this?

How to concatenate two NodeList objects into one, avoiding duplicates
Use isSameNode and Array.from
Array.from( nodeList1 ).forEach( function( ele, index ){
var isDuplicate = Array.from( nodeList2 ).some( ( ele2 ) => ele.isSameNode(ele2) );
if ( !isDuplicate )
{
nodeList2[ nodeList2.length ] = ele;
}
})
Now nodeList2 has all the nodes from nodeList1 which are not duplicates.
Demo
var nodeList1 = Array.from( document.querySelectorAll(".a") );
var nodeList2 = Array.from( document.querySelectorAll(".b") );
console.log( "original length " + nodeList1.length, nodeList2.length );
nodeList1.forEach(function(ele, index) {
var isDuplicate = nodeList2.some( ele2 => ele.isSameNode(ele2));
//console.log( ele, isDuplicate );
if (!isDuplicate) {
nodeList2.push( ele );
}
});
console.log( "Final length " + nodeList1.length , nodeList2.length );
<div class="a b"></div>
<div class="a"></div>
<div class="b"></div>
<div class="a b"></div>

Related

Trying to make a function that returns selected CSS properties but is pretty laggy

I was trying to make a function that gives you the selected CSS properties of an element those you want. But it's pretty laggy if used in console as of it needs to get and match all CSS properties.
function styleOf(elementUseSelectors, propertiesToCheck, tellInConsole) {
var element = elementUseSelectors;
var Arguments = propertiesToCheck;
var calculatedProperties = [];
var matchedProperties = [];
if (tellInConsole !== undefined && tellInConsole == true) {
console.warn("Running styleOf() Please Don't Do Other Calculations This Function Disables Console.")
}
for (var i = 0; i < Object.keys(getComputedStyle(element)).length; i++) {
var value = getComputedStyle(element).getPropertyValue(Object.entries(getComputedStyle(element))[i][0].replace(/([A-Z])/g, ' $1').trim().replaceAll(" ", "-").toLowerCase());
if (value !== "") {
calculatedProperties.push(Object.entries(getComputedStyle(element))[i][0].replace(/([A-Z])/g, ' $1').trim().replaceAll(" ", "-").toLowerCase() + ": " + value);
}
}
for (var i = 0; i < calculatedProperties.length; i++) {
for (var a = 0; a < Arguments.length; a++) {
if (calculatedProperties[i].includes(Arguments[a])) {
window.splitted = calculatedProperties[i].split("");
window.joinThis = [];
for (var k = 0; k < splitted.indexOf(":"); k++) {
joinThis.push(splitted[k]);
};
if (joinThis.join("") == Arguments[a]) {
matchedProperties.push(calculatedProperties[i]);
}
}
}
}
if (tellInConsole !== undefined && tellInConsole == true) {
console.warn("StyleOf() Calculations Completed You Can Now Use Console.")
}
return matchedProperties
}
The TreeWalker object is designed to quickly parse DOM nodes in a document. If you expand on the example given above in the MDN Web Docs you can output the computed CSS properties for a given node.
The first property of the method is the node you want to traverse – in this case it's document.body:
var treeWalker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
);
var nodeList = [];
var currentNode = treeWalker.currentNode;
while(currentNode) {
nodeList.push(currentNode);
const style = getComputedStyle(currentNode)
console.log(style)
currentNode = treeWalker.nextNode();
console.log("moving to next node...");
}
Welp #kaiido answered the question.
function styleOf(element, properties) {
const computed = getComputedStyle(element);
return properties.map( key => key + ": " + computed[ key ] )};
var style = styleOf(document.getElementsByTagName("body")[0], ["height", "width", "background-color", "font-size", "color", "font-family"]);
console.log(style);

Why does Promise.all().then() still make the output synchronous?

I am working on an exercise on Javascript and the point is to make everything work in an asynchronous way. The exercise goes like this: To have an array that is to be filled with random numbers. Then the max element of this array will be the length of a rectangular 2D-Array. For every unique element in the array that is to be used as an index in the 2D-array, i must find the sum of the rows and columns in the 2D-array, as well as the sum of the surrounding elements in the 2D-array. These tasks need to be done separately, and i used Promises. But when i log on the console to see how the work is taking place, it still outputs it synchronously, or even worse it starts searching on the arrays even before they are filled. I am new to this, so i need some guidance.
var arrayA = [];
var matricaA = [];
var n=10;
var m;
var arr = [];
var k = 0;
var funcMatrixHolder = [];
var result = [];
function genRandomNum(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
function fillArray(n) {
return new Promise(function(resolve,reject) {
arrayA = Array.from({length: n}, () => genRandomNum(1,10));
m = arrayA[0];
arrayA.filter(function(pos){
if(pos > m) {
m = pos;
}
resolve(m);
});
});
}
function createMatrix(size) {
return new Promise(function(resolve, reject){
arr = Array.from({length: size}, () => genRandomNum(1,10));
//console.log(arr);
resolve(arr);
});
}
function sumRowCol(matrix, len, arr) {
return new Promise(function(resolve, reject) {
var shuma=0;
arr.filter(function(elem, pos) {
var poz = elem-1;
if(arr.indexOf(elem) === pos) { //per cdo element unik
for(var k = 0; k<len; k++){
sum+=matrix[k][poz];
sum+=matrix[poz][k];
//console.log(k);
//
}
}
resolve(sum);
console.log(sum+" sum"); //to check how it works
sum=0;
})
});
}
function sumNr(myArray, arr) {
return new Promise(function(resolve, reject){
var sum = 0;
arr.filter(function(elem, pos) {
var rowLimit = myArray.length-1;
var columnLimit = myArray[0].length-1;
var i = elem-1;
var j = elem-1
if(arr.indexOf(elem) === pos) { //per cdo element unik
for(var x = Math.max(0, i-1); x <= Math.min(i+1, rowLimit); x++) {
for(var y = Math.max(0, j-1); y <= Math.min(j+1, columnLimit); y++) {
if(x !== i || y !== j) {
sum += myArray[x][y];
//
}
}
}
console.log(sum + "sum");
resolve(sum);
sum = 0;
}
})
})
}
fillArray(n).then(function(result) {
//filled array and got it's max
});
while(k<m) {
funcMatrixHolder.push(createMatrix(m));
k++;
}
//console.log(funcMatrixHolder);
Promise.all(funcMatrixHolder).then(function(result) {
matricaA = result;
});
Promise.all([sumNr(matricaA,arrayA),sumRowCol(matricaA,m,arrayA)]).then(function(result){
console.log(result);
});
Just in case, this is the answer that got approved as correct:
(Excuse the non-english labels)
var arrayA = [];
var matricaA = [];
var n=10;
var m;
var arr = [];
var k = 0;
var funcMatrixHolder = [];
var result_final = [];
var filterArr = [];
var result_final_final = [];
function genRandomNum(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
function fillArray(n) {
return new Promise(function(resolve,reject) {
arrayA = Array.from({length: n}, () => genRandomNum(1,10));
m = arrayA[0];
arrayA.filter(function(elem, pos){
if(elem > m) {
m = elem;
}
if(arrayA.indexOf(elem) === pos) {
filterArr.push(elem);
}
});
var fArrPH = {
max: m,
fArr: filterArr
}
resolve(fArrPH);
});
}
function createMatrix(size) {
return new Promise(function(resolve, reject){
arr = Array.from({length: size}, () => genRandomNum(1,10));
//console.log(arr);
resolve(arr);
});
}
function fillArrayFunction(size) {
return new Promise(function(resolve, reject) {
for (var i=0; i<size; i++){
funcMatrixHolder.push(createMatrix(size));
}
resolve(funcMatrixHolder);
})
}
function shumaRreshtKolone(matrix, index, madhesia) {
let shuma=0;
//console.log(madhesia);
for(var k = 0; k<madhesia; k++){
//console.log(index);
//index = 10;
shuma+=matrix[k][index];
shuma+=matrix[index][k];
}
console.log("ShumaRreshtKolone u llogarit.");
return shuma;
}
function sumNrRrethues(myArray, index) {
var sum = 0;
var rowLimit = myArray.length-1;
var columnLimit = myArray[0].length-1;
var i = index-1;
var j = index-1
for(var x = Math.max(0, i-1); x <= Math.min(i+1, rowLimit); x++) {
for(var y = Math.max(0, j-1); y <= Math.min(j+1, columnLimit); y++) {
if(x !== i || y !== j) {
sum += myArray[x][y];
}
}
}
console.log("ShumaNrRrethues u llogarit");
return sum;
}
var m1;
function job() {
return new Promise(function(resolve,reject) {
fillArray(n).then(function(result) {
//console.log("array", result);
m1 = result;
return fillArrayFunction(result.max);
}).then(function(result) {
Promise.all(result).then(function(result) {
matricaA = result;
console.log(matricaA);
console.log(arrayA);
m1.fArr.map(function(item) {
//console.log("item", item);
return result_final.push({
Elementi: m1.fArr.indexOf(item),
ShumaRreshtKolone: shumaRreshtKolone(matricaA,item-1,m1.max),
ShumaNrRrethues: sumNrRrethues(matricaA, item-1)
});
});
resolve(result_final);
}).catch(err => {
reject(err);
})
})
})
}
job().then(function(result){
console.log(JSON.stringify(result));
}).catch(err => {
console.log(err);
})

implementing split() method for exercise 4 in Object Oriented Javascript 2n edition

here is the question:
Imagine the String() constructor didn't exist. Create a constructor
function, MyString(), that acts like String() as closely as possible.
You're not allowed to use any built-in string methods or properties,
and remember that String() doesn't exist. You can use this code to
test your constructor:
I created constructor however I have no clue how to re-create split method, how to implement that functionality.
If you could give an idea how to implement split method, I would be grateful
function MyString(str) {
var thisObj = this;
var innerLength = 0;
this.length;
function updateLength() {
innerLength = 0;
for (var i = 0; str[i] != undefined; i++) {
innerLength++;
thisObj[i] = str[i];
}
thisObj.length = innerLength;
}
updateLength();
this.toString = function() {
return str;
}
this.charAt = function(i) {
if (isNaN(parseInt(i))) {
return this[0]
} else {
return this[i]
}
}
this.concat = function(string) {
str += string;
updateLength();
}
this.slice = function(start, end) {
var slicedString = "";
if (start >= 0 && end >= 00) {
for (start; start < end; start++) {
slicedString += str[start];
}
}
return slicedString;
}
this.reverse = function() {
var arr = str.split("");
arr.reverse();
var reversedString = "",
i;
for (i = 0; i < arr.length; i++) {
reversedString += arr[i];
}
return reversedString;
}
}
var ms = new MyString("Hello, I am a string")
console.log(ms.reverse())
You can convert the string to an array and use Array.prototype and RegExp.prototype methods.
this.split = function(re) {
var arr = Array.prototype.slice.call(this.toString());
if (re === "") {
return arr
}
if (re === " ") {
return arr.filter(function(el) {
return /[^\s]/.test(el)
})
}
if (/RegExp/.test(Object.getPrototypeOf(re).constructor)) {
var regexp = re.source;
return arr.filter(function(el) {
return regexp.indexOf(el) === -1
})
}
}
function MyString(str) {
var thisObj = this;
var innerLength = 0;
this.length;
function updateLength() {
innerLength = 0;
for (var i = 0; str[i] != undefined; i++) {
innerLength++;
thisObj[i] = str[i];
}
thisObj.length = innerLength;
}
updateLength();
this.toString = function() {
return str;
}
this.split = function(re) {
var arr = Array.prototype.slice.call(this.toString());
if (re === "") {
return arr
}
if (re === " ") {
return arr.filter(function(el) {
return /[^\s]/.test(el)
})
}
if (/RegExp/.test(Object.getPrototypeOf(re).constructor)) {
var regexp = re.source;
return arr.filter(function(el) {
return regexp.indexOf(el) === -1
})
}
}
this.charAt = function(i) {
if (isNaN(parseInt(i))) {
return this[0]
} else {
return this[i]
}
}
this.concat = function(string) {
str += string;
updateLength();
}
this.slice = function(start, end) {
var slicedString = "";
if (start >= 0 && end >= 00) {
for (start; start < end; start++) {
slicedString += str[start];
}
}
return slicedString;
}
this.reverse = function() {
var arr = str.split("");
arr.reverse();
var reversedString = "",
i;
for (i = 0; i < arr.length; i++) {
reversedString += arr[i];
}
return reversedString;
}
}
var ms = new MyString("Hello, I am a string")
console.log(ms.split(""), ms.split(" "), ms.split(/l/))
Iterate and search:
MyString.prototype.split = function(splitter){
var tmp="", result = [];
for(var i = 0; i < this.length; i++){
for(var offset = 0; offset < this.length && offset < splitter.length;offset++){
if(this[i+offset] !== splitter[offset]) break;
}
if(offset === splitter.length){
result.push( tmp );
tmp="";
i += offset -1;
}else{
tmp+=this[i];
}
}
result.push(tmp);
return result;
};
So now you can do:
new MyString("testtest").split("t") //['','es','','','es','']
In action

Would like to create an array with number of matches for specific regexs

Would like to create an array with number of matches for specific regexs:
So if january was found 5 times , feb 3 the table would be:
monthFound=[5,3......]
function findMonth(){
var fpath='log.txt';
var monthFound=[]
fs.readFileSync(fpath).toString().split('\n').forEach(function(line)
{
var regExpressions1=[/-jan-/,/-feb-/,/-mar-/,/-apr-/,/-may-/,/-jun-/,/-jul-/,/-aug/,/-sep-/,/-oct-/,/-nov/,/-dec-/];
for (var i = 0; i<regExpressions1.length;i++)
{
var idx = line.match(regExpressions1[i]);
if (idx !== null) {
y++;
}
}
});
}
This will return an array with each month match count:
fs.readFileSync(fpath).toString().split('\n').reduce((count, str) => {
['-jan-','-feb-','-mar-','-apr-','-may-','-jun-','-jul-','-aug-','-sep-','-oct-','-nov-','-dec-'].forEach((month, idx) => {
const match = (str.match(new RegExp(month, 'g')) || []).length;
if (count[idx]) {
count[idx] += match;
} else {
count[idx] = match;
}
});
return count;
}, []);
Use this :
function findMonth(){
var fpath='log.txt';
var monthFound=[]
fs.readFileSync(fpath).toString().split('\n').forEach(function(line) {
var regExpressions1=["-jan-","-feb-","-mar-","-apr-","-may-","-jun-","-jul-","-aug-","-sep-","-oct-","-nov-","-dec-"];
for (var i = 0; i<regExpressions1.length;i++) {
var idx = line.match(new RegExp(Expressions1[i]));
monthFound[i] === idx.length
}
});
}

How to check the object property in javascript

I have an array like below
var colorArray = ["#a", "#b", "#c", "#d", "#e"];
From this I will generate a map like this
function initilizeColorMap(){
for(var i = 0 ;i <colorArray.length ;i++){
colorTrackingMap[i] = {value: colorArray [i],state:"unused"};
}
}
Hopw i can iterate through the map when i need a color (next color from the map ) by checking the state in javascript..?
You can have a method that will return the next color. Check out this jsfiddle : http://jsfiddle.net/QYWDb/
var colorArray = ["#a", "#b", "#c", "#d", "#e"];
var colorTrackingMap = [];
var currentIndex = -1;
for(var i = 0 ;i <colorArray.length ;i++){
colorTrackingMap[i] = {value: colorArray [i],state:"unused"};
}
function getNextColor() {
if (currentIndex > colorTrackingMap.length)
currentIndex = 0;
else
currentIndex++;
while ( colorTrackingMap[currentIndex] !== undefined &&
colorTrackingMap[currentIndex].state !== "unused" ) {
currentIndex++;
}
if ( colorTrackingMap[currentIndex] )
return colorTrackingMap[currentIndex].value;
else
return "No color available";
}
If you need color according to given index you don't have to iterate, use such code:
var currentIndex = 0;
function Next() {
var tracking = colorTrackingMap[currentIndex];
alert("color: " + tracking.value + ", state: " + tracking.state);
currentIndex++;
if (currentIndex >= colorTrackingMap.length)
currentIndex = 0;
}
Live test case.
If you mean searching the array for item with specific value, just use ordinary loop:
function Find() {
var color = document.getElementById("color").value;
var state = "";
for (var i = 0; i < colorTrackingMap.length; i++) {
if (colorTrackingMap[i].value.toLowerCase() === color) {
state = colorTrackingMap[i].state;
break;
}
}
if (state.length == 0) {
alert("color isn't mapped");
} else {
alert("state: " + state);
}
}
You can also pass the color as function argument, this is just for sake of example.
Updated test case.
You could use something like this:
var ColourMap = function (arr) {
var _map = [],
out = [],
i,
len;
// Set up the colour map straight away
for (i = 0, len = arr.length; i < len; i++) {
_map.push({
value: arr[i],
state: "unused"
});
}
return {
get_next: function () {
var i,
len,
next;
for (i = 0, len = _map.length; i < len; i++) {
if (_map[i].state === "unused") {
next = _map[i];
break;
}
}
return next;
}
}
};
And then use something like:
var m = new ColourMap(["#a", "#b", "#c", "#d", "#e"]);
m.get_next(); // get the next available element
Here's a working example.

Categories