Best way to adjust letter spacing every 3 chars in Ionic/Angular input box - html

I'd like users to enter a code and to assist them in transcribing it I'd hope to increase the spacing between every 3rd character they type. I've seen this nicely done for credit cards having 4 character spacing. This will be for an Ionic app so the simple input box coud be replaced with a customised Ionic control.
What methods have you used for this and what works best?
Open to Angular/Ionic code samples or a related web site tutorial.
Pure CSS would be nice.

Here is an other version, without jquery, works with alphanumerical and takes a configurable separator:
Typescript:
GROUP_SEPARATOR=" ";
......
format(valString) {
if (!valString) {
return '';
}
let val = valString.toString();
const parts = val.replace(/ /g, '');
return parts.replace(/\B(?=(?:\w{3})+(?!\w))/g, this.GROUP_SEPARATOR)
};
HTML
<input [(ngModel)]="input"
style="border:1px solid black" #myBudget="ngModel" (input)="input = format(input)">
DEMO

You can add space on keyup event.
Example
$('#input').on('keyup', function(e){
var val = $(this).val();
var newval = '';
val = val.replace(/\s/g, '');
for(var i=0; i < val.length; i++) {
if(i%3 == 0 && i > 0) newval = newval.concat(' ');
newval = newval.concat(val[i]);
}
$(this).val(newval);
})

I found a simpler method based on Vija's method ... Basically we match 3 non-space chars and we remove any previously added space chars. This is needed to allow the user to update or erase any chars in the text box.
A final solution may also need to adjust the position of the cursor based on where it was prior to performing the replace.
$('#input').on('keyup', function(e){
var val = $(this).val();
var newval = val.replace(/([^ ][^ ][^ ]) */g, "\$1 ").trim();
$(this).val(newval);
})

Related

using .replace in gmail to spreadsheet function. Is there anyway to replace everything EXCEPT a selection that matches a pattern? [duplicate]

This question already has answers here:
What is the best regular expression to check if a string is a valid URL?
(62 answers)
Closed 8 years ago.
Currently I have an input box which will detect the URL and parse the data.
So right now, I am using:
var urlR = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)
(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
var url= content.match(urlR);
The problem is, when I enter a URL like www.google.com, its not working. when I entered http://www.google.com, it is working.
I am not very fluent in regular expressions. Can anyone help me?
Regex if you want to ensure URL starts with HTTP/HTTPS:
https?:\/\/(www\.)?[-a-zA-Z0-9#:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()#:%_\+.~#?&//=]*)
If you do not require HTTP protocol:
[-a-zA-Z0-9#:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()#:%_\+.~#?&//=]*)
To try this out see http://regexr.com?37i6s, or for a version which is less restrictive http://regexr.com/3e6m0.
Example JavaScript implementation:
var expression = /[-a-zA-Z0-9#:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()#:%_\+.~#?&//=]*)?/gi;
var regex = new RegExp(expression);
var t = 'www.google.com';
if (t.match(regex)) {
alert("Successful match");
} else {
alert("No match");
}
(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})
Will match the following cases
http://www.foufos.gr
https://www.foufos.gr
http://foufos.gr
http://www.foufos.gr/kino
http://werer.gr
www.foufos.gr
www.mp3.com
www.t.co
http://t.co
http://www.t.co
https://www.t.co
www.aa.com
http://aa.com
http://www.aa.com
https://www.aa.com
Will NOT match the following
www.foufos
www.foufos-.gr
www.-foufos.gr
foufos.gr
http://www.foufos
http://foufos
www.mp3#.com
var expression = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi;
var regex = new RegExp(expression);
var check = [
'http://www.foufos.gr',
'https://www.foufos.gr',
'http://foufos.gr',
'http://www.foufos.gr/kino',
'http://werer.gr',
'www.foufos.gr',
'www.mp3.com',
'www.t.co',
'http://t.co',
'http://www.t.co',
'https://www.t.co',
'www.aa.com',
'http://aa.com',
'http://www.aa.com',
'https://www.aa.com',
'www.foufos',
'www.foufos-.gr',
'www.-foufos.gr',
'foufos.gr',
'http://www.foufos',
'http://foufos',
'www.mp3#.com'
];
check.forEach(function(entry) {
if (entry.match(regex)) {
$("#output").append( "<div >Success: " + entry + "</div>" );
} else {
$("#output").append( "<div>Fail: " + entry + "</div>" );
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="output"></div>
Check it in rubular - NEW version
Check it in rubular - old version
These are the droids you're looking for. This is taken from validator.js which is the library you should really use to do this. But if you want to roll your own, who am I to stop you? If you want pure regex then you can just take out the length check. I think it's a good idea to test the length of the URL though if you really want to determine compliance with the spec.
function isURL(str) {
var urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?#)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
var url = new RegExp(urlRegex, 'i');
return str.length < 2083 && url.test(str);
}
Test:
function isURL(str) {
var urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?#)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
var url = new RegExp(urlRegex, 'i');
return str.length < 2083 && url.test(str);
}
var check = [
'http://www.foufos.gr',
'https://www.foufos.gr',
'http://foufos.gr',
'http://www.foufos.gr/kino',
'http://werer.gr',
'www.foufos.gr',
'www.mp3.com',
'www.t.co',
'http://t.co',
'http://www.t.co',
'https://www.t.co',
'www.aa.com',
'http://aa.com',
'http://www.aa.com',
'https://www.aa.com',
'www.foufos',
'www.foufos-.gr',
'www.-foufos.gr',
'foufos.gr',
'http://www.foufos',
'http://foufos',
'www.mp3#.com'
];
for (let index = 0; index < check.length; index++) {
var url=check[index]
if (isURL(check[index]))
console.log(`${url} ✔`);
else{
console.log(`${url} ❌`);
}
}
Result
Another possible solution, above solution failed for me in parsing query string params.
var regex = new RegExp("^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.#:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?");
if(regex.test("http://google.com")){
alert("Successful match");
}else{
alert("No match");
}
In this solution please feel free to modify [-0-9A-Za-z\.#:%_\+~#=, to match the domain/sub domain name. In this solution query string parameters are also taken care.
If you are not using RegEx, then from the expression replace \\ by \.
Hope this helps.
Test:-
function IsUrl(url){
var regex = new RegExp("^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.#:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?");
if(regex.test(url)){
console.log(`${url} ✔`);
}else{
console.log(`${url} ❌`);
}}
var check = [
'http://www.foufos.gr',
'https://www.foufos.gr',
'http://foufos.gr',
'http://www.foufos.gr/kino',
'http://werer.gr',
'www.foufos.gr',
'www.mp3.com',
'www.t.co',
'http://t.co',
'http://www.t.co',
'https://www.t.co',
'www.aa.com',
'http://aa.com',
'http://www.aa.com',
'https://www.aa.com',
'www.foufos',
'www.foufos-.gr',
'www.-foufos.gr',
'foufos.gr',
'http://www.foufos',
'http://foufos',
'www.mp3#.com'
];
for (let index = 0; index < check.length; index++) {
IsUrl(check[index])
}
Result
I was trying to put together some JavaScript to validate a domain name (ex. google.com) and if it validates enable a submit button. I thought that I would share my code for those who are looking to accomplish something similar. It expects a domain without any http:// or www. value. The script uses a stripped down regular expression from above for domain matching, which isn't strict about fake TLD.
http://jsfiddle.net/nMVDS/1/
$(function () {
$('#whitelist_add').keyup(function () {
if ($(this).val() == '') { //Check to see if there is any text entered
//If there is no text within the input, disable the button
$('.whitelistCheck').attr('disabled', 'disabled');
} else {
// Domain name regular expression
var regex = new RegExp("^([0-9A-Za-z-\\.#:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?");
if (regex.test($(this).val())) {
// Domain looks OK
//alert("Successful match");
$('.whitelistCheck').removeAttr('disabled');
} else {
// Domain is NOT OK
//alert("No match");
$('.whitelistCheck').attr('disabled', 'disabled');
}
}
});
});
HTML FORM:
<form action="domain_management.php" method="get">
<input type="text" name="whitelist_add" id="whitelist_add" placeholder="domain.com">
<button type="submit" class="btn btn-success whitelistCheck" disabled='disabled'>Add to Whitelist</button>
</form>

Partial replace in docs what matches only and preserve formatting

Let's assume that we have first paragraph in our google document:
Wo1rd word so2me word he3re last.
We need to search and replace some parts of text but it must be highlighted in editions history just like we changed only that parts and we must not loose our format (bold, italic, color etc).
What i have/understood for that moment: capturing groups didn't work in replaceText() as described in documentation. We can use pure js replace(), but it can be used only for strings. Our google document is array of objects, not strings. So i did a lot of tries and stopped at that code, attached in this message later.
Can't beat: how i can replace only part of what i've found. Capturing groups is very powerful and suitable instrument, but i can't use it for replacement. They didn't work or i can replace whole paragraph, that is unacceptable because of editions history will show full paragraph replace and paragraphs will lose formatting. What if what we searching will be in each and every paragraph, but only one letter must be changed? We will see full document replacement in history and it will be hard to find what really changed.
My first idea was to compare strings, that replace() gives to me with contents of paragraph then compare symbol after symbol and replace what is different, but i understand, that it will work only if we are sure that only one letter changed. But what if replace will delete/add some words, how it can be synced? It will be a lot bigger problem.
All topics that i've found and read triple times didn't helped and didn't moved me from the dead point.
So, is there any ideas how to beat that problem?
function RegExp_test() {
var docParagraphs = DocumentApp.getActiveDocument().getBody().getParagraphs();
var i = 0, text0, text1, test1, re, rt, count;
// equivalent of .asText() ???
text0 = docParagraphs[i].editAsText(); // obj
// equivalent of .editAsText().getText(), .asText().getText()
text1 = docParagraphs[i].getText(); // str
if (text1 !== '') {
re = new RegExp(/(?:([Ww]o)\d(rd))|(?:([Ss]o)\d(me))|(?:([Hh]e)\d(re))/g); // v1
// re = new RegExp(/(?:([Ww]o)\d(rd))/); // v2
count = (text1.match(re) || []).length; // re v1: 7, re v2: 3
if (count) {
test1 = text1.match(re); // v1: ["Wo1rd", "Wo", "rd", , , , , ]
// for (var j = 0; j < count; j++) {
// test1 = text1.match(re)[j];
// }
text0.replaceText("(?:([Ww]o)\\d(rd))", '\1-A-\2'); // GAS func
// #1: \1, \2 etc - didn't work: " -A- word so2me word he3re last."
test1 = text0.getText();
// js func, text2 OK: "Wo1rd word so-B-me word he3re last.", just in memory now
text1 = text1.replace(/(?:([Ss]o)\d(me))/, '$1-B-$2'); // working with str, not obj
// rt OK: "Wo1rd word so-B-me word he-C-re last."
rt = text1.replace(/(?:([Hh]e)\d(re))/, '$1-C-$2');
// #2: we used capturing groups ok, but replaced whole line and lost all formatting
text0.replaceText(".*", rt);
test1 = text0.getText();
}
}
Logger.log('Test finished')
}
Found a solution. It's a primitive enough but it can be a base for a more complex procedure that can fix all occurrences of capture groups, detect them, mix them etc. If someone wants to improve that - you are welcome!
function replaceTextCG(text0, re, to) {
var res, pos_f, pos_l;
var matches = text0.getText().match(re);
var count = (matches || []).length;
to = to.replace(/(\$\d+)/g, ',$1,').replace(/^,/, '').replace(/,$/, '').split(",");
for (var i = 0; i < count; i++) {
res = re.exec(text0.getText())
for (var j = 1; j < res.length - 1; j++) {
pos_f = res.index + res[j].length;
pos_l = re.lastIndex - res[j + 1].length - 1;
text0.deleteText(pos_f, pos_l);
text0.insertText(pos_f, to[1]);
}
}
return count;
}
function RegExp_test() {
var docParagraphs = DocumentApp.getActiveDocument().getBody().getParagraphs();
var i = 0, text0, count;
// equivalent of .asText() ???
text0 = docParagraphs[i].editAsText(); // obj
if (text0.getText() !== '') {
count = replaceTextCG(text0, /(?:([Ww]o)\d(rd))/g, '$1A$2');
count = replaceTextCG(text0, /(?:([Ss]o)\d(me))/g, '$1B$2');
count = replaceTextCG(text0, /(?:([Hh]e)\d(re))/g, '$1C$2');
}
Logger.log('Test finished')
}

Adding two javascript functions(depending on input)

I have put together a calculator what calculates a price, depending on user input. It works fine with one input, but now I have to scale it a little with a second user input. But here's the catch: the user might not want to put anything to the field, so it will be empty. And that's the thing that brakes my code. I could duplicate the calculator function and return the values and add those two together in a third function, but it will not work when there's an empty value.
Just for the sake of it, some trivial HTML code:
//When I only calculate with this user input, its easy
<input type="text" id="rocktext"><br>
// But how to consider this and do the same exact calculations like with the
//first one and add those two result together?
<input type="text" id="rocktext2"><br>
The code in the end should look like:
Take first user input, calculate the price(like in code below)
IF(!!) there is a second user input, calculate the price and add it to
the first one
Am I being a moron to try it with JS or just a moron in the firstplace?
Hope to hear from You, guys!
J.
The initial JS code is as follows:
function priceCalc() {
var inputs = document.getElementById("rocktext").value;
var length = inputs.length;
var accept = 6;
var initPrice = 8;
if (inputs<=accept){
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = initPrice + " dollars";
//I can also return the the value calculated here like so:
//retVal = initPrice;
}
else {
var intLength = parseInt(length, 10);
var lengthGap = intLength - accept;
var totals = lengthGap * 0.8 + initPrice;
var prec = totals.toPrecision(3);
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = prec + " dollars";
// Here also the return clause can be possible with the calculation result like so:
//retVal = prec;
}
// And the final return as an alternative to the innerHTML :
// return retVal;
}
Making it scalable, you can add a class to all the inputs which may be in the function (something like calcInput), so you iterate all of them and if the value isn't empty (and if it's a valid number), you put it in the calculation.
Or you can just verify if the second input is empty, if so, calls functionOne, if not, calls functionTwo:
function twoDifferentWays() {
var valueOne = document.querySelector("#rocktext").value;
var valueTwo = document.querySelector("#rocktext2").value;
if (!!valueTwo && !isNaN(valueTwo)) {
callsFunctionOne(valueOne, valueTwo);
} else {
callsFunctionTwo(valueOne, valueTwo);
}
}

Search HTML5 Datalist by Value and inner text (or some other property)

I am attempting to find a way so that when a user enters text into the data list, they can come across the same entry by course number (E.G. "CS 101") or course name (E.G. "Intro to Computer Science).
Currently, what I have is only searchable by the value field:
<datalist id="tagList">
<option value=""></option>
<option value="CSCI 4950">Senior Software Project</option>
<option value="CSCI 5117">Developing the Interactive Web</option>
<option value="CSCI 5421">Advanced Algorithms</option>
<option value="CSCI 5980">Design Methods for Comp. Sci.</option>
</datalist>
The solution needs to work in the Android Webkit web browser (Phonegap) -- Chrome seems to handle Datalists the same as Android's native browser so if it works in Chrome I should be ok.
It needs to display both the course name and course number to the user
This needs to be generalizable and not hard-coded as I am using AngularJS to actually populate the full list of courses.
What I've tried
https://stackoverflow.com/a/22827978/2831961 -- For some reason, this didn't work.
I've also tried a similar strategy, but with the data-value attribute. That didn't work either. Unless I am responsible for some behind the scenes Javascript work that I am unaware of.
http://jsfiddle.net/rh48cgrj/3/
Here's a fiddle. I put the option values/text into key:value pairs in a javascript object. NOTE: the key is an index number and the value is the option value attribute AND the text. This makes it easier to search them for our text.
var i = 0;
var selectItems = {}
$('#tagList option').each(function() {
var listvalue = $(this).val();
var listtext = $(this).text();
selectItems[i] = listvalue + " " + listtext + ",";
i++;
});
Then I split them into rows that included both value and text.
count = i;
for(i=0; i < count;i++) {
var blockoftext = blockoftext + " " + selectItems[i].toLowerCase() + ",";
}
I then setup a search function that would search those rows to see if any returned a match, and if they did the result was outputted to a div below the search box.
var texttosplit = blockoftext.split(",");
var searchresults;
for(i=0; i < texttosplit.length; i++) {
(texttosplit[i].indexOf(searchvalue.toLowerCase()) != -1) ?
(searchresults = texttosplit[i] + "<br>") : false;
$("#searched").html(searchresults);
}
There's an example for all of the above in the fiddle.
EDIT: The below is the commented code for the loop to check if search text is in the datalist per op request.
for (i = 0; i < texttosplit.length; i++) {
//The above loops through our array of class values and titles
(texttosplit[i].indexOf(searchvalue.toLowerCase()) != -1) ?
// The above determines if our search text is in class title using a ternary operator
// our array of class values and titles is lowercase so we make
//sure our search text is lowercase as well
// if we find a match between the search text and the class title/values perform the following:
(searchresults = texttosplit[i].replace(/\b[a-z]/g, function(letter) {
return letter.toUpperCase();
})
// The above replaces the first char of every word with an uppercase char
.replace("Csci", "CSCI") + "<br>",
// The above finds Csci and changes it to CSCI since all THOSE letters should be uppercase
prevtext = $("#searched").html(),
//get current text of element with id "searched" and place it in prevtext
$("#searched").html(prevtext + searchresults))
//append "searched" by adding it's current text with the new searchresults
:
//if search text is not in the class title return false
false;
}

Losing leading 0s when string converts to array

I have a textInput control that sends .txt value to an array collection. The array collection is a collection of US zip codes so I use a regular expression to ensure I only get digits from the textInput.
private function addSingle(stringLoader:ArrayCollection):ArrayCollection {
arrayString += (txtSingle.text) + '';
var re:RegExp = /\D/;
var newArray:Array = arrayString.split(re);
The US zip codes start at 00501. Following the debugger, after the zip is submitted, the variable 'arrayString' is 00501. But once 'newArray' is assigned a vaule, it removes the first two 0s and leaves me with 501. Is this my regular expression doing something I'm not expecting? Could it be the array changing the value? I wrote a regexp test in javascript.
<script type="text/javascript">
var str="00501";
var patt1=/\D/;
document.write(str.match(patt1));
</script>
and i get null, which leads me to believe the regexp Im using is fine. In the help docs on the split method, I dont see any reference to leading 0s being a problem.
**I have removed the regular expression from my code completely and the same problem is still happening. Which means it is not the regular expression where the problem is coming from.
Running this simplified case:
var arrayString:String = '00501';
var re:RegExp = /\D/;
var newArray:Array = arrayString.split(re);
trace(newArray);
Yields '00501' as expected. There's nothing in the code you've posted that would strip leading zeros. You may want to dig around a bit more.
This smells suspiciously like Number coercion: Number('00501') yields 501. Read through the docs for implicit conversions and check if any pop up in your code.
What about this ?
/^\d+$/
You can also specify exactly 5 numbers like this :
/^\d{5}$/
I recommend just getting the zip codes instead of splitting on non-digits (especially if 'arrayString' might have multiple zip codes):
var newArray:Array = [];
var pattern:RegExp = /(\d+)/g;
var zipObject:Object;
while ((zipObject = pattern.exec(arrayString)) != null)
{
newArray.push(zipObject[1]);
}
for (var i:int = 0; i < newArray.length; i++)
{
trace("zip code " + i + " is: " + newArray[i]);
}