I'm creating a <select> replacement using jQuery to replace it with divs and links.
Now I want to filter it when I start to type something with the new select open.
Like Google Translate does on the language selector.
Do you have any advice how do i proceed?
I started something with:
$(document).bind('keypress', function(event) {
//...
});
But I capture only single keys, not the whole typed string.
Important:
I don't have an <input /> to detect the keypress or keyup events on it
I prefer not to create this <input /> since I want to use only <div>'s and <a>'s on the "new select"
Lately I'll need to navigate on the open select with arrow keys + enter to select the option with my keyboard
You could achieve this by 'listening' about what is pressed on the window, and then detecting the particular letter/string pressed, search through items list and if you find it change its css properties or add a new 'selected' class i.e. (demo => http://jsfiddle.net/steweb/mC6tn/ ..try pressing whatever :) and added after something found press left or right btns, or enter) :
JS: (supposing that each element you want to find something into and select it has class 'elem')
var whatYouAreSearching = $('<div class="searching-string"></div>'); //just to see what string you're typing
$(document.body).append(whatYouAreSearching);
function search(what){
what = what.toLowerCase();
$('.elem').removeClass('selected'); //reset everything
$.each($('.elem'),function(index,el){
if($(el).html().toLowerCase().indexOf(what) > -1){
$(el).addClass('selected');
return false; //found, 'break' the each loop
}
});
}
var letterPressed = [];
var timeOutResetLetters = null;
$(window).keypress(function(e) {
clearTimeout(timeOutResetLetters); //clear timeout, important!
timeOutResetLetters = setTimeout(function(){ //if 500 ms of inactivity, reset array of letters pressed and searching string
letterPressed = [];
whatYouAreSearching.html('');
},500);
letterPressed.push(String.fromCharCode(e.keyCode)); //look at the comment, thanks Niclas Sahlin
whatYouAreSearching.html(letterPressed.join('')); //show string
search(letterPressed.join('')); //and search string by 'joining' characters array
});
EDIT added left/right/enter keys handling
$(window).keydown(function(e){ //left right handling
var currSelected = $('.elem.selected');
if(e.keyCode == "37"){ //left, select prev
if(currSelected.prev() && currSelected.prev().hasClass('elem')){
currSelected.prev().addClass('selected');
currSelected.removeClass('selected');
}
}else if(e.keyCode == "39"){ //right, select next
if(currSelected.next() && currSelected.next().hasClass('elem')){
currSelected.next().addClass('selected');
currSelected.removeClass('selected');
}
}else if(e.keyCode == "13"){ //enter
$('.entered').remove();
$(document.body).append(currSelected.clone().addClass('entered'));
}
});
You can try using jQuery UI's autocomplete
How to do what you asked
Each time the keypress event is triggered on the document, keep a record of the character that was typed, either in a variable (accessible from the global scope or in a closure) or in an element on the page (you may choose to use display: hidden; if you don't want this to be visible to the user).
Then, do a pass over the elements in your dropdown and hide those that don't contain/start with the string you've built from individual keystrokes.
What's actually recommended
Use an input element to contain the user's typed keystrokes, and let the user see the element.
Why?
Because it's an interaction behavior users are already familiar with. If you don't use an input element, you open several new questions that are already solved with an input element:
How does the user know that they can type to filter the list? Input elements are a clear declaration to the user: "You should type here!"
How does the user know what string is going to be filtered on when they press more than one key? When I quickly type 'hu' in that Google Translate interface, 'Hungarian' is selected, as I would expect. However, what happens when I type it slowly? If it's slow enough, 'Hatian Creole' is selected, and then 'Ukranian'.
What if I mistype something and want to start over? Is there a button to press to clear it out? How long do I need to wait for the filter to clear on its own?
You could certainly create a new interface element that solves all of these problems, and if that's your goal, go for it, but there are preexisting standards for these sorts of things.
For one, that previously-mentioned autocomplete widget is really handy, and really flexible.
you can try something like this:
var _interval;
$("#textarea/field_id").bind('keypress', function(event) {
clearTimeout(_interval);
_interval = setTimeout(onTimeout, 1000);
});
function onTimeout(){
var words = $("#textarea/field_id").val().split(' ');//do what you want with the string in the field
}
This will capture the entire string onTimeout. Play with the timeout a little bit to get it nice and clean!
What about this:
var word='';
$(document).bind('keypress', function(event) {
//UPDATE word ACCORDING TO THE CHAR, LIKE:
if (event.charCode >=48 && event.charCode <=57) {
.... ....
.... ....
}
//OR
switch(event.charCode) {
.... ....
.... ....
}
});
I created my own version of a <select> with <div> tags, check it out here.. If i understand you correctly, this is what you want..
http://jsfiddle.net/myTPC/
It also supports backspace (atleast in firefox).
What I've tried to do is:
1) get the keypressed (only 0-9, a-z and space) and save this inside a div
2) created a LI list (you can use a div with a-elements, that's fine aswell)
3) find LI-items with the text that's being saved
4) add up/right down/left arrows to get next/previous item in the list
For now it keeps all items in the list, you can hide them aswell if you want. It's just an illustration.
// EDIT:
Here's a starters setup: http://www.pendemo.nl/keyinputtest.html
In firefox the body doesn't get automatically selected which causes that you need to click the body/webpage again before a second input is being detected. In Chrome it detects keys pressed after eachother.
// EDIT2:
Working in firefox. Text is now saved inside a div (you can type a string you want and see it being placed in the body).
// EDIT3:
Added an UL list with some items. typing some text will filter this list with items matching the typed string.
// EDIT4:
Only a-z and space are being used to search. Still looking for a way on how to find the backspace key. Since Chrome is adding 'history.go-1' by default. Firefox however does notice the backspace key. event.preventDefault() is not changing anything in Chrome.
// EDIT5:
Added up+right arrow to select next and left+down array to select previous item.
// EDIT6:
Upon using the enter key, the current value is alert. Ofcourse the scripts stops after the alert. But as you can see the value is available for you.
Here's the code I came up with so far:
var typed_string = '';
$(document).ready(function() { $('#typedtext').select(); });
$(document).bind('keypress', function(event) {
event.preventDefault();
if((event.which > 47 && event.which < 58) || (event.which > 96 && event.which < 123) || event.which == 32) {
typed_string = typed_string + String.fromCharCode(event.which);
$('#typedtext').html(typed_string);
$('#testlist li').css('background-color', '#ffffff');
$('#testlist li:contains('+typed_string+')').css('background-color', 'green').first().addClass('selected').css('background-color', 'red');
$('#typedtext').select();
}
if(event.which == 13) {
alert('Selected item: ' + $('.selected').html());
$('#typedtext').select();
}
});
$(document).keyup(function(event) {
event.preventDefault();
if(event.which == 38 || event.which == 37) {
$('#testlist li').css('background-color', '#ffffff');
$('#testlist li:contains('+typed_string+')').css('background-color', 'green');
$('.selected').removeClass('selected').prev().css('background-color', 'red').addClass('selected');
}
if(event.which == 39 || event.which == 40) {
$('#testlist li').css('background-color', '#ffffff');
$('#testlist li:contains('+typed_string+')').css('background-color', 'green');
$('.selected').removeClass('selected').next().css('background-color', 'red').addClass('selected');
}
});
function clearInput() {
typed_string = '';
}
And I'm using this HTML:
Press any key to save text.<br /><br />
<div id="typedtext" style="border: 1px solid #09F; padding: 5px;"></div>
<br /><br />
Let's test to filter some items from the li. (use up/down or left/right keys to select next item)
<ul id="testlist">
<li>item</li>
<li>test</li>
<li>more test</li>
<li>another item</li>
<li>test item</li>
<li>more item</li>
<li>foo</li>
<li>foo bar</li>
<li>bar</li>
<li>more foo</li>
</ul>
I think it's easy enough for you to change the HTML code to fit your needs.
What's the reason you don't want to use an input, is it just so if JS isn't available you can graceful fall back to the select? If so this might do what you want, I've used the select as a basis and taken the values from there although I have ended up putting an input in there.
Following on from Neal's answer, I think autocomplete is fairly similar to what you need, but if you want to display the results differently I've got a second approach in the same example that displays the filtered results.
Full example version here:
http://jsfiddle.net/R7APm/9/
Here's the JS from it:
$opts = $('option', '#myselect');
//Grab the text from the select (could use option values instead with .val()
var values = [];
$.each($opts, function(i, opt) {
values.push($(opt).text());
});
$div = $('<div/>');
//Autocomplete version
$input = $('<input/>').autocomplete({
source: values
});
//Filter in div version
$wordlist = $('<div id="wordlist"/>');
$wordlist.text(values.join(", "));
$input.keyup(function() {
matches = $.grep(values, function(el, i) {
if (el.toLowerCase().indexOf($input.val().toLowerCase()) >= 0) {
return true;
} else {
return false;
}
});
$wordlist.text(matches.join(", "));
});
//Add new elements to wrapper div
$div.append($input);
$div.append($wordlist);
//Replace select with wrapper div
$('#replaceme').replaceWith($div);
$input.focus();
If you don't want to use a hidden dropdown (which i still strongly advise) i suggest following:
Make the DIV focusable
This works thanks to the "tabindex" workaround found at
http://snook.ca/archives/accessibility_and_usability/elements_focusable_with_tabindex
Capture only the keystrokes on your custom dropdown, NOT just all on the whole document. First, it's unusual behavior. Second, how would you deal with more than 1 custom dropdown?
Store the filter string via jQuery's data container
Check out the full working demo with a simple language dropdown at http://jsfiddle.net/aWE8b/
The demo contains:
Custom Dropdown
Supported keys:
Backspace
Enter
Escape
Left, Up
Right, Down
2 Modes:
Filter: remove unmatched items
Select: highlight first matched item
Related
I have used the guide provided on w3school to implement a drag and drop function in my website http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_ondrop_html. Now what I wish to do is add a function of some sort that grants premission to user to use the drag and drop function.
Currntly anyone visiting my website can drag and drop elements but I want to add a feature, say for example, if user presses certain key on the keyboard or input certain word inside a specifc textfield.
Also, not sure if this is possible to have this, instead of having a textfield is it possible to allow the user to simply click on the webpage/document and type in a word that doesn't display on the screen but is being picked up by the website.
I have researched but haven't found anything useful to follow so any help is welcomed.
jquery validation based on drag & dropped items
http://www.webdeveloper.com/forum/showthread.php?299067-Javascript-Drag-and-Drop-Function-with-validation%28Kindly-help-me-to-solve-this-prob%29
EDITED:
var code = "";
window.addEventListener("keydown",function(e) {
code = (code+String.fromCharCode(e.keyCode || e.which)).substr(-11);
if (code == "SECRET" ) {
for(i = 0, i <=20, i++) {
document.getElementById("dragID" + i).setAttribute("draggable", "true");
alert('unlocked');
}
}
},false);
First your last question!
Yes it's possible:
source: https://stackoverflow.com/a/32236394/2543240
So now that we have picked up the entered code in a string, a simple if statement should do the job:
var code = "";
window.addEventListener("keydown",function(e) {
code = (code+String.fromCharCode(e.keyCode || e.which)).substr(-11);
if (code == "SECRET" ) {
$('#dragtarget').attr('draggable', "true");
alert('unlocked');
}
},false);
In your html code, set draggable attribute to false:
<p ondragstart="dragStart(event)" draggable="false" id="dragtarget">Drag me!</p>
check this Fiddle
Edit: Without using jQuery:
var code = "";
window.addEventListener("keydown",function(e) {
code = (code+String.fromCharCode(e.keyCode || e.which)).substr(-11);
if (code == "SECRET" ) {
document.getElementById("dragtarget").setAttribute("draggable", "true");
alert('unlocked');
}
},false);
Fiddle 2
Edit2:
Add a button to activate dragging:
As you noted in your comment bellow.
Check this Fiddle 3
Edit3:
If you have multiple cases you can define a class, for example class="targets" for all of them.
Then iterate through multiple elements with same class:
var x = document.getElementsByClassName("targets");
for (var i=0; i < x.length; i++) {
x[i].setAttribute("draggable", "true");
}
I am not sure if you considered using jQuery's draggable feature, but the API exposes a very simple mechanism for enabling/disabling drag-ability among other things.
Here's a code snippet
$("#draggable").draggable({
revert: true
});
$("#droppable").droppable();
And here's the fiddle: https://jsfiddle.net/a5xktf0g/
In this example, the validation is based on button click event, you could easily tie the validation to a key-up event and capture the key that was pressed. Append the key to a string and check the last "n" characters if they match your "n" character validation string.
I'm attempting to make a page that allows users to input text and it will automatically format the input -- as in a screenplay format (similar to Amazon's StoryWriter).
So far I can check for text with ":contains('example text')" and add/remove classes to it. The problem is that all of the following p tags inherit that class.
My solution so far is to use .next() to remove the class I added, but that is limited since there might be need for a line break in the script (in dialogue for instance) and that will remove the dialogue class.
$('.content').on('input', function() {
$("p.input:contains('INT.')").addClass("high").next(".input").removeClass("high");
$("p.input:contains('EXT.')").addClass("high").next(".input").removeClass("high");
});
I can't get || to work in the :contains parameter either, but that's the least of my issues.
I have a JS fiddle
I've worked on this for a while now, and if I could change only the node that contains the text (INT. or EXT. in this example) and leaves the rest alone that would work and I could apply it to the rest of the script.
Any help would be appreciated, I'm new to the stackoverflow so thank you.
See the comments in the code below for an explanation of what's going on.
Fiddle Example
JQuery
var main = function(){
var content = $('.content');
content.on('input', function() {
$("p.input").each(function() {
//Get the html content for the current p input.
var text = $(this).html();
//indexOf will return a positive value if "INT." or "EXT." exists in the html
if (text.indexOf('INT.') !== -1 || text.indexOf('EXT.') !== -1) {
$(this).addClass('high');
}
//You could include additional "if else" blocks to check and apply different conditions
else { //The required text does not exist, so remove the class for the current input
$(this).removeClass('high');
}
});
});
};//main close
$(document).ready(main);
I am currently using a html5 text editor (bootstrap-wysihtml5). I'm trying to use a "keypress" event (on tab) to select specific words within the text editor.
Here is an example of my text:
<div>
My name is {{name}} and I enjoy {{programming in Rails}}.
</div>
<div>
{{Friend Name}} suggested that we get in touch to {{catch up}}.
He spoke {{highly}} about you and said that we should {{get together sometime}}.
</div>
Goal: on 'keypress' tab event, highlight each word within {{ }}.
i.e.
1. Press tab once, will highlight {{name}}.
2. Press tab on the 2nd time, will highlight {{programming in Rails}}, & so on.
Here is what I have implemented so far:
$('#wysihtml5').each(function(i, elem) {
$(elem).wysihtml5({
"font-styles": true,
"events": {
"focus": function() {
$('.wysihtml5-sandbox').contents().find('body').on("keydown",function(event) {
event.preventDefault();
var numLoops = _.size($(this).children());
var keyCode = event.keyCode || event.which;
if (keyCode == 9){
// loop thru all children divs
for (var i = 0; i < numLoops; i++) {
// get array of all matched items {{}}
var sentence = $($(this).children()[i]).html();
var toSwap = sentence.match(/\{{(.*?)\}}/g);
var numSwap = _.size(toSwap);
// NEED TO FIGURE OUT: How to select matched item..and move to the next one on tab
}
}
});
}
}
});
});
Any thoughts? I've been spending 2 days on finding how to make this work. The following are the references for what I have looked at:
jQuery Set Cursor Position in Text Area
Selecting text in an element (akin to highlighting with your mouse)
javascript regex replace html chars
What Is A Text Node, Its Uses? //document.createTextNode()
What you want is the index of the Regex matches.
If you perform the Regex as follows:
var reg = /\{{(.*?)\}}/g; // The Regex selector
while(match=reg.exec(sentence)) { // Iterate all the matched strings
// match.index gives the starting position of the matched string
// match.length gives the length of the matched string, number of characters
}
You will get the position and length of all the matches which can be used for selection. The while loop iterates all the matches.
Save the matches and user their index and length values to select them one by one.
Edit
Back again. As you probably have experienced, selecting text in javascript is not the easiest task but it is completely doable.
I put together a small JSFiddle to demonstrate the technique I used to get the correct result. You can find it here.
I hope it's kind of clear and I tried to comment it well.
Of course, if you have any question, just ask!
Cheers!
I have working on this problem for a couple weeks off and on. What I am trying to do is have placeholders to show users where they can type. When they do type, I want the placeholder to disappear, but reappear again when the div is empty.
Every thing I have found has to do with cross-browser placeholder support for inputs and textareas, and trying to apply the code for them to my issue results in failure.
I am using h1s for titles and standard divs for descriptions.
My code looks like this:
HTML
<div class="page-desc" contenteditable="true" data-placeholder="Write your description here."></div>
jQuery
var placeholder = '<span class="placeholder">Write your title here</span>';
$(this).html(placeholder);
I have more jQuery code, but it sucks. I am currently using keyup to hide the placeholder, and that's obviously not working. Can someone help me out?
I am totally open to using vanilla JavaScript as well.
You can have something like this:
$('#xdiv').html($('#xdiv').data('placeholder'));
$('#xdiv').keydown(function() {
if ($(this).html() == $(this).data('placeholder')) {
$('#xdiv').html('');
}
})
$('#xdiv').keyup(function() {
if ($(this).html() == '') {
$('#xdiv').html($('#xdiv').data('placeholder'));
}
})
Initially it sets DIV's HTML to placeholder text. Then when user begins to type (on keydown) it checks if DIV still has the placeholder text and if so - removes it. And since user can delete all the data - it checks (on keyup) if DIV is empty, and if so - restores placeholder's text.
Demo: http://jsfiddle.net/bP7RF/
there's a way to do it in css (modern browser only)
.pageDesc:empty:after {content : "Write your description here.";}
Javascript solution (not as pretty, but more cross-browser):
$("#in").keyup(function(){
if(!$(this).html()){
$(this).html($(this).attr('data-placeholder'));
$(this).attr('showing-placeholder',true);
}
});
$("#in").keydown(function(){
if($(this).attr('showing-placeholder')){
$(this).html('');
$(this).attr('showing-placeholder','');
}
});
Working Example: JSFiddle;
Why not use the Blur and Focus event handlers from jQuery and check the Text value of the Div?
Code for quick look:
$('[contenteditable="true"]').blur(function() {
var text = $.trim($(this).text());
var ph = $('<span/>',{ 'class':"placeholder"})
.text($(this).data('placeholder')||'');
if (text == '') {
$(this).html(ph);
}
}).focus(function() {
if ($(this).children('.placeholder').length > 0) {
$(this).html('<span> </span>');
}
});
Fiddle for example: http://jsfiddle.net/qvvVr/1/
Why can't you use the placeholder attribute of the input element.
It seems to do exactly what you want and it's very well supported
(http://caniuse.com/input-placeholder).
Sorry if I have missed something.
I have few tabs with input on each tab. I am using and I set on each input the same class so I can carry the value from one tab to another, like this:
$('.group_input1').change(function(){
$('.group_input1').val(this.value);
});
Now, to show each tab I am using shortkeys like this:
if (e.keyCode == 71) {
$("#input1").fadeIn();
$(".group_input").focus();
}
Each time the #input1 fade's In its input gets a value of the character pressed, so I am looking for something to say, when $(".group_input").focus(); delete last character ?
Or is there a better way to do it?
Something like (code not tested) -
$('#target').focus(function() {
$("#input1").val($("#input1").val().substring(0,$("#input1").val().length-1))
});
If I have understood your question correctly, you can use the "substring" function to remove the last character from the string e.g.
var text = "input1";
var text_new = text.substring(0, text.length-1);
alert(text_new);
I'd have to see more of the code to understand why the key is being added to that input. Is the e.keyCode portion within a keydown event?
As a simple solution just to get something that works you could set up a focus event handler on group_input to remove that character (see below), but I doubt it's the ideal way to do it. You should instead block that key from being added to the text. Can you set up an example on jsfiddle?
$('.group_input').focus(function () {
var text = $('#input1').val();
$('#input1').val(text.substr(0, text.length - 1));
}
To delete the last character you could do:
$(".group_input").focus(function(){
var valore = $(this).val();
$(this).val(valore.substring(0, valore.length - 1));
});
I found the problem. For the shortkeys I was using keydown instead of keyup, so I replaced it