Search in page with JavaScript Bootstrap - javascript

i would build a page with Bootstrap and i would use the navbar-search form for find the searched text in the same page.
What JS script i should use for do this?
I would that for every found text in the page the script add class "lead" to the p tag like this
<p class="lead">...</p>
How i can do this?
Thanks.

As Bootstrap requires jQuery for its plugins to work, I'll use it for your solution:
If your navbar-search is a class:
$(".navbar-search").on("keyup", function () {
var v = $(this).val();
$(".lead").removeClass("lead");
$("p").each(function () {
if (v != "" && $(this).text().search(v) != -1) {
$(this).addClass("lead");
}
});
});
Bear in mind that this will not look for words but for characters (so when you start typing say a, it will select both paragraphs straight away since both of them contain 'a'). If you want to search for words, you need to amend your code accordingly.
This solution is case-sensitive.
JSFiddle
So if you want to search for whole words, do this:
$(".navbar-search").on("keyup", function () {
var v = $(this).val();
$(".lead").removeClass("lead");
var re = new RegExp("\\b" + v + "\\b","g")
$("p").each(function () {
if (v != "" && $(this).text().search(re) != -1) {
$(this).addClass("lead");
}
});
});
Just bear in mind that you might want to escape your v before inserting it into the regexp if you expect people to search for something silly.
JSFiddle

Related

JS complex operation of the selected text

Great minds JavaScript, please help.
I need to deal with the complex operation of the selected text.
I have some text with a lot of html tags, and I need to get a function that returns the following result:
The user selects text in a particular tag with the class, for example <div class="text">,
and the function is activated in the event that:
$('.text').mouseup(function (e){...});
returns the beginning of the selection
returns the end of the
selection identifies a particular tag, with his class
Moreover:
the number of characters to be given html tags,
but you can exclude
some tags example ,
Ok, some code, what I have:
$(function () {
$('.text').mouseup(function (e){
$(this).highlight(getSelectionText());
})
})
this demo
Here we highlight the desired part of the text, but did not return the
correct position
In addition, the text is released coincidentally
characters, and I need it for the position
You might want to try this:
$(function () {
$('#detailBoxParagraph').mouseup(function (e){
var selectedText = getSelectionText();
$(this).removeHighlight();
$(this).highlight(selectedText);
var txt = $(this).text();
var pos = [];
var i = txt.indexOf(selectedText);
if(i > -1) {
pos.push({"start": i+1, "end": i + selectedText.length});
}
while (i != -1) {
i = txt.indexOf(selectedText, i + 1);
if(i > -1) {
pos.push({"start": i+1, "end": i + selectedText.length});
}
}
console.log(pos);
})
//alertSelection();
})

Rangy: word under caret (again)

I'm trying to create a typeahead code to add to a wysihtml5 rich text editor.
Basically, I need to be able to insert People/hashtag references like Twitter/Github/Facebook... do.
I found some code of people trying to achieve the same kind of thing.
http://jsfiddle.net/A9z3D/
This works pretty fine except it only do suggestions for the last word and has some bugs. And I want a select box like Twitter, not a simple "selection switching" using the tab key.
For that I tried to detect the currently typed word.
getCurrentlyTypedWord: function(e) {
var iframe = this.$("iframe.wysihtml5-sandbox").get(0);
var sel = rangy.getSelection(iframe);
var word;
if (sel.rangeCount > 0 && sel.isCollapsed) {
console.debug("Rangy: ",sel);
var initialCaretPositionRange = sel.getRangeAt(0);
var rangeToExpand = initialCaretPositionRange.cloneRange();
var newStartOffset = rangeToExpand.startOffset > 0 ? rangeToExpand.startOffset - 1 : 0;
rangeToExpand.setStart(rangeToExpand.startContainer,newStartOffset);
sel.setSingleRange(rangeToExpand);
sel.expand("word", {
trim: true,
wordOptions: {
includeTrailingSpace: true,
//wordRegex: /([a-z0-9]+)*/gi
wordRegex: /[a-z0-9]+('[a-z0-9]+)*/gi
// wordRegex: /([a-z0-9]+)*/gi
}
});
word = sel.text();
sel.removeAllRanges();
sel.setSingleRange(initialCaretPositionRange);
} else {
word = "noRange";
}
console.debug("WORD=",word);
return word;
This is only triggered when the selection is collapsed.
Notice I had to handle a backward move of the start offset because if the caret is at the end of the word (like it is the case most of the time when an user is typing), then the expand function doesn't expand around the currently typed word.
This works pretty nicely until now, the problem is that it uses the alpha release of Rangy 1.3 which has the TextRangeModule. The matter is that I noticed wysihtml5 is also using Rangy in a different and incompatible version (1.2.2) (problem with rangy.dom that probably has been removed).
As Rangy uses a global window.rangy variable, I think I'll have to use version 1.2.2 anyway.
How can I do an equivalent of the expand function, using only rangy 1.2.2?
Edit: by the way, is there any other solution than using the expand function? I think it is a bit strange and hakish to modify the current selection and revert it back just to know which word is currently typed. Isn't there a solution that doesn't involve selecting the currently typed word? I mean just based on ranges once we know the initial caret collapsed range?
As Rangy uses a global window.rangy variable, I think I'll have to use version 1.2.2 anyway.
Having read Rangy's code, I had the intuition that probably it would be feasible to load two versions of Rangy in the same page. I did a google search and found I was right. Tim Down (creator of Rangy) explained it in an issue report. He gave this example:
<script type="text/javascript" src="/rangy-1.0.1/rangy-core.js"></script>
<script type="text/javascript" src="/rangy-1.0.1/rangy-cssclassapplier.js"></script>
<script type="text/javascript">
var rangy1 = rangy;
</script>
<script type="text/javascript" src="/rangy-1.1.2/rangy-core.js"></script>
<script type="text/javascript" src="/rangy-1.1.2/rangy-cssclassapplier.js"></script>
So you could load the version of Rangy that your code wants. Rename it and use this name in your code, and then load what wysihtml5 wants and leave this version as rangy.
Otherwise, having to implement expand yourself in a way that faithfully replicates what Rangy 1.3 does is not a simple matter.
Here's an extremely primitive implementation of code that would expand selections to word boundaries. This code is going to be tripped by elements starting or ending within words.
var word_sep = " ";
function expand() {
var sel = rangy.getSelection();
var range = sel.getRangeAt(0);
var start_node = range.startContainer;
if (start_node.nodeType === Node.TEXT_NODE) {
var sep_at = start_node.nodeValue.lastIndexOf(word_sep, range.startOffset);
range.setStart(start_node, (sep_at !== -1) ? sep_at + 1 : 0);
}
var end_node = range.endContainer;
if (end_node.nodeType === Node.TEXT_NODE) {
var sep_at = end_node.nodeValue.indexOf(word_sep, range.endOffset);
range.setEnd(end_node, (sep_at !== -1) ? sep_at : range.endContainer.nodeValue.length);
}
sel.setSingleRange(range);
}
Here's a fiddle for it. This should work in rangy 1.2.2. (It would even work without rangy.)
For those interested, based in #Louis suggestions, I made this JsFiddle that shows a wysihtml5 integration to know the currently typed word.
It doesn't need the use of the expand function that is in rangy 1.3 which is still an alpha release.
http://jsfiddle.net/zPxSL/2/
$(function () {
$('#txt').wysihtml5();
var editor = $('#txt').data("wysihtml5").editor;
$(".wysihtml5-sandbox").contents().find("body").click(function(e) {
getCurrentlyTypedWord();
});
$(".wysihtml5-sandbox").contents().find("body").keydown(function(e) {
getCurrentlyTypedWord();
});
function getCurrentlyTypedWord() {
var iframe = this.$("iframe.wysihtml5-sandbox").get(0);
var sel = rangy.getIframeSelection(iframe);
var wordSeparator = " ";
if (sel.rangeCount > 0) {
var selectedRange = sel.getRangeAt(0);
var isCollapsed = selectedRange.collapsed;
var isTextNode = (selectedRange.startContainer.nodeType === Node.TEXT_NODE);
var isSimpleCaret = (selectedRange.startOffset === selectedRange.endOffset);
var isSimpleCaretOnTextNode = (isCollapsed && isTextNode && isSimpleCaret);
// only trigger this behavior when the selection is collapsed on a text node container,
// and there is an empty selection (this means just a caret)
// this is definitely the case when an user is typing
if (isSimpleCaretOnTextNode) {
var textNode = selectedRange.startContainer;
var text = textNode.nodeValue;
var caretIndex = selectedRange.startOffset;
// Get word begin boundary
var startSeparatorIndex = text.lastIndexOf(wordSeparator, caretIndex);
var startWordIndex = (startSeparatorIndex !== -1) ? startSeparatorIndex + 1 : 0;
// Get word end boundary
var endSeparatorIndex = text.indexOf(wordSeparator, caretIndex);
var endWordIndex = (endSeparatorIndex !== -1) ? endSeparatorIndex : text.length
// Create word range
var wordRange = selectedRange.cloneRange();
wordRange.setStart(textNode, startWordIndex);
wordRange.setEnd(textNode, endWordIndex);
console.debug("Word range:", wordRange.toString());
return wordRange;
}
}
}
});

Issue with the contains method and highlighting elements

I want to highlight an element that contains a string written in a textbox. This is the part of the code that's supposed to do it:
$("#rightContainer .magnifier").click(function () {
var a = $("#searchBox").val();
if (a != "") {
var foundin = $('div:contains(a)');
foundin.addClass("highlighted");
alert(a);
}
})
The problem is that the whole page gets highlighted. I'm assuming this happens because I have a main container which has its children containers, so the contains method selects the whole main container. Is this the case or is it because of something else, and does anyone have a better way of doing this? Thanks in advance.
The :contains selector will return any element which contains the text you're searching for, in this case "a". This has nothing to do with the variable named a. Perhaps you meant to do something like this:
$("#rightContainer .magnifier").click(function () {
var a = $("#searchBox").val();
if (a != "")
{
var foundin = $("div:contains('" + a + "')");
foundin.addClass("highlighted");
alert(a);
}
})
If I understand correctly, you only want the div highlighted which is wrapping that searchbox and not any other div. Use closest() to find that div.
$("#rightContainer .magnifier").click(function () {
var a = $("#searchBox").val();
if (a != "")
{
$("#searchBox").closest('div').addClass('highlighted');
}
})

How can I make greasemonkey search only within a table

Below is my code and currently it searches the whole webpage. I'm trying to figure out how to make it search only within a table. (There is only one table on the page).
Any help would be appreciated.
var TargetLink = $("a:contains('gg')");
var TargetSink = $("a:contains('u')");
if (TargetLink && TargetLink.length)
{
window.location.href = TargetLink[0].href;
}
else if (TargetSink && TargetSink.length)
{
window.location.href = TargetSink[0].href;
}
var TargetLink = $("table a:contains('gg')");
var TargetSink = $("table a:contains('u')");
EDIT:
You say there is only one table on the page. Do you absolutely know there will only ever be one table? Even if you think the answer is yes, I would try and add an id or class selector so that things won't break in the future.
Also, the following code can be simplified:
if (TargetLink && TargetLink.length)
to:
if (TargetLink.length)
Re: "could I combine those 2 variables into 1":
Use a comma in the selector, like so:
//--- Need more of the HTML structure for a better selector.
var TargetLink = $("table")
.find ("a:contains('gg'), a:contains('u')")
;
if (TargetLink.length) {
window.location.href = TargetLink[0].href;
}
If both kind of links are found, 'gg' will be used (first).

How to find link in a text using jquery?

Lets say I have a text such as this
"This is a long text. It contains 150 characters. You can find more about this text on this link http://www.somewebsite.com/RDFCCSDVDS".
So in above text I want to find that link and convert it into a link so that when user clicks on it, the user will be taken directly to this website.
How can I achieve this goal?
Use regular expressions:
$('p').html(function(i, text) {
return text.replace(
/\bhttp:\/\/([\w\.-]+\.)+[a-z]{2,}\/.+\b/gi,
'$&'
);
});
demo
I suspect that I could much improve upon this, though at the minute this is the best I can offer (albeit I think that some kind of replace might work more efficiently):
var $words = $('p').text().split(' ');
for (i in $words) {
if ($words[i].indexOf('http://') == 0) {
$words[i] = '' + $words[i] + '';
}
}
$('p').html($words.join(' '));
JS Fiddle demo.
A slightly improved version of the above (but good lord, it's ugly...):
var punctuation = ['!',"'",'"',',','.'];
$('p').each(
function(){
$words = $(this).text().split(' ');
for (i in $words){
if ($.inArray($words[i].charAt(0),punctuation) > -1 && $words[i].indexOf('http://') == 1){
alert($words[i]);
}
else if ($.inArray($words[i].charAt($words[i].length - 1),punctuation) > -1 && ($words[i].indexOf('http://') == 1 || $words[i].indexOf('http://') == 0)){
$words[i] = '' + $words[i].substring(0,$words[i].length-1) + '' + $words[i].charAt($words[i].length-1);
}
else if ($words[i].indexOf('http://') == 0){
$words[i] = '' + $words[i] + '';
}
}
$(this).html($words.join(' '));
});
JS Fiddle demo.
I'm not quite sure what to do about quoted links, though (text such as "http://google.com", for example); and, honestly, I think that regex is probably the far, far better approach to this problem.
#Eric solution is brilliant, but I discovered that could be wrong if the url has spaces after it. Try his jsfiddle example with a text like this:
<p>This is a long text. It contains 150 characters. You can find more about this text on this link http://api.som-ewebsite.com/RDFCCS-VDS/#!/?p1=foo&p2=bar right here</p>​​​​​​​​​​​​​​​​​​​​​​​
So I changed the latest part of the regex to intercept pretty much every URL-friendly character excluding the space, which is a url "terminator" to me (in the real world it's not, of course, but I couldn't find a way to separate normal spaces and spaces belonging to a URL in a plain text).
$('p').html(function(i, text) {
return text.replace(
/\bhttp:\/\/([\w\.-]+\.)+[a-z]{2,}([\/\w\.\-\_\?\=\!\#,\&]+)/gi,
'$&'
);
});​​
I think it can be improved, suggestions are welcome as always :)
EDITED:
Anyway, I think this is the best solution around: How to replace plain URLs with links?
using regular expression
var e = /http:\/\/([A-Za-z0-9\.-_]{2,}\.)+[A-Za-z]{2,}(\/.+)/,
s = "This is a long text. It contains 150 characters. You can find more about this text on this link http://www.somewebsite.com/RDFCCSDVDS";
if (s.match(e)) {
var url = RegExp['$&'];
s = s.replace(url, '' + url + '');
}
in jquery, you can use the tag in your selector to get all the links of the page ie.. $("a")
So if you want to do something to every link on the page, you could use
$("a").each(function() {
//your code here. you can access the link by using $(this)
});

Categories