I'm building a browser-based app which allows users to create folders with some .json files (not big deal). The thing is, the framework that I'm using (NW.js) doesn't appears to care about allowing users to create folders named "CON" or "NUL"; These are not supposed to be created, the files inside just vanish and it's somewhat difficult to delete the folder themselves.
I can no problem make something like this to prevent to happen:
var newFolder = "nul";
function checkFolderName(text) {
switch(newFolder) {
case "con":
console.log("folder can't be created")
break;
case "nul":
console.log("folder can't be created")
break;
// and so on... there's about 23 windows-reserved names that I could find
default:
console.log("folder can be created")
}}
checkFolderName(newFolder);
But I wonder if there is some easier way to check this through Regex/Javascript, or maybe some different approach to this idea.
Here's a little cleaner way to write what you want.
Function renamed to imply that it takes a string and returns a boolean.
If the input string is invalid, returns false.
All banned names are grouped together in an easily updated list.
Validity is checked by if the list contains the name.
function folderNameIsValid (name) {
let valid = false;
if (!name || typeof(name) !== 'string') {
return valid;
}
const bannedNames = [
'con',
'nul'
];
if (!bannedNames.includes(name.toLowerCase())) {
valid = true;
}
return valid;
}
if (folderNameIsValid('NUL')) {
console.log('folder can be created');
} else {
console.log('folder cannot be created');
}
My friend could help me to do this with regex:
let valid = /^(con|prn|aux|nul|com|lpt)\d*$/gi.test(newFolder)
console.log(valid) // true or false
However, it's starts to get pretty clanky if you want to add more "banned names", so jaredcheeda's suggestion it's pretty handy in this case
If you want to use regex you can do it like this:
if (/^con|nul|abc|xyz$/.test(newFolder))
console.log("folder can't be created");
The | character means 'or'. so the test function will return true if newFolder is "con" or "nul" or "abc" or "xyz"
The ^ and the $ sign are the beginning and the ending of the string.
If you want to know exactly what was the illegal part, you can use this:
var matching = newFolder.match(/^con|nul|abc|xyz$/);
if (matching) {
console.log("folder can't be created, found " + matching[0]);
}
You can also use this notation of switch case:
switch (newFolder)
{
case "con":
case "nul":
case "abc":
case "xyz":
console.log("folder can't be created");
break;
default:
console.log("folder can be created");
}
Related
In Javascript, is there a way to achieve something similar to this ?
const databaseObjectID = "someId"; // like "product/217637"
switch(databaseObjectID) {
case includes('product'): actionOnProduct(databaseObjectID); break;
case includes('user'): actionOnUser(databaseObjectID); break;
// .. a long list of different object types
}
This is more a curiosity question to understand the possibilities of switch / case, as in this particular case I have solved my problem using const type = databaseObjectID.split('/')[0]; and apply the switch case on type
This will work, but it shouldn't be used in practice.
const databaseObjectID = "someId"; // like "product/217637"
switch(true) {
case databaseObjectID.includes('product'): actionOnProduct(databaseObjectID); break;
case databaseObjectID.includes('user'): actionOnUser(databaseObjectID); break;
// .. a long list of different object types
}
You usage would be considered an abuse of case.
Instead just use ifs
if (databaseObjectId.includes('product')) actionOnProduct(databaseObjectID);
else if (databaseObjectId.includes('user')) actionOnUser(databaseObjectID);
// .. a long list of different object types
If the ObjectId contains static content around the product or user, you can remove it and use the user or product as a key:
var actions = {
"product":actionOnProduct,
"user" :actionOnUser
}
actions[databaseObjectId.replace(/..../,"")](databaseObjectId);
Sorry, I'm a noob so someone will probably have to clean this up, but here is the idea. Pass to a function to check and return a category then use the switch.
function classify(string){
var category = categorize(string);
switch (category) {
case 'product':
console.log('this is a product');
break;
case 'user':
console.log('this is a user');
break;
default:
console.log('category undefined');
}
}
function categorize(string){
if (string.includes('product')){
return 'product';
}
if (string.includes('user')){
return 'user';
}
}
classify("product789");
classify("user123");
classify("test567");
Sorry, as well, for not matching your example.
Question:
use string “includes()” in switch Javascript case
While the includes() method will work, it is case sensitive, and just matches any characters. I have found a Regex solution that I like much better, and provides a lot of flexibility. For example, you could easily change this to match only WORDS.
var sourceStr = 'Some Text and literaltextforcase2 and more text'
switch (true) { // sourceStr
case (/LiteralTextForCase1/i.test(sourceStr)):
console.log('Case 1');
break;
case (/LiteralTextForCase2/i.test(sourceStr)):
console.log('Case 2');
break;
default:
console.log('ERROR No Case provided for: ' + sourceStr);
};
//-->Case 2
I am learning JavaScript so that I can implement Google Tag Manager. I have a list of paths that I would like GTM to rewrite to something friendlier like so:
function() {
return document.location.pathname.indexOf('/l/138281/2016-06-07/dy383') > -1 ? 'Test Success' : undefined;
}
function() {
return document.location.pathname.indexOf('/l/138281/2016-04-03/55z63') > -1 ? 'SPP Contact Success' : undefined;
I'm just not sure how to combine these returns into one function (I currently have about 30 URLs to rewrite). I imagine I can use if/else, but advice would be quite lovely.
--edit--
URL Path Rewrite To
/test-638-jsj /test-success
/spp-zxcv-765 /spp-contact-success
/foo-asdf-123 /foo
/foo-bar-987 /foo-bar
The return function mentioned above does this beautifully for an individual link. I just want to be able to rewrite a series of URLs in one function (or however it makes sense to do this most specifically). Hopefully that helps clarify.
Thanks!
It is always a great idea to structure your code: separate abstract functionality from the specific problem.
What you are actually doing is scannins strings for occurences of keywords and returning specific values if such a keyword has been found.
Therefore, you need a function performing the above computation and a JavaScript datastructure holding your keywords and their values (= Object):
// Return patterns[key] if any key is found in string, else return string:
function match(string, patterns) {
for (key of Object.keys(patterns)) {
if (string.indexOf(key) > -1) return patterns[key];
}
return string;
}
var patterns = {
'/l/138281/2016-06-07/dy383': 'Test Success',
'/l/138281/2016-04-03/55z63': 'SPP Contact Success'
}
console.log(match('/l/138281/2016-06-07/dy383', patterns)); // "Test Success"
console.log(match('/doesnotexist', patterns)); // "/doesnotexist"
console.log(match(document.location.pathname, patterns));
I need to do a search on a text field (mongodb). The Search criteria / filter on the collection can be any substring of the sting in the field. I save the filter (input) in a session variable. The filter seems to work the first time after the Sessionvariable is null.
After the first search I get no result when I enter a new (extisting!) value. In case I clear the filter, hit enter and than reenter the filter I get the result.
I assume that my code is suboptimal. Can someone please review and maybe make a suggestion?
Here is what I have:
html:
<input class="medinput" maxlength="80" type="text" name="nameSearchBar" id="nameSearchBar" value="{{searchText}}">
javascript:
Session.setDefault('searchText', null);
Template.questions.helpers({
questions:function(){
if ((Session.get('searchText') === null) || (Session.get('searchText') === '')) {
Session.get('searchText',null);
return Questions.find({archived:{$ne:true}});
} else {
var searchText = Session.get('searchText');
Session.get('searchText',null);
return Questions.find( { $and: [ { archived: { $ne: true } }, {note:{$regex: (".*"+searchText+".*") } } ] } )
}
},
searchText:function(){
return Session.get('searchText');
}
})
Template.questions.events({
"change #nameSearchBar":function(event){;
searchText = event.target.value;
Session.set('searchText', searchText);
}
})
Questions:
why do I need to first "enter" an empty string to get a valid result
is this a good procedure? Doesn't hitting enter works against the reactive
approach? I think after enter the complete page is resent ??
Would it be better to check "keyup" for ASCII 27 and 13?
it seems to me that the regex works, are there any concerns? I like to find any substring of the typed in filter, also when the filter has a whitespace.
this is a full text search do I need to set something up on the mongodb side?
Open Question: are the already prebuild implementiations - I do not need to reinvent the wheel...
Here's my interpretation, or how I would possibly have built this:
Template.questions.helpers({
questions:function(){
var searchText = Session.get('search-text');
if(searchText && searchText != '') {
return Questions.find({$and: [{archived: {$ne: true}}, {note:{$regex: (".*"+searchText+".*")}}]});
} else {
return Questions.find({archived: {$ne: true}});
}
}
});
Template.questions.events({
"keyup #nameSearchBar": _.throttle(function(event){
searchText = event.target.value;
Session.set('searchText', searchText);
}), 500)
});
To me it doesn't seem necessary to set a default, or to call Session.get('search-text', null). Also you'll see how my code is a bit more concise. keyup is probably more effective as an event here too.
N.B. The _.throttle is an underscore.js function which will limit changing the Session variable to only every 500ms rather than constantly. This helps save unnecessary server load.
Two pre-built packages that are popular amongst Meteor developers are worth looking into: Easy Search or Search Source
I copied a generally working example for a search on a single text field.
#Ian: Thanks for the suggestion! I took the toggle part, I found that you can not leave the session variable as is, even it gets over written, it must evaluated before. So it has to be set back with NULL.
Session.setDefault('searchText', null);
Template.questions.helpers({
questions:function(){
if ((Session.get('searchText') === null) || (Session.get('searchText') === '')) {
return Questions.find({archived:{$ne:true}});
} else {
var searchText = Session.get('searchText');
return Questions.find( { $and: [ { archived: { $ne: true } }, {note:{$regex: (".*"+searchText+".*") } } ] } )
}
},
searchText:function(){
return Session.get('searchText');
}
})
Template.questions.events({
'keyup #nameSearchBar': _.throttle(function(event){;
Session.set('searchText',null);
searchText = event.target.value;
Session.set('searchText', searchText);
},500)
})
I have to upgrade my app to display pages based on a users type and role properties. Currently I employ a simple switch statement to do this based on user type, e.g.
switch(type) {
case 'a':
return CONSTANT.ONE;
case 'b':
return CONSTANT.TWO;
default:
return null;
}
The switch just returns a constant string which dictates the view showm, but that isn't scalable as number of types , roles increases. Can anyone suggest a good pattern to use in this case. I thought a state pattern might be good but is that over the top just to return a string ?
Thanks
Very similarly to #MarkusJarderot, but with a few important differences in behavior, I would use:
var mapping = {
'a': CONSTANT.ONE,
'b': CONSTANT.TWO,
'_default': null
};
return mapping.hasOwnProperty(type) ? mapping[type] : mapping["_default"];
When the value of mapping[type] is falsy, this will still return it, rather than going to the null alternative. That will be very helpful when one of your values is 0 or an empty string.
Use an object as a lookup:
var roles = {};
Then you can add roles like this:
roles['a']=CONSTANT.ONE;
and look them up like this:
var xxx = roles['a'];
This way you can add things to the roles in different places in your code
You can use Strategy Pattern:
//Example without strategy pattern
gameDifficulty(difficulty) {
switch(difficulty){
case 'easy':
easyGameMode();
break;
case 'difficult'
difficultMode();
break;
}
}
// Using Strategy
const strategies = {
easy: easyGameMode(),
difficult: difficultGameMode(),
//More strategies
__default__: normalGameMode()
}
const easyGameMode = (game) => {
game.difficulty(1);
//Do easy game mode stuff in here
return game;
}
const normalGameMode= (game) => {
game.difficulty(2);
//Do normal game mode stuff in here
return game;
}
const difficultGameMode = (game) => {
game.difficulty(3);
//Do difficult game mode stuff in here
return game;
}
const startGame = (game, difficulty) => {
const gameModifier = strategies[difficulty] ?? strategies.__default__;
return gameModifier(game, difficulty);
}
More info in this article.
I have an XML document that defines a task, which is a list of actions to be performed on certain data. I need to convert this "task list" to a Javascript method which can be called at some later time, which in turn calls a series of pre-defined methods, with the appropriate data. How would you achieve this?
Important Clarification:
I'm not worried about the XML parsing. I'm more interested in how to actually build the Task Method, including binding the essential data to the pre-defined action methods. That's the part I'm struggling with.
Edit: I've revised my example to make it a bit more interesting, and hopefully a bit clearer.
XML:
<task id="enter-castle">
<if holding="castle-key">
<print message="You unlock the castle door and enter." />
<destroy item="castle-key" />
<goto location="castle" />
<else>
<print message="The castle door is locked." />
</else>
</if>
</task>
Javascript:
Game = {
print: function(message) {
// display message
},
destroy: function(item) {
// destroy the object
},
goto: function(location) {
// change player location
},
ifHolding: function(item) {
// return true if player has item
}
};
parseTask(taskNode) {
var taskId = taskNode.getAttribute('id');
// What goes here??
Game.tasks[taskId] = /* ??? */;
}
When I call parseTask() on the <task id="enter-castle"> node, this should create a function that, in effect, does the following when called:
Game.tasks.enterCastle = function() {
if (Game.ifHolding('castle-key')) {
Game.print("You unlock the castle door and enter.");
Game.destroy('castle-key');
Game.goto('castle');
} else {
Game.print("The castle door is locked.");
}
}
What you want are closures.
function createMethod(arguments) {
var task = doSomethingWithYour(arguments);
return function(xmlData) { // <- this is the fundamental part
// do the task with your data
// the "task" vars are still available
// even if the returned function is executed in a different context
}
}
This allows you to create an own method for each task. Don't use the Function constructor or eval.
This is a situation where JavaScript's eval() function will make your life much easier. You can easily build a JavaScript source string matching your desired one and evaluate it to assign the function to the desired property of your Game object.
Of course, there are drawbacks to using "eval", which I won't explore in this answer since you can find countless justifications for why not to use it on the web. However, building and evaluating a simple JS source string will be much easier in the short term than say, a closure based solution, despite any potential drawbacks of performance and security. Moreover, the "eval" based solution will be easy to test since you can simply inspect the source string before it is evaluated.
So try something like this:
function buildTaskFunction(taskXml) {
var source='', depth=0, node /*a visitor to each DOM node*/;
// foreach (node in traverseInOrder(taskXml)) {
switch (node.nodeName) {
case 'TASK':
source += 'Game.tasks.' + makeFunctionName(node.id) + '= function(){';
depth++;
break;
case 'IF':
source += 'if(' + getConditionalAttribute(node) + '){'
depth++;
break;
case 'ELSE':
source += '}else{';
break;
case 'DESTROY':
source += 'Game.destroy("' + node.getAttribute('item') + '");'
break;
case 'PRINT':
source += 'Game.print("' + node.getAttribute('message') + '");'
break;
// case etc...
default: throw new Error('unhandled node type "' + node.nodeName + '"');
}
// end "foreach node".
while (depth-- > 0) { // You'll need to account for nested "if"s somehow...
source += '}';
}
eval(source);
}
And again, there are many potential problems (not definitive ones) with using "eval", so please do read about and try to understand them in the context of your solution. Use your own judgement when deciding if the drawbacks are worth the benefits in your own program -- just because a tool can be dangerous doesn't mean you should not use it.
Example using dojo:
dojo.require("dojox.xml.parser");
dojo.ready(function(){
// Parse text and generate an XML DOM
var xml = "<tnode><node>Some Text</node><node>Some Other Text</node></tnode>";
var dom = dojox.xml.parser.parse(xml);
var docNode = dom.documentElement();
// ...
}
The remainder of the function is non-trivial, but would largely just consist of attribute lookup using ['<attribute-name>'] and child node iteration using dojo.forEach(<node>.childNodes, function(childNode) { /* do stuff */ });