jquery match() variable interpolation - complex regexes - javascript

I've already looked at this, which was helpful to a point.
Here's the problem. I have a list of users propagated into an element via user click; something like this:
<div id="box">
joe-user
page-joe-user
someone-else
page-someone-else
</div>
On click, I want to make sure that the user has not already been clicked into the div. So, I'm doing something like:
if ( ! $('#box').html().match(rcpt) )
{
update_div();
}
else
{
alert(rcpt+' already exists.');
}
However, with existing lack of interpolation that javascript has for regular expressions, is causing my alert to trigger in the use-case where page-joe-user is selected and then the user selects joe-user, which are clearly not exactly the same.
In Perl I would do something like:
if ( $rcpt =~ /^\Qrcpt\E/ )
{
# code
}
All I want to do is change my match() to be:
if ( ! $('#box').html().match(/^rcpt/) )
{
# code
}
if ( ! $('#box').html().match(rcpt) ) seemed a little promising but it, too, fails. Using new RegExp() also does not work using concatenation of complex RE syntax within the function IE $('#box').html().match(new RegExp('^'+rcpt)). I also tried $('#box').html().match('/^'+rcpt'/'). I can only imagine that I'm missing something. I'm pretty new to javascript.
I don't seem to be able to find anything that really addresses such a use-case, here on this site.
TIA

The match function only works on strings, not jQuery objects.
The best way to do this is to put each username into a separate HTML tag.
For example:
<ul id="users">
<li>joe-user</li>
<li>page-joe-user</li>
<li>someone-else</li>
<li>page-someone-else</li>
</ul>
You can then write the following:
if($('#users li').is(function () { return $(this).text() === rcpt; }))
If you want to do it your way, you should call text() to get the string inside the element. ($('#box').text().match(...))
EDIT: The best way to do this using your HTML would be to split the string.
For example:
var userExists = false;
var users = $('#box').text().split(/\r?\n/);
for(var i = 0; i < users.length; i++) { //IE doesn't have indexOf
if (users[i] == rcpt) {
userExists = true;
break;
}
}
if (userExists) {
//Do something
}
This has the added benefit of not being vulnerable to regex-injection.

Related

Any chance to reduce the size of this snippet of code?

IS there any way I could reduce the size of the snippet of code below? Something like if (!$('body#pagina_blog_1 to body#pagina_blog_10).length) Online javascript minifier tools do not help.
jQuery(function($){
if (!$('body#pagina_blog_1, body#pagina_blog_2, body#pagina_blog_3, body#pagina_blog_4, body#pagina_blog_5, body#pagina_blog_6, body#pagina_blog_7, body#pagina_blog_8, body#pagina_blog_9, body#pagina_blog_10').length)
return;
// do stuff
});
Yes you can: $('*[id^="pagina_blog_"]')
For more details refer jquery selectors: http://api.jquery.com/attribute-starts-with-selector/
If you know it's an id on the body tag, you don't even need to use selectors as you can just get the id string directly and compare it to anything you want using a regex. For example, you could do this:
if (document.body.id.match(/^pagina_blog_\d+$/)) {
// code here
}
Or, for just any one or two digits at the end:
if (document.body.id.match(/^pagina_blog_\d{1,2}$/)) {
// code here
}
Or, if you wanted to actually see if the number after the id is in some specific numeric range such as 1-10, you could do this:
var num, matches = document.body.id.match(/^pagina_blog_(\d+)$/);
if (matches) {
num = +matches[1];
if (num >= 1 && num <= 10) {
// code here
}
}
It's not really minifying, but how about just
if ( $('[id^="pagina_blog_"]').length === 0 ) {
// do stuff
}
Give them a shared class to select on.
If you must use the ids for some reason, I would suggest...
!$('body').is('[id^="pagina_blog_"]')
The reason you do not want to put the id selector as the first selector is this would result in a complete dom scan, which is not desired. However in your logic it looks like your only concerned with the body tag having it.

CodeMirror - Using RegEx with overlay

I can't seem to find an example of anyone using RegEx matches to create an overlay in CodeMirror. The Moustaches example matching one thing at a time seems simple enough, but in the API, it says that the RegEx match returns the array of matches and I can't figure out what to do with it in the context of the structure in the moustaches example.
I have a regular expression which finds all the elements I need to highlight: I've tested it and it works.
Should I be loading up the array outside of the token function and then matching each one? Or is there a way to work with the array?
The other issue is that I want to apply different styling depending on the (biz|cms) option in the regex - one for 'biz' and another for 'cms'. There will be others but I'm trying to keep it simple.
This is as far as I have got. The comments show my confusion.
CodeMirror.defineMode("tbs", function(config, parserConfig) {
var tbsOverlay = {
token: function(stream, state) {
tbsArray = match("^<(biz|cms).([a-zA-Z0-9.]*)(\s)?(\/)?>");
if (tbsArray != null) {
for (i = 0; i < tbsArray.length; i++) {
var result = tbsArray[i];
//Do I need to stream.match each element now to get hold of each bit of text?
//Or is there some way to identify and tag all the matches?
}
}
//Obviously this bit won't work either now - even with regex
while (stream.next() != null && !stream.match("<biz.", false)) {}
return null;
}
};
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), tbsOverlay);
});
It returns the array as produced by RegExp.exec or String.prototype.match (see for example https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/match), so you probably don't want to iterate through it, but rather pick out specific elements the correspond to groups in your regexp (if (result[1] == "biz") ...)
Look at implementation of Code Mirror method match() and you'll see, that it processes method parameter for two types: string and RegExp.
Your constant in
stream.match("<biz.")
is of string type.
Define it in RegExp type:
tbsArray = /<biz./g
Thus, your stream will be matched with RegExp.

Exact string match with javascript regex

I'm struggling with what is probably a very simple regex problem. I'm working on a simple prototype and need to know what page I'm on, so I don't reload it if the user clicks a menu widget to navigate to the same view.
I have two URLs the user can switch between:
http://localhost/TestMVC/Larry/LarryTiles
http://localhost/TestMVC/Larry/LarryTilesList
The URLs can also have some trailing querystring items, like this:
http://localhost/TestMVC/Larry/LarryTilesList?filterValue=servers
LarryTiles is giving me the problem. "/\bLarryTiles\b/" worked on Friday (after answers from other questions here) but this doesn't match now. :)
I need to find exactly the strings "LarryTiles" and "LarryTilesList" in these two URLs but can't quite figure out how to do that. The URL changes between my local machine and the various servers where it's hosted, so I can't rely on position.
EDIT: added the example with a trailing querystring, which I'd forgotten. Sorry :(
You can get the last path segment of an URL like this:
function getLastPathSegment(url) {
var match = url.match(/\/([^\/]+)\/?$/);
if (match) {
return(match[1]);
}
return("");
}
// returns "LarryTiles"
getLastPathSegment("http://localhost/TestMVC/Larry/LarryTiles");
// returns "LarryTilesList"
getLastPathSegment("http://localhost/TestMVC/Larry/LarryTilesList");
So, you could do this:
var endPath = getLastPathSegment(window.location.pathname);
if (endPath == "LarryTiles") {
// some code
} else if (endPath == "LarryTilesList") {
// some code
} else {
// some code
}
You can use this code:
str = 'http://localhost/TestMVC/Larry/LarryTiles?filterValue=servers';
if (str.match(/\/([^\/?]+)(?=\/$|\?|$)/)) {
if (match[1] == 'LarryTiles')
alert('LarryTiles found');
else if (match[1] == 'LarryTilesList')
alert('LarryTilesList found');
}
Seems like what you explained works, otherwise try this: http://jsfiddle.net/Wfz9d/
Do you have a case-sensitivity issue?

JavaScript & string length: why is this simple function slow as hell?

i'm implementing a charcounter in the UI, so a user can see how many characters are left for input.
To count, i use this simple function:
function typerCount(source, layerID)
{
outPanel = GetElementByID(layerID);
outPanel.innerHTML = source.value.length.toString();
}
source contains the field which values we want to meassure
layerID contains the element ID of the object we want to put the result in (a span or div)
outPanel is just a temporary var
If i activate this function, while typing the machine really slows down and i can see that FF is using one core at 100%. you can't write fluently because it hangs after each block of few letters.
The problem, it seems, may be the value.length() function call in the second line?
Regards
I can't tell you why it's that slow, there's just not enough code in your example to determine that. If you want to count characters in a textarea and limit input to n characters, check this jsfiddle. It's fast enough to type without obstruction.
It could be having problems with outPanel. Every time you call that function, it will look up that DOM node. If you are targeting the same DOM node, that's very expensive for the browser if it's doing that every single time you type a character.
Also, this is too verbose:
source.value.length.toString();
This is sufficient:
source.value.length;
JavaScript is dynamic. It doesn't need the conversion to a string.
I doubt your problem is with the use of innerHTML or getElementById().
I would try to isolate the problem by removing parts of the function and seeing how the cpu is used. For instance, try it all these ways:
var len;
function typerCount(source, layerID)
{
len = source.value.length;
}
function typerCount(source, layerID)
{
len = source.value.length.toString();
}
function typerCount(source, layerID)
{
outPanel = GetElementByID(layerID);
outPanel.innerHTML = "test";
}
As artyom.stv mentioned in the comments, cache the result of your GetElementByID call. Also, as a side note, what is GetElementByID doing? Is it doing anything else other than calling document.getElementById?
How would you cache this you say?
var outPanelsById = {};
function getOutPanelById(id) {
var panel = outPanelsById[id];
if (!panel) {
panel = document.getElementById(id);
outPanelsById[id] = panel;
}
return panel;
};
function typerCount(source, layerId) {
var panel = getOutPanelById(layerId);
panel.innerHTML = source.value.length.toString();
};
I'm thinking there has to be something else going on though, as even getElementById calls are extremely fast in FF.
Also, what is "source"? Is it a DOMElement? Or is it something else?

finding and replacing parameters in href with javascript

Here's the issue:
I need to check for a parameter in the query. If it's been set, then I need to change it (harder part). If it hasn't been set, I need to set it (easy part)
I was so sure it would be an easy task, but it somehow ended up being a bit more complicated than I thought. Especially for those cases where there are multiple parameters, and the one I'm looking for is in the middle somewhere.
The parameter is "siteLanguage", and is always followed by =xx where xx represents any two characters, like en or es or whatever. So maybe regex is the answer (boy, do I suck at regex)
No frameworks for this one, guys, just plain ol' javascript.
I guess you've figured out how to find all the links.
The standard format of an URL is service://host/path?query
I suggest to cut away the query (just take everything after the first ?) and then split that at & (because that separates parameters).
You'll be left with an array of the form key=value. Split that into an associative array. Now you can work on that array. After you've made your modifications, you need to join the query again and set the href attribute of the link.
This would check all "a href=" throughout the document appending or adjusting the language.
checkhrefs = function(lang){
var links = document.getElementsByTagName("a");
for (var i=0;i<links.length;i++){
if (links[i].href.indexOf("siteLanguage") == -1){
links[i].href += "&siteLanguage="+lang;
} else {
links[i].href = links[i].href.replace(new RegExp("siteLanguage=[a-z][a-z]"),"siteLanguage="+lang);
}
}
}
Ended up just doing a quick hack like so:
function changeLanguage(lang) {
if (location.search.indexOf("siteLanguage") > -1) { //siteLanguage set
location.href = location.search.replace(/siteLanguage=[a-z][a-z]/, "siteLanguage="+lang);
} else if (location.search == "") {
location.href += "?siteLanguage="+lang;
} else {
location.href += "&siteLanguage="+lang;
}
}
Actually pretty happy with a 9-liner function...

Categories

Resources