css to json parser freezes the browser-window - javascript

I found some days ago a really nice approach to parse css-strings (even nested) to json. However, it seems, that there's somewhere a big problem in it.
https://github.com/csvplot/cml-parse
If we try to parse a css-string, it will kill the browser window, don't know what's going on here... I already opend an issue but there's no one to answer the issue, since the maintainer David Ellis is lost.
Any ideas/suggestions?
function parse(data) {
var stateStack = [];
var scopeStack = [];
var outObj = {};
while(data) {
// Grab current number of indentation characters
/^(\s*)/.test(data);
// If we've entered any state, and that state is not an explicit block declaration ( {}'s ) and we have an indent level smaller than the most recent indent level,
// then remove the most recent scope level and recall the state back to the previous scope's state
if(stateStack.length &&
stateStack[stateStack.length-1] !== 'explicitBlock' &&
scopeStack.length &&
RegExp.$1.length < scopeStack[scopeStack.length-1].indent) {
scopeStack.pop();
while(stateStack.length && (stateStack[stateStack.length-1] !== 'block' || stateStack[stateStack.length-1] !== 'explicitBlock')) {
stateStack.pop();
}
}
// If current chunk is the key to an object
if(/^(\s*)([^:]*)\s*([{\n])/.test(data)) {
// Grab the indent size of the key and the current outObj position from the scope stack
var indentLength = RegExp.$1.length;
var currScope = (scopeStack.length ? scopeStack[scopeStack.length-1].ref : outObj);
// Split the identifier by spaces and construct/traverse down the defined path
// TODO: Figure out how to handle commas that define the same inner content along multiple paths
RegExp.$2.split(/\s*/).forEach(function(scope) {
if(scope !== '') {
currScope[scope] = currScope[scope] || {};
currScope = currScope[scope];
}
});
// Push the deepest scope and the current indent length onto the scope stack, and push the explicitBlock vs block state onto the state stack
// TODO: Work on a state diagram to truly handle all of the possible states involved properly
scopeStack.push({ref: currScope, indent: indentLength});
stateStack.push(RegExp.$3 === '{' ? 'explicitBlock' : 'block');
// Rip out the handled chunk of data from the string
data = data.replace(/^\s*[^:]*\s*[{\n]/, '');
}
}
return data;
}
http://fiddle.jshell.net/5pTBr/

Running the code, it looks like it just does not work.
It reaches an infinite loop since this regex is failing after the first run:
if(/^(\s*)([^:]*)\s*([{\n])/.test(data)) {
Hence why the browser is stuck. It also does not return the correct JSON.
I'd advise on writing something like this by yourself, or trying to debug and fix the existing code.

Related

How to Efficiently Utilize Objects in Conjunction with HTML Elements

I am getting pretty deep into an employee talent management system website and I am finding out really quick why OOP is so talked about. Being able to efficiently utilize it would change that game for me and make my codebase much more maintainable. I am currently working on a dropdown menu section, and while I have implemented OOP, I can tell from a mile away it is not "good code." It gets the job done but is very messy. I will have an example of the Object and Implementation down below. I have tried watching a few videos on implementing OOP in an existing project, but I keep coming up dry. I understand the basic concepts, but I am not sure how to implement these ideas in a real world application.
Here are some sticking points I am having:
I am not confident I instantiated my objects correctly/efficiently. I have a list of toggleable menus, each representing a candidate in the portal. Well, I created an object for each menu using a for loop. This worked, but it felt unintuitive. When I wanted to attach click events to these menus, I had to loop through them a second time to attached to objects methods as click events.
I felt I had a lot of 'if' statements in my Object. This is because I see myself using the object again in the future, but I do not think each menu will have all the same features. For example, this specific menu had a fade in animation when clicked. But, I doubt every toggleable menu will have this feature. I don't know, I just felt it made the code way more difficult to navigate.
I did not like having to loop through my menu elements and attach methods as click events. This made me have to run an additional for loop and felt 'off'. I was tempted to handle all the event attachments inside the object itself, but I wasn't sure if this is bad practice. It seemed like a good idea and would save a lot of code, but I'm not sure.
Long story short, I can see myself using OOP for forms, buttons, toggleable menus, navbars, (ect.) all over the place. The problem is I am not sure how to actually carry out the process of handling HTML elements and converting them to Objects in a clear and concise manner.
I looked into some design patterns on refactoring.guru, but I felt these concepts were past the scope of what I am trying to do. They all felt like more advanced concepts to take on after getting a solid grip on objects. It was helpful and I really liked the builder pattern. I am currently working on a branch which implements the builder pattern into my current scenario.
Any thoughts, advice, or direction?
Here is an example of the Object and it's Implementation:
TOGGLE MENU OBJECT
class ToggleMenu {
constructor(wrapper, menu, openIcon, closeIcon, title, hiddenMenu) {
this.wrapper = wrapper
this.menu = menu
this.openIcon = openIcon
this.closeIcon = closeIcon
this.title = title
this.hiddenMenu = hiddenMenu
this.toggled = false
}
props() {
console.log(this.menu)
console.log(this.openIcon)
console.log(this.closeIcon)
console.log(this.title)
console.log(this.hiddenMenu)
console.log(this.toggled)
}
openHiddenMenu(config) {
if (config == undefined){
config = {}
}
if (config.menuBackGroundColor !== undefined){
this.menu.style.backgroundColor = config.menuBackGroundColor
}
if (config.titleColor !== undefined){
this.title.style.color = config.titleColor
}
if (config.hiddenMenuDisplay !== undefined){
this.hiddenMenu.style.display = config.hiddenMenuDisplay
}
if (config.hiddenMenuAnimation !== undefined){
this.hiddenMenu.style.animationName = config.hiddenMenuAnimation
}
if(config.menuAnimation !== undefined){
this.menu.style.animationName = config.menuAnimation
}
this.openIcon.style.display = 'none'
this.closeIcon.style.display = 'block'
this.toggled = true
}
closeHiddenMenu(config){
if (config == undefined){
config = {}
}
if (config.menuAnimation !== undefined && this.toggled == true){
this.menu.style.animationName = config.menuAnimation
}
this.menu.style.backgroundColor = ''
this.openIcon.style.display = ''
this.closeIcon.style.display = ''
this.title.style.color = ''
this.hiddenMenu.style.display = ''
this.toggled = false
}
}
IMPLEMENTATION
const initCandidateMenus = () => {
let candidateToggleMenus = document.getElementsByClassName('candidate-toggle-menu')
let candidateToggleWrappers = document.getElementsByClassName('candidate-toggle-menu-wrapper')
let hiddenMenus = document.getElementsByClassName('hidden-candidate-menu')
let toggleMenus = []
//collecting toggle menu objects
for (x = 0; x < candidateToggleMenus.length; x++){
let toggleMenu = new ToggleMenu(
candidateToggleWrappers[x],
candidateToggleMenus[x],
candidateToggleMenus[x].getElementsByClassName('candidate-open-icon')[0],
candidateToggleMenus[x].getElementsByClassName('candidate-close-icon')[0],
candidateToggleMenus[x].getElementsByClassName('candidate-name')[0],
hiddenMenus[x],
)
toggleMenus.push(toggleMenu)
}
//looping through toggle menu objects
for (x = 0; x < toggleMenus.length; x++){
let currentMenu = toggleMenus[x]
currentMenu.openIcon.addEventListener('click', () => {
//closing all other toggle menus
for (y = 0; y < toggleMenus.length; y++){
toggleMenus[y].closeHiddenMenu()
}
//opening current menu
currentMenu.openHiddenMenu({
menuBackGroundColor: 'var(--main-clr)',
titleColor: 'var(--white)',
menuAnimation: 'fade-title-color',
hiddenMenuDisplay: 'flex',
hiddenMenuAnimation: 'open-hidden-menu'
})
})
currentMenu.closeIcon.addEventListener('click', () => {
//closing current menu
currentMenu.closeHiddenMenu()
})
}
}
ok this isn’t really an answer, but more of just advice that I need to use code for.
I noticed that you didn’t implement a lot of common features that can reduce lines and characters, so I’ll point them out here
For the class functions, you did this:
openHiddenMenu(config) {
if (config == undefined){
config = {}
}
Which can be simplified to this:
openHiddenMenu(config = {}) {
// Completely remove the entire if statement
Putting an equal sign in the parameter will assign a default value if it isn’t defined.
Another thing is checking if something is undefined:
if (config.menuBackGroundColor !== undefined){
this.menu.style.backgroundColor = config.menuBackGroundColor
}
if (config.titleColor !== undefined){
this.title.style.color = config.titleColor
}
if (config.hiddenMenuDisplay !== undefined){
this.hiddenMenu.style.display = config.hiddenMenuDisplay
}
if (config.hiddenMenuAnimation !== undefined){
this.hiddenMenu.style.animationName = config.hiddenMenuAnimation
}
if(config.menuAnimation !== undefined){
this.menu.style.animationName = config.menuAnimation
}
Instead you could remove the ‘!== undefined’ part, because any value that is ‘falsey’ (0, NULL, undefined, NaN) will also return false. So if it has a value and isnt 0, it will return true.
Plus since it’s only 1 line, you can remove brackets:
if (config.menuBackGroundColor)
this.menu.style.backgroundColor = config.menuBackGroundColor
if (config.titleColor)
this.title.style.color = config.titleColor
if (config.hiddenMenuDisplay)
this.hiddenMenu.style.display = config.hiddenMenuDisplay
if (config.hiddenMenuAnimation)
this.hiddenMenu.style.animationName = config.hiddenMenuAnimation
if(config.menuAnimation)
this.menu.style.animationName = config.menuAnimation
If you wanted to simplify even further, you could use an or operator ||, so if the value is falsey, it will become the other value. This doubles as a default value.
this.menu.style.backgroundColor = config.menuBackGroundColor || // Default value
this.title.style.color = config.titleColor || // Default value
this.hiddenMenu.style.display = config.hiddenMenuDisplay || // Default value
this.hiddenMenu.style.animationName = config.hiddenMenuAnimation || // Default value
this.menu.style.animationName = config.menuAnimation || // Default value
There are some other things you can do, but this answer is insanely long and I’m writing this late at night. Hope this helps though

Binary Search Tree Syntax

For this portion of an implementation of a binary search tree in JS, what is the significance of referring to "this._root"? (why can't they say "this.root")? The link for this is available at http://www.nczonline.net/blog/2009/06/16/computer-science-in-javascript-binary-search-tree-part-2/
BinarySearchTree.prototype = {
//more code here
remove: function(value){
var found = false,
parent = null,
current = this._root,
childCount,
replacement,
replacementParent;
//make sure there's a node to search
while(!found && current){
//if the value is less than the current node's, go left
if (value < current.value){
parent = current;
current = current.left;
//if the value is greater than the current node's, go right
} else if (value > current.value){
parent = current;
current = current.right;
//values are equal, found it!
} else {
found = true;
}
}
//only proceed if the node was found
if (found){
//continue
}
},
//more code here
};
They may be trying to indicate that this variable should not be accessed outside of the object (private in other languages).
Python has a strong convention of using names starting with underscore character to indicate that this field or method is private. The author may be trying to apply the same convention to javascript.
I suppose that more complete example is located here: https://github.com/nzakas/computer-science-in-javascript/blob/master/data-structures/binary-search-tree/binary-search-tree.js
Regarding this._root - I think it's author's decision only, without any special meaning.

looping through objects to return objects with 'distinct' property - Javascript

I have a list of objects as shown in the image.
These all have the property statusCode: 62467 but the journey property goes like: 0,1,2,3,3,4,4,4,4
I want to loop through these objects and return the FIRST of the duplicated (they are not the same object, just that both have the same journey number and the same status code) objects with the same journey number.
So I want to return the bold objects: 0,1,2,3,3,4,4,4,4
$.each(points, function (index, point) {
for (i = 0; i < journeyNumber.length; i++) {
if (point.k.journey === journeyNumber[i] && point.k.statusCode === '62467') {
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
}
});
The screenshot is the log of console.log(point), so ideally I would like another loop inside which returns only the first object of the same journey number.
Hope this makes sense and thank you for your time.
Try this,
var temp = [];
$.each(points, function (index, point) {
if (temp.indexOf(point.k.journey) === -1) {
temp.push(point.k.journey);
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
});
Create a fresh object with status codes and check against that.
var journeys = {};
for(object in points){
// extract the properties you want (or use them directly, this is not necessary)
var journey = points[object].journey;
var status = points[object].statusCode;
// use the typeof operator to see if the journey has already been set before
if(typeof journeys[journey] == "undefined"){
// then define it.
journeys[journey] = status;
}
}
(Please note I am not actually correctly referencing the journey and statusCode, you'd have to do something like objects[object][k].journey to access the right property, but thats not really the point)
You can even add anything you want into the journeys object, nesting another object with the extracted latitude and longitude, or even just nesting the entire object in the journey!
journeys[journey] = points[object];
Now you can get every journey by looping through them again, and the associated first statusCode:
for(journey in journeys){
console.log("First instance of journey " + journey + " had statusCode " + journeys[journey]);
}

Setting a Javascript if statement with 2 requirements to one line

var status = result.locations[index].status;
var operator = result.locations[index].operator;
var original = result.locations[index].original;
var produced = result.locations[index].produced;
var href = result.locations[index].more;
I have the above which each need to be an if statement to check if there is content and my output is the below code.
if (result.locations[index] && result.locations[index].status){
var status = result.locations[index].status;
} else {
var status = '';
}
I would need to reproduce this per line from the code at the top of the post. What would be the best method to simplify each down to keep the code neater and not produce 5 lines of if statement when 1 or 2 would do.
var status = (result.locations[index] && result.locations[index].status ? result.locations[index].status : '');
Not sure why you want to, but:
var status = (result.locations[index] && result.locations[index].status) ? result.locations[index].status : ""
Your problem is trying to access a property of a "deep" javascript object using its path.
This is a common question :
Javascript: Get deep value from object by passing path to it as string
Accessing nested JavaScript objects with string key
There is no built-in way to do this in javascript.
There are plenty of libraries to do that, for example, with selectn, this would become something like (I have not tested it, so I don't know if the index part will work, but you get the idea) :
var status = selectn("locations." + index + ".status", result) || ''
If the structure of your objects is always the one above (that is, the property is just at one level of depth), and you're not expecting 'falsy', you could simply write the 'test' function yourself :
function safeGet(instance, propertyName, defaultValue) {
// As pointed by AlexK, this will not work
// if instance[propertyName] can be anything Falsy ("", 0, etc...)
// If it's possible, get a library that will do
// the full series of insane checks for you ;)
if (instance && instance[propertyName)) {
return instance[propertyName];
} else {
return defaultValue;
}
}
var location = result.locations[index]; // Potentially undefined, but safeGet will deal with it
var status = safeGet(location, "status", "");
var operator = safeGet(location, "operator", "DEFAULT_OPERATOR");
...
var status = result.locations[index] && result.locations[index].status || '';
However, better maje sure before, if result.locations[index] exists... else do whatever is to be done in your code..

Store a table row index as an array index

There a simple function:
selected_row = []; // global scope
function toggleRowNumber(rowIndex) {
if(selected_row[rowIndex]) selected_row.splice(rowIndex, 1);
else selected_row[rowIndex] = 1;
}
usage
toggleRowNumber(50000); // click the row - write the index
toggleRowNumber(50000); // click the row again - remove the inxed
alert(selected_row.length);
50001
OK
Delightful feature!
So is there a way to direct write|read an index without any searchin/looping? And without this huge feat as decribed above.
Thanks.
If I understoold correctly, you want to store and index where you can check/set whether an item is selected or not. If that is the case, you are looking for a "key - value" data structure. Then, why not use a map?
var selected_row = {};
function toggleRowNumber(rowIndex) {
if(selected_row[rowIndex]) selected_row[rowIndex] = 0; //or = undefined;
else selected_row[rowIndex] = 1;
}
That is better because hash map will save you time and space.
Space becuase you are not storing hundreds of 'undefined' values in a vector.
Time because, hash function used to access elements is pretended to hit the right position in many cases.

Categories