Regex, doesnt stop matching - javascript

I'm working on a bbcode example, but i cannot seem to get it to work.
the regex matches all the [img] tags and make it all look wierd. I'm trying to have the option to click on the image and get it full size and when I do, everything becomes a link (when i have more than once img-tag).
Here's my text:
[img size="small" clickable="no"]img1.jpg[/img]
[img size="large" clickable="yes"]img2.jpg[/img]
Here's my source code:
var bbArray = [/\n/g,
/\[img size="(.*?)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="(.*?)" clickable="no"\](.*?)\[\/img\]/g];
var bbReplace = ['<br>',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">'];
The operation:
for (var i = 0; i < content_text_bb.length; i++) {
content_text_bb = content_text_bb.replace(bbArray[i], bbReplace[i]);
}
the result:
<img src="localhost/img/small" clickable="no" ]img1.jpg[="" img]
[img size="large_img2.jpg?1423317485160" alt="img2.jpg">;
I'm not that familiar with regex and I really need someone to look at it, I'm lost.

Something that may be of interest to you, Extendible BBCode Parser. An example of use.
var bbcArr = [
'[img size="small" clickable="no"]img1.jpg[/img]',
'[img size="large" clickable="yes"]img2.jpg[/img]'
];
XBBCODE.addTags({
"img": {
openTag: function(params, content) {
params = (params.match(/(\S+?=".*?")/g) || [])
.reduce(function(opts, item) {
var pair = item.match(/(\S+?)="(.*?)"/);
opts[pair[1]] = pair[2];
return opts;
}, {});
var html = '<img src="http://localhost/img/';
if (params.clickable === 'yes') {
html = '<a href="http://localhost/img/' + content +
'" alt="' + content + '">' + html;
}
if (params.size === 'small' || params.size === 'large') {
html += params.size + '/';
}
html += content + '" />';
if (params.clickable === 'yes') {
html += '</a>';
}
return html;
},
closeTag: function(params, content) {
return '';
},
displayContent: false
}
});
bbcArr.forEach(function(item) {
var result = XBBCODE.process({
text: item,
removeMisalignedTags: false,
addInLineBreaks: false
});
this.appendChild(document.createTextNode(result.html + '\n'));
}, document.getElementById('out'));
<script src="https://rawgithub.com/patorjk/Extendible-BBCode-Parser/master/xbbcode.js"></script>
<pre id="out"></pre>

First thing first, your loop should be:
for (var i = 0; i < bbArray.length; i++) {
(not content_text_bb.length)
Secondly, the issue you have is with this size="(.*?). This says: match any content non-greedily till I find the first "thing-that-follow" (in this case the thing-that-follows is the first occurrence of " clickable="yes"
If you look at your input text, the search for [img size="{ANYTHING}" clickable="yes"] means that {ANYTHING} is: small" clickable="no"]img1.jpg[/img][img size="large and you can see how that returns your results, and breaks everything.
So, it should firstly be noted that regexps are not the best tool for language processing (plenty of posts on SO and the internet at large on the topic). In this particular case, you can fix your problem by being very specific about what you want matched.
Do NOT match "anything". If you want to match a size attribute, look for digits only. If you want to match any property value, look for "{ANYTHING_NOT_DOUBLE_QUOTES}". So, with that said, if you change bbArray to the code below, it should work in the particular example you have given us:
var bbArray = [/\n/g,
/\[img size="([^"]*)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="([^"]*)" clickable="no"\](.*?)\[\/img\]/g];
Just to be clear: while this should work on your current input, it is by no mean robust bbcode processing. It will only match [img] bbcode tags that have exactly one size attribute and one clickable attribute, in that order!! Most free-to-type bbcode out-there will have much broader variations, and this code obviously won't work on them.

Related

Dynamic Filter of Iframe with Two Input Fields

I'm attempting to make a dynamic filter on one iframe with two input boxes. Let's call the input boxes "Box 1" and "Box 2". When both boxes are not populated, I would like the iframe to display all of the information. When Box A is populated, I want it to display information on Box A. When Box B is populated as well, I would like both the filters to apply. When only Box B is populated, I would like the iframe to only display Box B's input.
One limitation I have is the changing nature of having one of the input boxes blank. I am limited to assigning a number to the input on the URL (e.g. - col1, op1, val1). If the "salModBox" is blank for instance, it needs to be dynamic enough to assign "serNumPrefBox" with col1, op1, val1). If both are populated, it would need to be col1, op1, val1 for "salModBox" and col2, op2, val2 for "serNumPrefBox". If neither are populated, well, it doesn't need to have col1 or 2 for that matter.
Expected output of the URL would ultimately look like this if both are populated:
https://example.com/#/embed/viz/longID/?col1=Variable%20Number%20One&op1=EQ&val1="+salesMod+"&col2=Variable%20Number%20Two&op2=EQ&val2="+serNoPre+"#/moreinfo/anotherID
Expected output of the URL with one variable populated:
https://example.com/#/embed/viz/longID/?col1=Variable%20Number%20One&op1=EQ&val1="+salesMod (or serNoPre) +"#/moreinfo/anotherID
With both of them blank, it would simply be the original URL source link. This would be a wide open search. A user isn't technically limited to values they can put in either input box.
function salModSnpFilter() {
var salModInput = document.getElementById('salModBox').value;
var serNumPrefInput = document.getElementById('serNumPrefBox').value;
var smSnp = '';
if (salModInput = ' ' and serNumPrefInput = ' ') {"https://en.wikipedia.org/wiki/IFrame"
} else if (salModInput = ' ' and serNumPrefInput != ' ') {"https://en.wikipedia.org/wiki/IFrame" + serNumPrefInput
} else if (serNumPrefInput = ' ' and salModInput != ' ') {"https://en.wikipedia.org/wiki/IFrame" + salModInput
} else if (salModInput != ' ' and serNumPrefInput != ' ' {"chttps://en.wikipedia.org/wiki/IFrame"+salModInput+serNumPrefInput
} else {"https://en.wikipedia.org/wiki/IFrame"
}
var salModString = "https://en.wikipedia.org/wiki/IFrame" + salModInput";
var serNumPrefString = "https://en.wikipedia.org/wiki/IFrame" + serNumPrefInput";
var bothString = "https://en.wikipedia.org/wiki/IFrame" + serNumPrefInput + salModInput";
document.getElementById('SM_SNPiFrame').src = salModString;
document.getElementById('SM_SNPiFrame').src = serNumPrefString;
document.getElementById('SM_SNPiFrame').src = bothString;
}
<div>
<input name="textfield" type="text" class="guidedQueryEntry" placeholder="Box A" name="Box A" id="salModBox">
</div>
<div>
<input name="textfield" type="text" class="guidedQueryEntry" placeholder="Box B" name = "Box B" id="serNumPrefBox">
</div>
<div>
<iframe src="https://en.wikipedia.org/wiki/IFrame"
width="100%" height="600" style="border-color:#FFCD11" id="SM_SNPiFrame" allowfullscreen></iframe>
</div>
I ultimately used this code and it worked:
function filterSelection() {
var smBoxValue = document.getElementById("salModBox").value;
var snpBoxValue = document.getElementById("serNumPrefBox").value;
if (smBoxValue != "" && snpBoxValue != "") {var combinedModString =
"https://example.com/col1=Serial%20Number%20Prefix&op1=EQ&val1=" +
snpBoxValue +"&col2=Sales%20Model%20BOM%20EDS&op2=EQ&val2=" +
smBoxValue";
document.getElementById('SM_SNPiFrame').src = combinedModString;
}
else if (smBoxValue == "" && snpBoxValue != "") {var snpModString =
"https://example.com/#/col1=Serial%20Number%20Prefix&op1=EQ&val1="
+ snpBoxValue;
document.getElementById('SM_SNPiFrame').src = snpModString;
}
else if (smBoxValue != "" && snpBoxValue == "") {var salModString =
"https://example/col1=Sales%20Model%20BOM%20EDS&op1=EQ&val1=" +
smBoxValue;
document.getElementById('SM_SNPiFrame').src = salModString;
}
else {document.getElementById('SM_SNPiFrame').src =
"https://example.com/";
}
}
Your code seems a bit complex than what your issue is, I'll explain to you how to correct this and use some good practices in JavaScript.
Since you need to handle the values inside the input tags and use them into the iFrame tag, we will do the following:
Global elements first.
Since we will probably need to define only once which DOM element is the iFrame tag and which ones are the input tags, lets have them at the very beginning:
var iframe = document.getElementById('SM_SNPiFrame'),
elements = [
document.getElementById('salModBox'),
document.getElementById('serNumPrefBox')
],
strings = [];
Also, we define a strings variable that will help us store the input values in the same index as elements array.
Set event listeners for every element.
After defining which elements we want to use, now we should handle the change of its value. The most fast-looking effect is to use keyup event, this will pass the value everytime that the user types:
elements.forEach((e,index)=>{
e.addEventListener("keyup",event=>{
strings[index] = event.target.value;
salModSnpFilter();
});
});
In this event listener, you need to setup what will happen every time this event is fired. I just did a simple function to store the new value into the same index but in different array (strings array).
And after that done, call the function that will update the iFrame tag.
Keep your code simple and functional.
The function salModSnpFilter() doesn't need a lot of if statements and the same string appearing multiple times to handle the new source of the iFrame. Lets keep code simple:
const salModSnpFilter = () => {
let source = "https://en.wikipedia.org/wiki/IFrame",
finalString = "/"; //You can set it to empty: "" if you dont want slashes.
strings.forEach(string => {
if (string !== "") {
finalString += string; //You can add a slash with by adding: + "/" between the s and the semicolon.
}
});
iframe.src = source + finalString;
};
We define the base URL in a variable at the top and a variable that will hold the string that we will append to the base source.
We iterate over the strings array and add this string to finalString array in the same order of the inputs.
After this, the only thing left to do is to set the source of the iFrame tag.
Final code:
var iframe = document.getElementById('SM_SNPiFrame'),
elements = [
document.getElementById('salModBox'),
document.getElementById('serNumPrefBox')
],
strings = [];
elements.forEach((e,index)=>{
e.addEventListener("keyup",event=>{
strings[index] = event.target.value;
salModSnpFilter();
});
});
const salModSnpFilter = () =>{
let source = "https://en.wikipedia.org/wiki/IFrame",
finalString = "/";//You can set it to empty: "" if you dont want slashes.
strings.forEach(string=>{
if(string !== ""){
finalString += string; //You can add a slash with by adding: + "/" between the s and the semicolon.
}
});
iframe.src = source + finalString;
};
<div>
<input name="textfield" type="text" class="guidedQueryEntry" placeholder="Box A" name="Box A" id="salModBox">
</div>
<div>
<input name="textfield" type="text" class="guidedQueryEntry" placeholder="Box B" name="Box B" id="serNumPrefBox">
</div>
<div>
<iframe src="https://en.wikipedia.org/wiki/IFrame" width="100%" height="600" style="border-color:#FFCD11" id="SM_SNPiFrame" allowfullscreen></iframe>
</div>
Note: The order of the strings and how they are used on the iFrame are the same as the order you added the inputs to the elements array. This means, inputA value will always go before inputB value. Unless you change the order in the elements array.

Get Elements By Partial Attribute Value

I've been fiddling with this for several hours and I'm utterly stumped by its behavior. On JSFiddle, it seems to only be returning the values of the href attribute when I want the entire elements, but I can still use getAttribute(attribute) as if it's an element. In the userscript that this is for, it seems to completely break everything after calling the function(hence turning to JSFiddle and having no result to show here).
Why is this happening? How can I accomplish the stated goal?
HTML:
<a name="edit-a" href="http://example.com/edit1">foo</a>
<a name="moo" href="http://example.com/edit2">roo</a>
<a name="edit-b" href="http://example.com/boo">bar</a>
JavaScript function:
function getElementsByPartialValue(searchtext, searchattr, searchtag)
{
var searchreturn = [];
var searchreturni = 0;
var tagmatches = document.getElementsByTagName(searchtag);
for (var tagmatchesi = 0; tagmatchesi < document.getElementsByTagName(searchtag).length; tagmatchesi++)
{
if (tagmatches[tagmatchesi].getAttribute(searchattr).indexOf(searchtext) > -1)
{
searchreturn[searchreturni] = tagmatches[tagmatchesi];
searchreturni++;
}
}
return searchreturn;
}
Checking the result:
alert(getElementsByPartialValue('edit', 'name', 'a')[0]);
Result(https://jsfiddle.net/81s4g42a/3/):
http://example.com/edit1
Accessing other attributes(https://jsfiddle.net/81s4g42a/4/):
alert(getElementsByPartialValue('edit', 'name', 'a')[0].getAttribute('name'));
Result:
edit-a
Use Attribute-Contains Selector like this:
var tagmatches = document.querySelectorAll(searchtag + "[" + searchattr + " *= '" + searchtext + "']");
function getElementsByPartialValue(searchtext, searchattr, searchtag)
{
return document.querySelectorAll(searchtag + "[" + searchattr + " *= '" + searchtext + "']");
}
var elems = getElementsByPartialValue("edit", "name", "a");
for(var i = 0; i < elems.length; i++) {
elems[i].style.background = "red";
}
<a name="edit-a" href="http://example.com/edit1">foo</a>
<a name="moo" href="http://example.com/edit2">roo</a>
<a name="edit-b" href="http://example.com/boo">bar</a>
Use .querySelectorAll(), attribute is equal to or begins with followed by "-" selector
var tagMatches = document.querySelectorAll("a[name|='edit']");
console.log(tagMatches);
<a name="edit-a" href="http://example.com/edit1">foo</a>
<a name="moo" href="http://example.com/edit2">roo</a>
<a name="edit-b" href="http://example.com/boo">bar</a>
I hate to say this, but it's returning "name", not "href", if you want the url you should return the "href", not the "name"... Check your script and you'll find that you've set the name of the first tag to "edit-a", so when alerting the name of [0] you get "edit-a". If you access [1] you get "edit-b", and if you use 1 instead of 'name' you get "http://example.com/boo", and it's skipping the second one with "moo" as a name because you're only searching for ones with "edit" in its name, not its href/url.
alert(getElementsByPartialValue('edit', 'name', 'a')[0].getAttribute('href'));
I tested your code sample and find out, your code execute perfectly well. The problem is from the "alert()" function, try using console log, you will see that your code actually works.

Is there a better way to bind data to the divs?

I'm getting JSON data from the API, like this
data = {
q: 'sugar',
from: 0,
to: 10,
params: {
sane: [],
q: [ 'sugar' ]
},
more: true,
count: 1000,
hits: [{
recipe: {
uri: 'http://www.edamam.com/ontologies/edamam.owl#recipe_a46ae0ad4f8320fa6285b25fc7b36432',
label: 'Bread Pudding with Apple and Brown Sugared Bacon',
image: 'https://www.edamam.com/web-img/1ae/1ae111af3737d42e9d743445f5605373.JPG '
},
recipe: {
uri: 'http://www.edamam.com/ontologies/edamam.owl#recipe_a36b51f50f102bf5da228af55d2ce040',
label: 'Vanilla sugar',
image: 'https://www.edamam.com/web-img/4fd/4fdd2336043aa81dd05a4b6a08934402.jpg',
}
}]
}
And I try to bind the recipe to divs. For example, there is a div with the id columns,
Here is that piece of codes.
var list = data.hits;
function Builddivs(list) {
var array = new Array(0);
var count = list.length;
for (var i = 0; i < 10; i++) {
var p = list[i];
title = p.recipe.label;
imgurl = p.recipe.image;
href = p.recipe.url;
array.push("<div class='pin'><a href='" + href + "'><img src='" + imgurl + "'/></a><p>" + title + "</p> </div>");
}
var html = array.join("");
$("#columns").html(html);
}
The problem is to generate that html takes like several seconds, so is there a better way to do that? like bind the data directly to existing dynamic number of divs? Thanks!
Instead of generating a lot of HTML at once, it would be more efficient to edit existing HTML.
Example jsfiddle solution to this question
Editing HTML with jQuery
You can replace or add text or HTML to a div:
$(selector).html('Try <span class="red">this!</span>');
$(selector).text('Just add some text');
$(selector).append('Some HTML');
Adding src to an image or adding href to a link:
$(selector).attr('src','http://example.com/someimage.jpg');
$(selector).attr('href','http://example.com');
Instead of using a for loop, you could use javascript Array.forEach or jquery $.each
Generating HTML for the first time
On every run (every time the list changes) you can check if the HTML element to be edited exists. If not, then you can generate the appropriate HTML. On the first run of the code, the HTML would then be generated for every element from the list.
See this question to see how to check if elements exist:
How do you check if a selector matches something in jQuery?
Example
Here is a working jsfiddle with an example of how HTML can be edited using $().attr and $().html: https://jsfiddle.net/fyux250p/1/
var hitsContent =""
(list || []).forEach(function(data,index){
hitsContent += "<div class='pin'><a href='" + data.url + "'><img src='" + data.url + "'/></a><p>" + data.label + "</p> </div>";
})
$("#columns").html(hitsContent);

Most efficient way of converting plain text to HTML, Match or Regexp

I have a large text document filled with random words, urls, email-addresses etc. An example: "word 2014 john#doe.com http://www.example.com/ http://example.com/image.gif", but it could look differently, there could be linebreaks, multiple spaces, tabs etc. And the data could very fast become huge (it is a type of bookmarking service so data is arriving all the time in the form of images, text and hyperlinks).
Another example of content in the text document (the one I use for testing):
http://movpod.in/images3/MovPod-logo.png
https://dt8kf6553cww8.cloudfront.net/static/images/developers/chooser-drawing-vfln1ftk6.png
http://xregexp.com/assets/regex_cookbook.gif
asd asd ad feaf
apa
http
I want to wrap all these strings in tags, and be able to target out images, hyperlinks, emails and strings. I have tried different ways but unsure which is the best, and also, there is a RegExp I do not fully understand.
The end result should be:
<span>word</span>
<span>2014</span>
<a class="mail" href="mailto:john#doe">john#doe.com</a>
<a class="url" href="http://www.example.com/">http://www.google.com/</a>
<a class="img" href="http://example.com/image.gif">http://example.com/image.gif</a>"
Match. This approach is however not keeping the text order intact, but it works.
arr = data.split("\n");
for (i = 0; i < arr.length; i++)
{
arr2 = arr[i].split(' ');
for (j = 0; j < arr2.length; j++)
{
if (arr2[j].match(/(.gif|.png|.jpg|.jpeg)/))
{
ext = arr2[j].substr(-4);
ext = ext.replace(".","");
imgs += '<a class="img '+ext+'" href="'+arr2[j]+'">'+arr2[j]+'</a>';
}
else if (arr2[j].match(/(http:)/))
{
urls += '<a class="url" href="'+arr2[j]+'">'+arr2[j]+'</a>';
}
else
{
spans += '<span>'+arr2[j]+'</span>';
}
}
}
Regexp. I thought it would be possible to look for the inverse at exp_all, as in anything else but containing http. It does not however.
var exp_img = /(https?:\/\/([\S]+?)\.(jpg|jpeg|png|gif))/g,
exp_link = /([^"])(https?:\/\/([a-z-\.]+)+([a-z]{2,4})([\/\w-_]+)\/?)/g,
exp_all = /^((?!http).)*$/g;
text = data.replace(exp_all, '<span>$3</span>');
text = text.replace(exp_img, '<a class="img" href="$1">$1</a>');
text = text.replace(exp_link, '<a class="url" href="$2">$2</a>');
So, the best way of accomplishing this plain-text to HTML conversion would be appreciated. I would love if there was already some type of library for this. I was looking at Markdown but then I would still have to update the plain-text for the Markdown, so I guess not an option.
And if possible I would like to strip out "http://" and have it as clean and neat as possible.
Im making a few assumptions about your data (for example, that every entry is always there.) If that's true, then something like this should work fine:
<script>
var data = ['word\n 2014\t\t john#doe.com\n\n\n\n\n http://www.example.com/ http://example.com/image.gif apa http',
'fooo 2013 foo#bar.com http://www.blah.com/ http://blah.com/gif.gif asd asd ad feaf'];
function htmlify(string){
var elem = string.replace(/[^\w\s\/#:\.]/g,'').replace(/\s+/g, ' ').split(' ');
var result = [];
for (var i = 0; i < elem.length; i++){
if (elem[i].match(/http:/)) {
if (elem[i].substr(-4).match(/.gif|.png|.jpg|.jpeg/)){
result.push("<a class='img' href='" + elem[i] + "'>" + elem[i] + "</a>");
} else {
result.push( "<a class='url' href='" + elem[i] + "'>" + elem[i] + "</a>");
}
} else if (elem[i].match(/\w+#\w+\.\w+/)){
result.push("<a class='mail' href='mailto:" + elem[i] + "'>" + elem[i] + "</a>");
} else {
result.push("<span>" + elem[i] + "</span>");
}
}
return result;
}
var result = data.map(htmlify);
console.log(result);
</script>

How do I display Javascript code as page content?

I made a webpage that needs javascript. More specifically if anyone has heard of it, I am using an Ajax-Solr API to make a good user interface for an Apache Solr/Lucene Search Engine. For some of the results that come up (which are webpages that have been crawled), javascript is embedded on some of the webpages, and that is messing up part of my subsequent html/javascript. Help me out. Here is some of my code:
AjaxSolr.theme.prototype.snippet = function(doc) {
var output = '' + doc.id;
if (doc.text.length > 300) {
output += doc.text.substring(0, 300);
output += '<span style="display:none;">' + doc.text.substring(300);
output += '</span> <br id="aftsnippet"/><button id = "expand' + doc.id + '">Expand/Contract</button>';
} else {
output += doc.text + '<br/>';
}
output+='<a id="goToSite"><button>Go to Site</button></a><button id = "sitedetailsbutton' + doc.id + '">Site Details</button>';
return output;
};
I don't know if that helps, but pretty much what happens is that doc.text might contain some random javascript from a javascript file online, and then that causes the buttons from
<button>Go to Site</button></a><button id = "sitedetailsbutton' + doc.id + '">Site Details</button>';
to not show up. What could I do to fix this?
You need to HTML-encode the JavaScript. You can do that with the following.
function htmlEncode(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
Also, you can replace newline characters with <br />, as appropriate:
function htmlEncode(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br />');
}

Categories

Resources