I'm trying to build a "search in the shown elements" function with jquery and css.
Here's what I got so far:
http://jsfiddle.net/jonigiuro/wTjzc/
Now I need to add a little feature and I don't know where to start. Basically, when you write something in the search field, the corresponding letters should be highlighted in the list (see screenshot, the blue highlighted part)
Here's the script so far:
var FilterParticipants = function(options) {
this.options = options;
this.participantList = [];
this.init = function() {
var self = this;
//GENERATE PARTICIPANTS OPBJECT
for(var i = 0; i < this.options.participantBox.length ; i++) {
this.participantList.push({
element: this.options.participantBox.eq(i),
name: this.options.participantBox.eq(i).find('.name').text().toLowerCase()
})
}
//ADD EVENT LISTENER
this.options.searchField.on('keyup', function() {
self.filter($(this).val());
})
}
this.filter = function( string ) {
var list = this.participantList;
for(var i = 0 ; i < this.participantList.length; i++) {
var currentItem = list[i];
//COMPARE THE INPUT WITH THE PARTICIPANTS OBJECT (NAME)
if( currentItem.name.indexOf(string.toLowerCase()) == -1) {
currentItem.element.addClass('hidden');
} else {
currentItem.element.removeClass('hidden');
}
}
}
this.init();
}
var filterParticipants = new FilterParticipants({
searchField: $('#participants-field'),
participantBox: $('.single_participant'),
nameClass: 'name'
});
I think you're just complicating things too much... You can do this easily in a few lines. Hope this helps:
var $search = $('#participants-field');
var $names = $('.single_participant p');
$search.keyup(function(){
var match = RegExp(this.value, 'gi'); // case-insensitive
$names
.hide()
.filter(function(){ return match.test($(this).text()) })
.show()
.html(function(){
if (!$search.val()) return $(this).text();
return $(this).text().replace(match, '<span class="highlight">$&</span>');
});
});
I used hide and show because it feels snappier but you can use CSS3 animations and classes like you were doing.
Demo: http://jsfiddle.net/elclanrs/wTjzc/8/
Here`s the way to do it with jQuery autocomplete so question
If you want to build it on your own you can do the following:
1. Get the data of every item.
2. Make render function in which you will substitute say "Fir" in Fire word to Fire
3. Every time you change the text in the input you can go through the items and perform substitution.
Related
I'm using Isotope.js with vanilla javascript.
Inside my items, I have put a div with a display:none to hide keywords for each item. For example, the item Orange has the keywords 'color' and 'fruit'. So if someone types in any of those three words into the input form (orange, color, or fruit) that item will be shown via Isotope.
Here is a jsfiddle showing my project.
What I'm wanting to do, is if someone were to type all three words into the input form in any order the item will show. Right now the item will only show if the keywords are typed in order. For example, typing in "fruit color" will show the item Orange, but "color fruit" will not.
Edit: This answer here does exactly what I'm trying to achieve. I applied it to a jQuery version of my project and worked perfectly. However, I'm having troubling rewriting it in vanilla JS. Any help is immensely appreciated.
Can you try changing the following, I have removed the regex to string
filter: function(itemElem) {
return qsRegex ? itemElem.textContent.indexOf(qsRegex) !== -1 : true;
}
var quicksearch = document.querySelector('input[type="text"]');
quicksearch.addEventListener('input', function() {
// match items by first letter only
qsRegex = quicksearch.value; // Changed here
iso.arrange();
});
I ended up getting it working myself. I apologise, I'm still new to Javascript and am learning by trial and error, and I'm not sure how to give a proper explanation on how I got it working. But here is the final result:
var qsRegex;
var quicksearch = document.querySelector('input[type="text"]');
// init Isotope
var iso = new Isotope('#grid', {
itemSelector: '.item',
layoutMode: 'fitRows',
transitionDuration: 1000,
filter: function(itemElem) {
var qsRegex = [];
var resultRegex = [];
var endResult = new Boolean();
var searchID = quicksearch.value;
var searchTable = searchID.split(" ");
for (var i = 0; i < searchTable.length; i++) {
qsRegex[i] = new RegExp("(^|\\s)(" + searchTable[i] + ")", 'gi');
resultRegex[i] = qsRegex[i] ? itemElem.textContent.match(qsRegex[i]) : true;
endResult = endResult && resultRegex[i];
}
return endResult;
}
});
// use value of input to filter
var quicksearch = document.querySelector('input[type="text"]');
quicksearch.addEventListener('input', function() {
iso.arrange();
});
Updated jsfiddle link
Using Tooltipster, I want to populate tooltips with words selected from a English/Thai glossary set up as a js 2D array. The intention is that as an English word is tooltipped it will be used to access and display the paired Thai word(s). All of this is in a modal dialog. Here is the html:
<div id="modal_text">
<p id="modal_text01">The <span class="tooltip">boy</span> is <span class="tooltip">walking</span><span> </span><span class="tooltip" >home</span></p>
here is the js code (the array is set as a global variable)
var eng_thai_glossary=[["the","คำนำหน้านามเจาะจง"], ["and","และ"], ... ["dependent","ซึ่งพึ่งพา ผู้อาศัย"]];
jQuery(document).ready(function () {
"use strict";
var modalIndex = "";
var ws_dlog = jQuery("div#ws_dialog").dialog({
... /* dialog setup */
jQuery("span.ws_dialog_icon").on("click",function(evnt) {
evnt.stopPropagation();
ws_dlog.dialog("open");
jQuery("#ui-dialog-title-dialog").hide();
jQuery(".ui-dialog-titlebar").removeClass('ui-widget-header');
var elementId = evnt.target.id;
modalIndex = elementId.substr(7);
var modalId = "modal_text" + modalIndex,
modalText = document.getElementById(modalId).innerHTML;
var ws_modal_html = '<div class = "ws_dialog_box"><p class = "ws_dialog_text">Here is the word in a sentence</p><p class="ws_dialog_thai">คำในประโยค</p><p class = "ws_dialog_sentence"></p><p><span class="fa fa-volume-up fa_volume_ws"></span></p></div>';
ws_dlog.html(ws_modal_html);
jQuery("div.ws_dialog_box p.ws_dialog_sentence").append(modalText);
jQuery('span.tooltip').tooltipster({
functionAfter: function(evnt) {
var eng_word = jQuery(this).evnt.innerHTML,
thai_word = "";
for( var i=0; i<eng_thai_glossary.length; i++) {
if(eng_thai_glossary[i][0] === eng_word) {
thai_word = eng_thai_glossary[i][1];
return thai_word;
}
}
}
});
});
... /* audio code */
});
Firebug shows the class "tooltipstered" is being added to the html indicating Tooltipster is being initialized. I'm a bit lost beyond this point. I'm not sure whether functionAfter is the right way to go here, or any of the other code for that matter. Any advice would be most welcome
OK, this is the solution I arrived at for the above issue. Pretty standard stuff, I guess. The toLowerCase method covers the English convention of capitalizing the first character of a sentence.
jQuery('span.tooltip').tooltipster({
functionBefore: function(origin, continueTooltip) {
var eng_word = jQuery(origin).text().toLowerCase(),
thai_word = "",
gloss_length = eng_thai_glossary.length;
for(var i=0; i<gloss_length; i++){
if(eng_thai_glossary[i][0] === eng_word) {
thai_word = eng_thai_glossary[i][1];
break;
}
}
origin.tooltipster( "content", thai_word);
continueTooltip();
}
});
In Google docs, this function changes the selected text to black
function selectedFontColorBlack() {
// DocumentApp.getUi().alert('selectedFontColorBlack');
var sel = DocumentApp.getActiveDocument().getSelection();
var elements = sel.getRangeElements();
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
// Only modify elements that can be edited as text; skip images and other non-text elements.
if(element.getElement().editAsText) {
var text = element.getElement().editAsText();
// Bold the selected part of the element, or the full element if it's completely selected.
if (element.isPartial()) {
text.setForegroundColor(element.getStartOffset(), element.getEndOffsetInclusive(), "#000000");
} else {
text.setForegroundColor("#000000");
}
}
}
}
This function changes the entire paragraph in which the cursor (or selection) exists to uppercase:
function uppercaseSelected() {
// DocumentApp.getUi().alert('uppercaseSelected');
var sel = DocumentApp.getActiveDocument().getSelection();
var elements = sel.getRangeElements();
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
// Only modify elements that can be edited as text; skip images and other non-text elements.
if(element.getElement().editAsText) {
var text = element.getElement().editAsText();
text.setText(text.getText().toUpperCase());
}
}
}
I don't see any corresponding setText function that works on the selection's "offset", as does the setForegroundColor(Integer,Integer,String). (Both of these functions are in class Text.)
How can I change the actually selected text to uppercase, and not the entire paragraph in which the selection exists?
Thank you.
Try using the setAttributes(startOffset, endOffsetInclusive, attributes) method. Check out the documentation
[EDIT: my bad, i don't think that'll do it. I'll look a bit longer tho]
The gem hidden in the post that #Mogsdad is referring to is this: var selectedText = elementText.substring(startOffset,endOffset+1);. to be little more verbose on how this is used: you can use the string method substring on objects such as DocumentApp.getActiveDocument().getSelection().getSelectedElements()[i].getElement().editAsText().getText()
so, essentially, grab that substring, convert it to uppercase, delete the text in the range (selectedElement.getstartOffset,selectedElement.endOffsetInclusive) and insert the bolded text at selectedElement.getstartOffset
Tada! check it out:
function uppercaseSelected() {
// Try to get the current selection in the document. If this fails (e.g.,
// because nothing is selected), show an alert and exit the function.
var selection = DocumentApp.getActiveDocument().getSelection();
if (!selection) {
DocumentApp.getUi().alert('Cannot find a selection in the document.');
return;
}
var selectedElements = selection.getSelectedElements();
for (var i = 0; i < selectedElements.length; ++i) {
var selectedElement = selectedElements[i];
// Only modify elements that can be edited as text; skip images and other
// non-text elements.
var text = selectedElement.getElement().editAsText();
// Change the background color of the selected part of the element, or the
// full element if it's completely selected.
if (selectedElement.isPartial()) {
var bitoftext = text.getText().substring(selectedElement.getStartOffset(), selectedElement.getEndOffsetInclusive() + 1);
text.deleteText(selectedElement.getStartOffset(), selectedElement.getEndOffsetInclusive());
text.insertText(selectedElement.getStartOffset(), bitoftext.toUpperCase());
} else {
text.setText(text.getText().toUpperCase());
}
}
}
Started with the code from Google App script Document App get selected lines or words?, and made this almost a year ago. I'm happy if it helps you.
The "trick" is that you need to delete the original text and insert the converted text.
This script produces a menu with options for UPPER, lower and Title Case. Because of the delete / insert, handling more than one paragraph needs special attention. I've left that to you!
function onOpen() {
DocumentApp.getUi().createMenu('Change Case')
.addItem("UPPER CASE", 'toUpperCase' )
.addItem("lower case", 'toLowerCase' )
.addItem("Title Case", 'toTitleCase' )
.addToUi();
}
function toUpperCase() {
_changeCase(_toUpperCase);
}
function toLowerCase() {
_changeCase(_toLowerCase);
}
function toTitleCase() {
_changeCase(_toTitleCase);
}
function _changeCase(newCase) {
var doc = DocumentApp.getActiveDocument();
var selection = doc.getSelection();
var ui = DocumentApp.getUi();
var report = ""; // Assume success
if (!selection) {
report = "Select text to be modified.";
}
else {
var elements = selection.getSelectedElements();
if (elements.length > 1) {
report = "Select text in one paragraph only.";
}
else {
var element = elements[0].getElement();
var startOffset = elements[0].getStartOffset(); // -1 if whole element
var endOffset = elements[0].getEndOffsetInclusive(); // -1 if whole element
var elementText = element.asText().getText(); // All text from element
// Is only part of the element selected?
if (elements[0].isPartial())
var selectedText = elementText.substring(startOffset,endOffset+1);
else
selectedText = elementText;
// Google Doc UI "word selection" (double click)
// selects trailing spaces - trim them
selectedText = selectedText.trim();
endOffset = startOffset + selectedText.length - 1;
// Convert case of selected text.
var convertedText = newCase(selectedText);
element.deleteText(startOffset, endOffset);
element.insertText(startOffset, convertedText);
}
}
if (report !== '') ui.alert( report );
}
function _toUpperCase(str) {
return str.toUpperCase();
}
function _toLowerCase(str) {
return str.toLowerCase();
}
// https://stackoverflow.com/a/196991/1677912
function _toTitleCase(str)
{
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}
Basically I want to make a function that, when the text is clicked, it prints the 'id' on the form. and when it's clicked again, only that 'id' is deleted (prior clicked/printed 'id's remain).
The print script I have so far:
function imprime01(obj) {
document.form2.text.value = document.form2.text.value + obj.title;
}
the div
<div onclick="imprime01(this);" title="240 ">240</div>
<div onclick="imprime01(this);" title="230 ">230</div>
<div onclick="imprime01(this);" title="220 ">220</div>
So what I want is: when I click 240, 230 it prints "240 230" on the form, and when I click "240" again, it deletes only "240" from the form. Is there a way to achieve this?
There are many ways to do this.
I would store your ids in an array. In your click handler, test for the existence of the id in your array and remove it if it exists, otherwise add it. Then write all the ids in the array to your text box:
var idList = [];
function imprime01(obj) {
var id = obj.title;
var idIndex = idList.indexOf(id);
if (idIndex > -1) {
idList.splice(idIndex, 1);
}
else {
idList.push(id);
}
document.form2.text.value = idList.join(" ");
}
This may be a little more involved than a simple string replacement, but it gives you other functionality that could be useful later. For example, if another part of your program needs to know which ids have been selected, they are already available in an array.
Edit: Rather than storing the array in a variable, you could generate it on the fly in your click handler with string.split(" "):
function imprime01(obj) {
var id = obj.title;
var idList = document.form2.text.value.split(" ");
var idIndex = idList.indexOf(id);
if (idIndex > -1) {
idList.splice(idIndex, 1);
}
else {
idList.push(id);
}
document.form2.text.value = idList.join(" ");
}
Working demo: http://jsfiddle.net/gilly3/qWRct/
See http://jsfiddle.net/BdEMx/
function imprime01(obj) {
var arr=document.form2.text.value?document.form2.text.value.split(' '):[];
var i=arr.indexOf(obj.title);
if(i===-1){
arr.push(obj.title);
}else{
arr.splice(i,1);
}
document.form2.text.value = arr.join(' ');
}
You shouldn't add a space at the end of title attributes only because you want to join some of them.
Use replace and indexOf functions:
var str = document.form2.text.value;
if(str.indexOf(obj.title) != -1)
document.form2.text.value = str.replace(obj.title,"");
else
document.form2.text.value = str + obj.title;
I have a <ul> "ul-list-one", which contains a number of checkboxes. If I check the checkbox and click the move button it means that it will move to another <ul> "ul-list-two", and the checked checkbox will be removed from the previous, which here would be "ul-list-one".
In "ul-list-two" I can do the same, and it moves to the next, this time "ul-list-three".
Note: "ul-list-two" and "ul-li-three" will be created dynamically.
Here I have done some work, but how can I be able to create multiple <ul>s dynamically?
$('#mer').click( function() {
var txtBox = "";
var txtstatus = false;
$('input[type="checkbox"]').each (function() {
var t = $(this);
var from = 'checklist';
var val=$("#hidden_id").val();
var to = 'ch';
if (!t.is(':checked')){
var swap = to;
to = from;
from = swap;
} else {
txtstatus = true;
}
$(':checkbox:checked').attr('disabled', true);
$('#'+to).append(t.attr('name', to).parent());
$('#ch').addClass('br');
});
if(txtstatus){
txtBox = "<input type='text' value=''>";
$('#ch').after(txtBox);
}
});
//close buttom code
$('#cls').click( function() {
$('input[type="checkbox"]').each (function() {
var t = $(this);
var from = 'checklist';
var to = 'ch';
if (t.is(':checked')){
var swap = to;
to = from;
from = swap;
}
$(':checkbox:checked').attr('disabled', false);
$(':checkbox:checked').attr('checked', false);
$('#'+from).append(t.attr('name', from).parent());
});
});
Not the prettiest thing I have ever written. If you want to leave the empty ul's, just comment out the removeEmpties call. I didn't worry about checkbox order, but it would be easy to implement in a separate function after the checkbox is moved. I also assumed you wouldn't want them to move backward beyond the initial ul. If you want that functionality, you could just add another else if to the move function.
http://jsfiddle.net/pJgyu/13225/