Incorrect Placement of Comma in Sum - javascript

I have a table with a text input on each line. Users can specify a dollar amount within each text box. My code loops through each text input and simply sums up the values. My problem is that when a user enters a value over >= 1,000,000 the sum becomes incorrect. For example, when a user enters 1,000,000 the sum is 1,000.
function init_icheck() {
$('#datatable input[type=checkbox]').iCheck({
checkboxClass: 'icheckbox_square-blue',
increaseArea: '10%'
});
}
// When Pay in Full Checkbox is Checked fill in Pay This Time Field with Invoice Amount Due Value
function paynow() {
var payFull = $('input[type="checkbox"].payfull');
payFull.on('ifChecked', function(event) {
$(this).parents('tr').find('.paynow').val($(this).val().replace('$', ''));
CalcFooter();
});
}
// If Pay in Full Unchecked then remove value from respective Pay This Time Input
// Only bind the ifUnchecked event if the checkbox is checked
function remove_checkbox() {
var payFull = $('input[type="checkbox"].payfull');
payFull.on('ifUnchecked', function(event) {
if ($(this).parents('tr').find('.paynow').val() == $(this).val().replace('$', '')) {
$(this).parents('tr').find('.paynow').val('');
CalcFooter();
}
});
}
// If Pay This Time changes recalculate total
function recalc_total() {
$('.paynow').keyup(function() {
var $ThisCheck = $(this).parents('tr').find('.payfull');
// Add Commas if # is over 1,000
$(this).val(addCommas($(this).val().replace(/,/g, '')));
if ($(this).val() == $ThisCheck.val().replace('$', '')) {
$ThisCheck.iCheck('check');
} else {
$ThisCheck.iCheck('uncheck');
}
CalcFooter();
});
}
// Recalc Function
function CalcFooter() {
var amtPage = 0;
var amtTotal = 0;
var Sum = 0;
$('.paynow').each(function(index, Obj) {
var value = parseFloat($(this).val().replace(',', ''));
if (!isNaN(value)) amtPage += value;
});
$('#datatable').DataTable().$('.paynow').each(function(index, Obj) {
var value = parseFloat($(this).val().replace(',', ''));
if (!isNaN(value)) amtTotal += value;
});
$('#amounttopay').text(
'Page: $' + addCommas(amtPage.toFixed(2)) +
' / Total: $' + addCommas(amtTotal.toFixed(2))
);
}
// Add Commas if value > 1,000
addCommas = function(input) {
// If the regex doesn't match, `replace` returns the string unmodified
return (input.toString()).replace(
// Each parentheses group (or 'capture') in this regex becomes an argument
// to the function; in this case, every argument after 'match'
/^([-+]?)(0?)(\d+)(.?)(\d+)$/g,
function(match, sign, zeros, before, decimal, after) {
// Less obtrusive than adding 'reverse' method on all strings
var reverseString = function(string) {
return string.split('').reverse().join('');
};
// Insert commas every three characters from the right
var insertCommas = function(string) {
// Reverse, because it's easier to do things from the left
var reversed = reverseString(string);
// Add commas every three characters
var reversedWithCommas = reversed.match(/.{1,3}/g).join(',');
// Reverse again (back to normal)
return reverseString(reversedWithCommas);
};
// If there was no decimal, the last capture grabs the final digit, so
// we have to put it back together with the 'before' substring
return sign + (decimal ? insertCommas(before) + decimal + after : insertCommas(before + after));
}
);
};
// Reinitialize iCheck on Pagination Change
$('#datatable').on('draw.dt', function() {
init_icheck();
paynow();
recalc_total();
remove_checkbox();
CalcFooter();
});
// Initialize Datatables
$('#datatable').dataTable({
"stateSave": true,
"oLanguage": {
"sSearch": "Search Results:"
}
});
I have a simple jsfiddle that illustrates this issue. I thank you in advance for pointing me in the right direction.
http://jsfiddle.net/tgf59ezr/14/

Using .replace(',', '') only replaces the first instance of the searched string, causing the number parsing to not work as intended.
Use this instead:
.replace(/,/g, '')
The g means replace all instances.
http://jsfiddle.net/da03j0aa/
Reference: String.prototype.replace()

Related

Fromat a TextField as soon as it's written to

I am trying to update a TextField as soon as the user types something in. I like to avoid people writing in different text formats but have the proper capitlisation eg. instead of jOHN or JOHN or john, the Text needs to be updated (firstCapitalLetter) John in this case.
I tried to copy the method as described here: Format input text to uppercase but I am failing to adapt it to my case. The txtFirstName is the ID of the TextField.
NWF$(document).ready(function () {
NWF$("#" + txtFirstName).change(function () {
// get the text value from the FirstNname textfield
var textContent = NWF$('#' + txtFirstName).text();
// check to see if the value is not null
if (textContent.length > 0) {
// format the first letter to UpperCase and the rest to LowerCase
textContent = NWF$("#" + txtFirstName).toUpperCase() + txtFirstName.substr(1).toLowerCase();
NWF.value = textContent;
}
});
});
I managed to get it working, after so many trials.
Now, the txtFirstName changes the format as wanted :)
NWF$(document).ready(function () {
NWF$("#" + txtFirstName).change(function () {
// get the text value from the FirstNname textfield
var textContent = this.value;
// check to see if the value is not null
if (textContent.length > 0) {
// format the first letter to UpperCase and the rest to LowerCase
textContent = textContent[0].toUpperCase() + textContent.substr(1).toLowerCase();
this.value = textContent;
}
});
});
Here is another option if you have to update two seperate txtFields.
Maybe one of you can propose a better approach on this.
Basically, I wanted to say, when the the txtFields are updated then they need to be formatted to the proper capitalisation to avoid things like: john / JOHN / jOHn
NWF$(document).ready(function () {
NWF$("#" + txtFirstName).change(function () {
// get the text value from the FirstNname textfield
var textContent = this.value; //alert(textContent)
// check to see if the value is not null
if (textContent.length > 0) {
// format the first letter to UpperCase and the rest to LowerCase
textContent = textContent[0].toUpperCase() + textContent.substr(1).toLowerCase();
this.value = textContent;
}
});
NWF$("#" + txtLastName).change(function () {
// get the text value from the FirstNname textfield
var textContent = this.value; //alert(textContent)
// check to see if the value is not null
if (textContent.length > 0) {
// format the first letter to UpperCase and the rest to LowerCase
textContent = textContent[0].toUpperCase() + textContent.substr(1).toLowerCase();
this.value = textContent;
}
});
});

Remove current input if not yyyy/mm/dd format?

I want to remove input data if it is not match with yyyy/mm/dd format ! I tried with following but only remove letter and special character ...
eg.
20144 -> must remove last 4
2014// -> must remove last /
2014/01/123 -> must remove last 3
$("input").on("keyup", function() {
console.log(this.value);
this.value = this.value.replace(/[^(\d{4})\/(\d{1,2})\/(\d{1,2})]/g, '');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text">
The strategy is actually quite simple, once you actually break down the logic of what you want. So, you want to coerce user input into a YYYY/MM/DD format. We can do this in a step-by-step manner:
Split the input's value by the / character. You now get an array.
We keep the first three elements of the array, which should correspond to YYYY, MM, and DD respectively. We will ignore whatever fragments that come after, since they aren't part of the valid date. This can be done using .slice(0,3) on the array.
Parse each individual part of the array:
At index of 0, you have the year fragment. Use .substring(0,4) so that it is trimmed to 4 characters max
At index of 1 or 2, you have the month/day fragment respectively. Use .substring(0,2) so that it is trimmed to 2 characters max
Join the resulting array back using .join('/').
If the array contains empty elements, you will end up duplicated // in your string. Simply trim them away using regex, .replace(/\/(\/)+/, '/')
You will notice that in my logic I have not included padding numbers, e.g.
. converting days from 1 to 01. You cannot do this when the user is inputting, because you never know if the user intends to type one or two digits. If you want this, you will have to reparse the input onblur, because that is when you know the user is done with the input.
See proof-of-concept below:
$('input').on('keyup', function() {
var valueParts = this.value.split('/');
if (!valueParts.length) {
return;
}
// Only keep the first 3 elements of array
valueParts = valueParts.slice(0, 3);
// Substring array (keep first 4 characters for year, and first 2 characters for month/day)
var substringCounts = [4, 2, 2];
substringCounts.forEach(function(substringCount, index) {
// If index does not exist in array, skip it
if (!valueParts[index])
return;
valueParts[index] = valueParts[index].substring(0, substringCount);
});
// Join remaining elements
var parsedString = valueParts.join('/');
// Trim extraneous slashes
parsedString = parsedString.replace(/\/(\/)+/, '/');
this.value = parsedString;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text">
Note: if you want to pad the numbers, you will have to include the following logic, on top of what has been mentioned above:
// Pad numbers on blur
$('input').on('blur', function() {
var valueParts = this.value.split('/');
if (!valueParts.length) {
return;
}
// Only keep the first 3 elements of array
valueParts = valueParts.slice(0, 3);
// Pad lengths (year to 4 digits, month to 2 digits, day to 2 digits)
var padLengths = [4, 2, 2];
padLengths.forEach(function(padLength, index) {
// If index does not exist in array, skip it
if (!valueParts[index])
return;
valueParts[index] = valueParts[index].padStart(padLength, '0');
});
// Join remaining elements
var parsedString = valueParts.join('/');
// Trim extraneous slashes
parsedString = parsedString.replace(/\/(\/)+/, '/');
this.value = parsedString;
});
With that in mind, if you want to combine the above two logic together, you can abstract the part dealing with "joining remaining elements" and "trim extraneous slashes". I have hidden the code snippet below, since it's very verbose and mostly contains the same logic as mentioned above:
// Helper method: joins array using '/' and trims duplicated joining characters
function joinAndTrimSlashes(valueArray) {
// Join remaining elements
var parsedString = valueArray.join('/');
// Trim extraneous slashes
parsedString = parsedString.replace(/\/(\/)+/, '/');
return parsedString;
}
$('input').on('keyup', function() {
var valueParts = this.value.split('/');
if (!valueParts.length)
return;
// Only keep the first 3 elements of array
valueParts = valueParts.slice(0, 3);
// Substring array (keep first 4 characters for year, and first 2 characters for month/day)
var substringCounts = [4, 2, 2];
substringCounts.forEach(function(substringCount, index) {
// If index does not exist in array, skip it
if (!valueParts[index])
return;
valueParts[index] = valueParts[index].substring(0, substringCount);
});
this.value = joinAndTrimSlashes(valueParts);
});
// Pad numbers on blur
$('input').on('blur', function() {
var valueParts = this.value.split('/');
if (!valueParts.length)
return;
// Only keep the first 3 elements of array
valueParts = valueParts.slice(0, 3);
// Pad lengths (year to 4 digits, month to 2 digits, day to 2 digits)
var padLengths = [4, 2, 2];
padLengths.forEach(function(padLength, index) {
// If index does not exist in array, skip it
if (!valueParts[index])
return;
valueParts[index] = valueParts[index].padStart(padLength, '0');
});
this.value = joinAndTrimSlashes(valueParts);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text">
Since I do think that pure regex is going to be very bad at solving this you can just do a manual pass like e.g.
var good = '2013/01/01';
var bad1 = '20123/01/02';
var bad2 = '2011//01/03';
var bad3 = '2010/01/034';
var bad4 = '2009//01/045';
var bad5 = '20083//01/223';
var all = [ good, bad1, bad2, bad3, bad4, bad5 ];
function normalizeDate(dateString) {
var currentValue = dateString.replace(/\/{2,}/g,'/'); //remove repeated /
var parts = currentValue.split('/').map(function (value) {
return value.replace(/\D/g, '0');
});
var newParts = [
parts[0] ? parts[0].padEnd(4,'0').substring(0,4) : '2000' ,
parts[1] ? parts[1].padStart(2, '0').substring(0,2) : '01',
parts[2] ? parts[2].padStart(2, '0').substring(0,2) : '01'
];
return newParts.join('/');
}
for (var i = 0;i < all.length;i++) {
console.log(normalizeDate(all[i]));
}
$("input").on("keyup", function() {
var validationRegex = new RegExp(/([12]\d{3}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01]))/);
if(!validationRegex.test(this.value)){
this.value = '';
}
});
This will match only the format YYYY/MM/DD.
Thank all for your answer! I reference your answers and I can figure out to solve my desire .
I believe there have much better solution so answer here if you guy have better one
var format = ["number","number","number","number","slash","number","number","slash","number","number"];
$("input").on("keyup", function() {
if(this.value.length > format.length) {
this.value = this.value.slice(0,format.length);
return;
}
for(var i in this.value) {
if(format[i] == "number") {
if(!this.value[i].match(/[0-9]/)) {
this.value = this.value.slice(0,i);
}
} else {
if(this.value[i] != "/") {
this.value = this.value.slice(0,i);
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text">

upper case both last name when there is a dash in between

I would like to modify an existing JavaScript function that formats a user name properly by setting the first name first letter to upper case, as well as the first name of the last name.
There are some last names that are hyphenated and when those happen, they look like Hugo Bearsotti-potz, when in fact it should be Hugo Bearsotti-Potz
I would like to ask for help to modify this function so it allows proper case to hyphenated last names, if possible.
Here is the existing code (pertinent snippet only):
if (input) {
var out = '';
input.split(delimiter || ' ').forEach(function (sector) {
var x = sector.toLowerCase();
out += x.charAt(0).toUpperCase() + x.substr(1) + ' ';
});
if (out.length > 0) {
out = out.substring(0, out.length - 1);
}
return out;
}
Many thanks.
this should satisfy your test conditions set: http://plnkr.co/edit/9welW6?p=preview
html:
<input type="text" ng-model="foo">
<br>
{{foo | nameCaps}}
js:
app.filter('nameCaps',function(){
return function(input) {
if (!input) return;
return input.toString().replace(/\b([a-z])/g, function(ch) {
return ch.toUpperCase();
});
};
});
although I'm wary about making assumptions about people's names http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/
You could also create a function for capitalizing the first character after any given delimiter. Not quite as succinct as the regex solution though.
function capitalizeAfter(input, delimiter) {
var output = '',
pieces = input.split(delimiter);
pieces.forEach(function(section, index) {
// capitalize the first character and add the remaining section back
output += section[0].toUpperCase() + section.substr(1);
// add the delimiter back if it isn't the last section
if (index !== pieces.length - 1) {
output += delimiter;
}
}
return output;
}
Then it would be used like so:
if (input) {
return capitalizeAfter(capitalizeAfter(input.toLowerCase(), ' '), '-');
}

jquery filter script not ignoring diacritics and not highlighting string matches as user enters filter text into text input field

I have multiple vocabulary tables on the same html page.
Above each vocabulary table, I would like to enable users to type a word or phrase in a text input field to view only the table rows that contain the typed string (word or phrase). For example, if you type "good" in the text input field, the table rows that do not contain the string "good" will disappear. This is already working if you go to http://www.amanado.com/idioma-colombiano/, click on "Vocabulario (oficial y de jerga) - palabras y frases comunes" to expand the accordion section, and then type "good" in the text input field below the words "Ingresa palabra o frase en el siguiente campo para filtrar la información de la tabla". After typing "good" into the text input field, all but 7 rows in the vocabulary table should disappear (7 rows remain).
I am having the following 3 issues:
1) I am unable to ignore accents (e.g., é, ñ, ü) in the same way that case is already successfully ignored. For example, if a user enters "que" in the input field, rows that contain "que" and "qué" should not disappear. However, when you type "que", rows that contain "qué" do erroneously disappear. As you can see, if you type "que" into the input field (excluding the quotes), 2 records that contain "que" will remain. And, if you type or paste "qué" into the input field (excluding the quotes), 6 records that contain "qué" will remain.
2) I am trying to use a version of jquery.highlight.js to highlight the string matches in the rows that remain/do not disappear. For an example of how this should look visually, type "que" into the input field where instructed in the 2nd paragraph of this question summary and you will see the string "que" is highlighted in the 2 rows that remain/do not disappear. Note that this is not working correctly because I hardcoded the "que" highlight by inserting the script "$("table td").highlight("que");" into the "head" section of the html page for the purposes of demonstrating that (a) jquery.highlight.js is active/functioning and (b) providing a visual example of how the highlighted text is intended to appear.
3) In addition to the javascript that enables users to enter a word or phrase in a field to view only the table rows that contain the entered word or phrase not successfully ignoring accents (e.g., é, ñ, ü), which is the desired behavior, the jquery.highlight.js script is also not successfully ignoring accents (e.g., é, ñ, ü). For example, type "pues" in the input field where instructed in the 2nd paragraph of this question summary and you will multiple cases of the string "Qué" and "qué" not successfully highlighted in the rows that remain/do not disappear. Remember, I hardcoded the "que" highlight by inserting the script "$("table td").highlight("que");" into the section of the html page, so the strings "que", "qué", "Que" and "Qué" should all be highlighted in the table rows that remain/do not disappear if any of the strings "que", "qué", "Que" or "Qué" are entered into the input field given it is intended that (a) case and (b) accents (e.g., é, ñ, ü) are ignored. It is interesting to note that functionionality to "ignoreAccents" is included in the version of jquery.highlight.js that I am using.
Below are:
(a) the input field as it appears in my html;
(b) the javascript I am using to enable users to enter a word or phrase in a field to view only the table rows that contain the entered word or phrase (for the purpose of brevity, this is referred to below as "filter javascript"); and
(c) the version of jquery.highlight.js javascript I am using to highlight text.
Please note: I am not a software engineer, but I do know how to implement a change if someone tells me what to do specifically (e.g., make this exact change, then make this exact change, then make this exact change). I appreciate any assistance anyone can provide and literal instructions would be especially appreciated. And, It is always my intent to use the least amount of code (e.g., javascript, css, html) to achieve the most.
Additional notes/considerations are included at the bottom of this question summary.
(a) input field starts here
<form class="live-search" action="" method="post">
<p>Ingresa palabra o frase en el siguiente campo para filtrar la información de la tabla</p>
<input class="input-text-tr" type="text" value="Mostrar sólo filas que contengan..." />
<span class="filter-count-tr"></span>
</form>
(a) input field ends here
(b) filter javascript starts here
$(function() {
$(".input-text-tr").on('keyup', function(e) {
var disallow = [37, 38, 39, 40];//ignore arrow keys
if($.inArray(e.which, disallow) > -1) {
return true;
}
var inputField = this,
val = this.value,
pattern = new RegExp(val, "i"),
$group = $(this).closest(".group"),
$trs = $group.find(".myTable tbody tr"),
$s;
if(val === '') {
$s = $trs;
}
else {
$s = $();
$trs.stop(true,true).each(function(i, tr) {
if(val !== inputField.value) {//if user has made another keystroke
return false;//break out of .each() and hence out of the event handler
}
$tr = $(tr);
if ($tr.text().match(pattern)) {
$s = $s.add(tr);
}
});
//$trs.not($s).fadeOut();
$trs.not($s).hide();
}
$group.find(".filter-count-tr").text("(" + $s.show ().length + ")");
}).on('focus blur', function() {
if (this.defaultValue == this.value) this.value = '';
else if (this.value == '') this.value = this.defaultValue;
});
$(".group").each(function() {
$this = $(this);
$this.find(".filter-count-tr").text("(" + $this.find("tbody tr").length + ")");
});
});
(b) filter javascript ends here
(c) jquery.highlight.js javascript starts here
jQuery.extend({
highlight: function (node, re, nodeName, className, ignoreAccents) {
if (node.nodeType === 3) {
var nodeData = node.data;
if (ignoreAccents) {
nodeData = jQuery.removeDiacratics(nodeData);
}
var match = nodeData.match(re);
if (match) {
var highlight = document.createElement(nodeName || 'span');
highlight.className = className || 'highlight'; var wordNode = node.splitText(match.index);
wordNode.splitText(match[0].length);
var wordClone = wordNode.cloneNode(true);
highlight.appendChild(wordClone);
wordNode.parentNode.replaceChild(highlight, wordNode);
return 1; //skip added node in parent
}
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
!(node.tagName === nodeName.toUpperCase() &&
node.className === className)) { // skip if already highlighted
for (var i = 0; i < node.childNodes.length; i++) {
i += jQuery.highlight(node.childNodes[i], re, nodeName, className, ignoreAccents);
}
}
return 0;
},
removeDiacratics : function(str) {
var rExps = [
{re:/[\xC0-\xC6]/g, ch:'A'},
{re:/[\xE0-\xE6]/g, ch:'a'},
{re:/[\xC8-\xCB]/g, ch:'E'},
{re:/[\xE8-\xEB]/g, ch:'e'},
{re:/[\xCC-\xCF]/g, ch:'I'},
{re:/[\xEC-\xEF]/g, ch:'i'},
{re:/[\xD2-\xD6]/g, ch:'O'},
{re:/[\xF2-\xF6]/g, ch:'o'},
{re:/[\xD9-\xDC]/g, ch:'U'},
{re:/[\xF9-\xFC]/g, ch:'u'},
{re:/[\xD1]/g, ch:'N'},
{re:/[\xF1]/g, ch:'n'}
];
for (var i = 0, len = rExps.length; i < len; i++) {
str = str.replace(rExps[i].re, rExps[i].ch);
}
return str;
}
});
jQuery.fn.unhighlight = function (options) {
var settings = { className: 'highlight', element: 'span' };
jQuery.extend(settings, options);
return this.find(settings.element + "." + settings.className).each(
function () {
var parent = this.parentNode;
parent.replaceChild(this.firstChild, this);
parent.normalize();
}).end();
};
jQuery.fn.highlight = function (words, options) {
var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false, ignoreAccents : true };
jQuery.extend(settings, options);
if (words.constructor === String) {
words = [words];
}
words = jQuery.grep(words, function(word, i) {
return word != '';
});
words = jQuery.map(words, function(word, i) {
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
});
if (words.length == 0) {
return this;
}
var flag = settings.caseSensitive ? "" : "i";
var pattern = "(" + words.join("|") + ")";
if (settings.wordsOnly) {
pattern = "\\b" + pattern + "\\b";
}
var re = [];
re.push(new RegExp(pattern, flag));
if (settings.ignoreAccents) {
var wordsNoAccents = jQuery.map(words, function(word, i) {
return jQuery.removeDiacratics(word);
});
var patternNoAccents;
if (settings.wordsOnly) {
// workaround for word separation using \\b
patternNoAccents = "( " + wordsNoAccents.join("|") + " )";
patternNoAccents = "\\b" + patternNoAccents + "\\b";
} else {
patternNoAccents = "(" + wordsNoAccents.join("|") + ")";
}
if (patternNoAccents!=pattern) {
re.push(new RegExp(patternNoAccents, flag));
}
}
return this.each(function () {
for (var i in re) {
jQuery.highlight(this, re[i], settings.element, settings.className, settings.ignoreAccents);
}
});
};
(c) jquery.highlight.js javascript ends here
Additional notes/considerations start here
1) It is my intent to enhance, not depart from, the javascript I am already using to enable users to enter a word or phrase in a field to view only the table rows that contain the entered word or phrase because the javascript I am already using is working with the exception of the above issues (thanks to Beetroot's excellent contributions to a previous question I published).
2) javascript I've found that touches on the functionality I am trying to achieve includes the following 4 examples (note because stackoverflow does not allow me to use more than a couple links in a question, I replaced "http://" with "[http:// here]" in the below examples):
a) [http:// here]demopill.com/jquery-onpage-text-highlighter-and-filter.html [most closely resembles functionality I am trying to achive; seems to successfully filter and highlight as a user enters text into an input field; successfully ignores case, but does not successfully ignore accents (e.g., é, ñ, ü)];
b) [http:// here]stackoverflow.com/search?q=jquery.highlight.js (dialogue on stackoverflow re: ignoring accented characters)
c) [http:// here]www.jquery.info/The-plugin-SearchHighlight (includes a highlight feature); and
d) [http:// here]docs.jquery.com/UI/Effects/Highlight (includes a highlight feature; note that I am already using "jquery ui" on the website referenced in paragraph 2 of this question summary).
Additional notes/considerations end here
Highlighting
With jquery.highlight.js installed on the page ...
change :
$group.find(".filter-count-tr").text("(" + $s.show().length + ")");
to :
$group.find(".filter-count-tr").text("(" + $s.show().unhighlight().highlight(val).length + ")");
However, the accent-insensitivity code below modifies this.
Accent Insensitivity
This seemed almost impossible but I had a breakthrough on finding this which indicates how the hightlight plugin might be modified to offer accent-insensitive highlighting.
To better understand the code, I refactored it into a better plugin (better for me anyway). It now puts no members into the jQuery namespace (previously one) and one member into jQuery.fn (previously two). With the new plugin, setting and unsetting highlights is performed as follows:
$(selector).highlight('set', words, options);
$(selector).highlight('unset', options);
Explanations and further examples are provided with the code (see below).
The 'set' settings include an '.accentInsensitive' option, which operates (I regret) on a limited number of hard-coded (Spanish) accented character groups implemented about as efficiently as I can manage using a private member in the plugin to cache reusable RegExps and replacement strings for later use by the 'set' method. It would be far better to have a generalized "Unicode normalisation" solution but that's something for another day.
The new plugin also afforded the opportunity to split out part of the code as a separate method, .makepattern, with the advantage that RegExp-ready patterns can be used externally, outside the plugin, with provision for them to be reinjected. This feature allows us to use the plugin as a resource for achieving the other aim here - namely accent-insensitive filtering - with absolute certainty that the RegExp patterns used (for highlighting and filtering) are identical.
Here's the plugin code :
/*
* jQuery highlightIt plugin
* by Beetroot-Beetroot
* https://stackoverflow.com/users/1142252/beetroot-beetroot
*
* based on Highlight by Bartek Szopka, 2009
* http://bartaz.github.com/sandbox.js/jquery.highlight.html,
* based on highlight v3 by Johann Burkard
* http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
*
* Most important changes:
* - Code refactored into jQuery preferred plugin pattern.
* - Now called with :
* - $(slector).highlight('set', words, options); previously $(slector).highlight(words, options);
* - $(slector).highlight('unset', options); previously $(slector).unhighlight(options);
* - $().highlight('makePattern', words, options); This new option returns a RegExp-ready pattern that can be used externally and/or re-injected for reuse (see .isPattern option below), thus avoiding remaking the pattern as might otherwise happen.
* - 'set' .isPattern option; When true, this new option indicates that the 'words' parameter is a prepared RegExp-ready pattern.
* - 'set' .accentInsensitive option; This new option is limited to operating on hard-coded character groups (eg, Spanish accented chars), not Unicode normalized (which would be a better approach but much harder to achieve and probably slower).
*
* Usage:
* // wrap every occurrance of text 'lorem' in content
* // with <span class='highlight'> (default options)
* $('#content').highlight('set', 'lorem');
*
* // search for and highlight more terms at once
* // so you can save some time on traversing DOM
* $('#content').highlight(['set', 'lorem', 'ipsum']);
* $('#content').highlight('set', 'lorem ipsum');
*
* // search only for entire word 'lorem'
* $('#content').highlight('set', 'lorem', { wordsOnly: true });
*
* // don't ignore case during search of term 'lorem'
* $('#content').highlight('set', 'lorem', { caseSensitive: true });
*
* // wrap every occurrance of term 'ipsum' in content
* // with <em class='important'>
* $('#content').highlight('set', 'ipsum', { element: 'em', className: 'important' });
*
* // remove default highlight
* $('#content').highlight('unset');
*
* // remove custom highlight
* $('#content').highlight('unset', { element: 'em', className: 'important' });
*
* // get accent-insensitive pattern
* $().highlight('makePattern', { element: 'lorem', {'accentInsensitive':true});
*
*
* Copyright (c) 2009 Bartek Szopka
*
* Licensed under MIT license.
*
*/
(function($) {
// **********************************
// ***** Start: Private Members *****
var pluginName = 'highlight';
var accentedForms = [//Spanish accednted chars
//Prototype ...
//['(c|ç)', '[cç]', '[CÇ]', new RegExp('(c|ç)','g'), new RegExp('(C|Ç)','g')],
['(a|á)', '[aá]'],
['(e|é)', '[eé]'],
['(i|í)', '[ií]'],
['(n|ñ)', '[nñ]'],
['(o|ó)', '[oó]'],
['(u|ú|ü)', '[uúü]']
];
//To save a lot of hard-coding and a lot of unnecessary repetition every time the "set" method is called, each row of accentedForms is now converted to the format of the prototype row, thus providing reusable RegExps and corresponding replacement strings.
//Note that case-sensitivity is established later in the 'set' settings so we prepare separate RegExps for upper and lower case here.
$.each(accentedForms, function(i, af) {
af[2] = af[1].toUpperCase();
af[3] = new RegExp(af[0], 'g');
af[4] = new RegExp(af[0].toUpperCase(), 'g');
});
var h = function(node, re, settings) {
if (node.nodeType === 3) {//text node
var match = node.data.match(re);
if (match) {
var wordNode = node.splitText(match.index);
wordNode.splitText(match[0].length);
$(wordNode).wrap($("<" + settings.element + ">").addClass(settings.className));
return 1;
}
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
!(node.tagName === settings.element.toUpperCase() && node.className === settings.className)) { // skip if already highlighted
for (var i = 0; i < node.childNodes.length; i++) {
i += h(node.childNodes[i], re, settings);
}
}
return 0;
};
// ***** Fin: Private Members *****
// ********************************
// *********************************
// ***** Start: Public Methods *****
var methods = {
//This is a utility method. It returns a string, not jQuery.
makePattern: function (words, options) {
var settings = {
'accentInsensitive': false
};
$.extend(settings, options || {});
if (words.constructor === String) {
words = [words];
}
words = $.grep(words, function(word, i) {
return word != '';
});
words = $.map(words, function(word, i) {
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
});
if (words.length == 0) { return ''; };
var pattern = "(" + words.join("|") + ")";
if (settings.accentInsensitive) {
$.each(accentedForms, function(i, af) {
pattern = pattern.replace(af[3], af[1]).replace(af[4], af[2]);
});
}
return pattern;
},
set: function (words, options) {
var settings = {
'className': 'highlight',
'element': 'span',
'caseSensitive': false,
'wordsOnly': false,
'accentInsensitive': false,
'isPattern': false
};
$.extend(settings, options || {});
var pattern = settings.isPattern ? words : methods.makePattern(words, settings);
if (pattern === '') { return this; };
if (settings.wordsOnly) {
pattern = "\\b" + pattern + "\\b";
}
var flag = settings.caseSensitive ? "" : "i";
var re = new RegExp(pattern, flag);
return this.each(function () {
h(this, re, settings);
});
},
unset: function (options) {
var settings = {
className: 'highlight',
element: 'span'
}, parent;
$.extend(settings, options || {});
return this.find(settings.element + "." + settings.className).each(function () {
parent = this.parentNode;
parent.replaceChild(this.firstChild, this);
parent.normalize();
}).end();
}
};
// ***** Fin: Public Methods *****
// *******************************
// *****************************
// ***** Start: Supervisor *****
$.fn[pluginName] = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || !method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist in jQuery.' + pluginName );
}
};
// ***** Fin: Supervisor *****
// ***************************
})( jQuery );
And here's the application code for the language site :
$(function() {
$(".text-input").on('keyup', function(e) {
var disallow = [37, 38, 39, 40];//ignore arrow keys
if($.inArray(e.which, disallow) > -1) {
return true;
}
var $group = $(this).closest(".group"),
accent_sensitive = false,
case_sensitive = false,
val = this.value,
pattern = $().highlight('makePattern', val, {
'accentInsensitive': !accent_sensitive,
'caseSensitive': case_sensitive
}),
$trs = $group.find(".myTable tbody tr"),
$s;
if(val === '') {
$s = $trs;
}
else {
$s = $();
$trs.stop(true,true).each(function(i, tr) {
$tr = $(tr);
//if ($tr.text().match(new RegExp(pattern, "i"))) {
if ($tr.text().match(new RegExp(pattern, case_sensitive ? '' : "i"))) {
$s = $s.add(tr);
}
});
$trs.not($s).hide();
}
$group.find(".filter-count-tr").text("(" + $s.show().highlight('unset').highlight('set', pattern, {
'isPattern':true,
'caseSensitive':case_sensitive
}).length + ")");
}).on('focus blur', function() {
if (this.defaultValue == this.value) this.value = '';
else if (this.value == '') this.value = this.defaultValue;
});
$(".group").each(function() {
$this = $(this);
$this.find(".filter-count-tr").text("(" + $this.find("tbody tr").length + ")");
});
});
All tested, so should work if installed properly.
By the way, I used this page as my source for Spanish accented characters.

Insert space after certain character into javascript string

I'm working on a form and I'd like to mask the input of the phone numbers. The plugins what I found aren't okay for me since the area code could be 1 or 2 character long.
What I'd like to do is the following:
when the user types his number after the first two character the script inserts a space on keyup, then after the next three and later after every fourth character.
So when someone types 44444444444 then in the textbox appears 44 44 444 4444.
I must check the second group as well, and when someone types there for example 1, the the number must look like: 44 1 444 4444
Is any solution to do that?
You could do something like this:
http://jsfiddle.net/ffwAA/4/
Which applies this function to the string to get the desired formatting:
function formatCode(str){
var result = str;
str = str.replace(/\D+/g, "");
var m = str.match(/^(\d\d)(?:([2-90]\d|1)(?:(\d\d\d)(\d+)?)?)?$/);
if(m){
result = m[1] + " ";
if(m[2]) result += m[2] + " ";
if(m[3]) result += m[3] + " ";
if(m[4]){
result += m[4].split(/(\d{4})/).join(" ");
result = result.replace(/\s+/g, " ");
}
}
return result;
}
And using this jQuery to set it up:
function update(obj){
var val = obj.value;
var got = formatCode(val);
if(got != val)
obj.value = got;
}
var timer;
var prev_val = "";
$('#code').keyup(function(){
clearTimeout(timer);
// when adding numbers at the end of input, update at once
// don't want to update when editing in the middle of the string or removing parts of it
// because it would move the carret location to the end of input, and make it unusable
if(this.value.indexOf(prev_val) == 0){
update(this);
prev_val = this.value;
return;
}
prev_val = this.value;
// in other cases update 1 second after the changes are done
timer = setTimeout(update, 1000, this);
});
Have you tried the maskedInput plugin?
http://digitalbush.com/projects/masked-input-plugin/
I think it can solve your problem.
Hope this helps. Cheers

Categories