I have variable which is negative numbers after $ sign (actually it shows currency with currency sign). Please tell me how to show minus currency in brackets with currency sign. I mean to say how to change var val=($125,220,328.00)
My code is looks like this
function addCommas(nStr)
{
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
function netAmount(){
var net_amount =0;
$('#productList tr:gt(1)').each(function() {
var row_index= $(this).index();
var qty= $('#productList tr:eq('+row_index+') td input[name="quantity"]').val().replace( /[^0-9\.]/g, '' );
var price= $('#productList tr:eq('+row_index+') td input[name="purchase_price"]').val().replace( /[^0-9\.]/g, '' );
net_amount+= +(parseFloat(qty*price).toFixed(2));
$('input[name="net_ammount"]').val('$'+ addCommas(parseFloat(net_amount).toFixed(2)));
});
}
Now i want if net_amount is looks like -123225.32 then it show in input[name="net_ammount"] as ($123,225.32)
Here's my working attempt:
function addCommas(val2) {
val2 = val2.toString(); // cast to a string
// index of minus sign
var negative = val2.indexOf('-');
// org = original index of dot, make val an array; i should be above index of minus + 1; decrease i
for (var i = org = val2.indexOf('.'), val2 = val2.split(""); i > negative + 1; i--) {
// i difference between org and i is multiple of 3 and at the current index is a number
if ((org - i) % 3 == 0 &&
/[0-9]/.test(val2[org - i])) {
// insert a `,` and decrease i
val2.splice(i--, 0, ',');
}
}
val2 = val2.join("");
if(parseInt(val2, 10) >= 0)
return '$' + val2;
else
return '($' + val2 + ')';
}
alert(addCommas(123225.32)); // $123,225.32
alert(addCommas(-123225.32)); // ($123,225.32)
function remCommas(val){
var pre = '';
if(val.indexOf("(") > -1){
pre = "$-";
val = val.replace(/\(\$/, "").replace(/\)/, "");
}
val = pre + val;
return val;
}
alert(remCommas('$123,225.32')); // $123,225.32
alert(remCommas('($123,225.32)')); // $-123,225.32
Related
I have a function that wraps textboxes in FabricJS so that they don't become too wide, (it is automatically line breaking when the the maximum width is reached). However it is causing the text cursor to get pushed behind by 1 character every time it adds a new line.
Look at this gif to fully see the problem in play a gif
I am using the following function to automatically line break the text box. To give some context, it checks if the length of a textLine exceeds the maxWidth, and if it is the case with the last word included but doesn't exceed if the last word is not included, then it adds a new line by entering \n and somewhere here it causes the problem.
function wrapCanvasText(t, canvas, maxW, maxH) {
let initialFormatted = t.text
if (typeof maxH === "undefined") {
maxH = 0;
}
var words = t.text.split(" ")
var formatted = '';
// clear newlines
var sansBreaks = t.text.replace(/(\r\n|\n|\r)/gm, "");
// calc line height
var lineHeight = new fabric.Text(sansBreaks, {
fontFamily: t.fontFamily,
fontSize: t.fontSize
}).height;
// adjust for vertical offset
var maxHAdjusted = maxH > 0 ? maxH - lineHeight : 0;
var context = canvas.getContext("2d");
context.font = t.fontSize + "px " + t.fontFamily;
var currentLine = "";
var breakLineCount = 0;
for (var n = 0; n < words.length; n++) {
console.log(words[n])
var isNewLine = currentLine == " ";
var testOverlap = currentLine + ' ' + words[n] + ' ';
// are we over width?
var w = context.measureText(testOverlap).width;
if (w < maxW) { // if not, keep adding words
currentLine += words[n] + ' ';
formatted += words[n] += ' ';
} else {
// if this hits, we got a word that need to be hypenated
if (isNewLine) {
var wordOverlap = "";
// test word length until its over maxW
for (var i = 0; i < words[n].length; ++i) {
wordOverlap += words[n].charAt(i);
var withHypeh = wordOverlap + "-";
if (context.measureText(withHypeh).width >= maxW) {
// add hyphen when splitting a word
withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + "-";
// update current word with remainder
words[n] = words[n].substr(wordOverlap.length - 1, words[n].length);
formatted += withHypeh; // add hypenated word
break;
}
}
}
n--; // restart cycle
if (words[n+1] !== '') {
formatted += '\n';
breakLineCount++;
}
currentLine = "";
}
if (maxHAdjusted > 0 && (breakLineCount * lineHeight) > maxHAdjusted) {
// add ... at the end indicating text was cutoff
formatted = formatted.substr(0, formatted.length - 3) + "...\n";
break;
}
}
// get rid of empy newline at the end
formatted = formatted.substr(0, formatted.length - 1);
return formatted;
}
You can try out this snippet it is an approximate version of what I have, most importantly, it does have the same cursor problem. To try out the problem, edit the text directly in the canvas after initialization.
var canvas = new fabric.Canvas('c');
canvas.backgroundColor = "#F5F5F5";
var textArea = document.getElementById('addNote');
function checkForChange() {
var activeObject = canvas.getActiveObject();
let formatted1 = wrapCanvasText(activeObject, canvas, 400, 2000);
activeObject.text = formatted1;
}
function wrapCanvasText(t, canvas, maxW, maxH) {
let initialFormatted = t.text
if (typeof maxH === "undefined") {
maxH = 0;
}
var words = t.text.split(" ")
var formatted = '';
// clear newlines
var sansBreaks = t.text.replace(/(\r\n|\n|\r)/gm, "");
// calc line height
var lineHeight = new fabric.Textbox(sansBreaks, {
fontFamily: t.fontFamily,
fontSize: t.fontSize
}).height;
// adjust for vertical offset
var maxHAdjusted = maxH > 0 ? maxH - lineHeight : 0;
var context = canvas.getContext("2d");
context.font = t.fontSize + "px " + t.fontFamily;
var currentLine = "";
var breakLineCount = 0;
for (var n = 0; n < words.length; n++) {
console.log(words[n])
var isNewLine = currentLine == " ";
var testOverlap = currentLine + ' ' + words[n] + ' ';
// are we over width?
var w = context.measureText(testOverlap).width;
if (w < maxW) { // if not, keep adding words
currentLine += words[n] + ' ';
formatted += words[n] += ' ';
} else {
// if this hits, we got a word that need to be hypenated
if (isNewLine) {
var wordOverlap = "";
// test word length until its over maxW
for (var i = 0; i < words[n].length; ++i) {
wordOverlap += words[n].charAt(i);
var withHypeh = wordOverlap + "-";
if (context.measureText(withHypeh).width >= maxW) {
// add hyphen when splitting a word
withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + "-";
// update current word with remainder
words[n] = words[n].substr(wordOverlap.length - 1, words[n].length);
formatted += withHypeh; // add hypenated word
break;
}
}
}
n--; // restart cycle
if (words[n + 1] !== '') {
formatted += '\n';
breakLineCount++;
}
currentLine = "";
}
if (maxHAdjusted > 0 && (breakLineCount * lineHeight) > maxHAdjusted) {
// add ... at the end indicating text was cutoff
formatted = formatted.substr(0, formatted.length - 3) + "...\n";
break;
}
}
// get rid of empy newline at the end
formatted = formatted.substr(0, formatted.length - 1);
return formatted;
}
$("#addNote").keyup(function(e) {
var activeObject = canvas.getActiveObject();
if (activeObject && activeObject.type == 'textbox') {
activeObject.text = textArea.value
let formatted1 = wrapCanvasText(activeObject, canvas, 400, 2000);
activeObject.text = formatted1;
while (activeObject.textLines.length > 1 && canvas.getWidth() * 0.8 >= activeObject.width) {
activeObject.set({
width: activeObject.getScaledWidth() + 1
})
}
canvas.renderAll();
} else {
var textSample = new fabric.Textbox(textArea.value, {});
textSample.left = 0
textSample.splitByGrapheme = true
textSample.lockRotation = true
textSample.editable = true
textSample.perPixelTargetFind = false
textSample.hasControls = true
textSample.width = canvas.getWidth() * 0.8
textSample.height = canvas.getHeight() * 0.8
textSample.maxWidth = canvas.getWidth() * 0.8
textSample.maxHeight = canvas.getHeight() * 3
canvas.add(textSample);
canvas.setActiveObject(textSample);
canvas.renderAll();
}
canvas.on('text:changed', checkForChange)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>
<textarea id="addNote"></textarea>
<canvas id="c" width="400" height="400"></canvas>
I'm trying to return every value from the array allArtistsArray, which gets values from a spreadsheet, and have them display as an unordered list with buttonTemplate first, and then every value in the spreadsheet after it.
The problem I'm having is that only the first value from the spreadsheet is being returned and displayed on the web app. How do I get every value to display after buttonTemplate?
What's being displayed is:
* buttonTemplate
or
* value 1 from spreadsheet
What I'm trying to get displayed is:
* buttonTemplate
* value 1 from spreadsheet
* value 2 from spreadsheet
* value 3 from spreadsheet
* etc
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= getContent("js") ?>
<?!= getContent("css") ?>
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Abel">
</head>
<body>
<div id="artistTabs">
<ul id="artistList">
<?!= createArtistList(); ?>
</ul>
</div>
</body>
</html>
code.gs
var ss = SpreadsheetApp.openById('id');
var sheet = ss.getSheets()[0];
function doGet()
{
return HtmlService.createTemplateFromFile('index').evaluate();
}
function getContent(filename)
{
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function createArtistList()
{
var buttonStartingRow = 2;
var buttonStartingColumn = 1;
var buttonCell = sheet.getRange(buttonStartingRow, buttonStartingColumn).getValue();
var x = '<li><a onClick="addArtist(); return false;" href="">';
var y = buttonCell;
var z = '</a></li>';
var buttonTemplate = x + y + z;
//return buttonTemplate;
var startingRow = 2;
var startingColumn = 1;
var howManyRows = sheet.getLastRow() - 1;
var howManyColumns = 1;
var allArtistsArray = sheet.getRange(startingRow, startingColumn, howManyRows, howManyColumns).getValues(); //get every name in 1st column after second row
//allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
//allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
//Logger.log(allArtistsArray);
for (i = 0; i < allArtistsArray.length; i++)
{
allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
if (allArtistsArray == '')
{
Logger.log("array = blank");
break; //leave for loop and only return buttonTemplate ???
}
else
{
var x1 = '<li><a onClick="test(); return false;" href="">';
var z1 = '</a></li>';
var _1 = allArtistsArray[i];
var _2 = x1 + _1 + z1;
Logger.log(_2);
}
}
Logger.log(allArtistsArray);
return buttonTemplate;
}
Looks to me like you should be changing the value of buttonTemplate IN your for loop if that is the result you want. For example: buttonTemplate += _2 (or whatever you want appended it is unclear from your example).
EDIT
Without a snippet to play around with it's hard to see if this works but here is a better example of what I meant:
function createArtistList()
{
var buttonStartingRow = 2;
var buttonStartingColumn = 1;
var buttonCell = sheet.getRange(buttonStartingRow, buttonStartingColumn).getValue();
var x = '<li><a onClick="addArtist(); return false;" href="">';
var y = buttonCell;
var z = '</a></li>';
var buttonTemplate = x + y + z;
var artistsOutput = '';
//return buttonTemplate;
var startingRow = 2;
var startingColumn = 1;
var howManyRows = sheet.getLastRow() - 1;
var howManyColumns = 1;
var allArtistsArray = sheet.getRange(startingRow, startingColumn, howManyRows, howManyColumns).getValues(); //get every name in 1st column after second row
//allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
//allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
//Logger.log(allArtistsArray);
for (i = 0; i < allArtistsArray.length; i++)
{
allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
if (allArtistsArray == '')
{
Logger.log("array = blank");
break; //leave for loop and only return buttonTemplate ???
}
else
{
var x1 = '<li><a onClick="test(); return false;" href="">';
var z1 = '</a></li>';
var _1 = allArtistsArray[i];
if (_1 != null)
{
var _2 = x1 + _1 + z1;
artistsOutput += _2;
Logger.log(_2);
} else {
Logger.log('The ' + i + 'th element was null for some reason');
}
}
}
Logger.log(allArtistsArray);
return buttonTemplate + artistsOutput;
}
I am trying to format an <input> box using javascript / jquery.
The Goal - As the user types, add hyphens automatically after every third character.
123123123 becomes 123-123-123
I have a working code, but it is super slow and clunky. I am looking for recommendations on how to improve the code
$('#serial').keyup(function(){
$(this).val( $(this).val().trim() );
var str = $(this).val();
var newStr = str.replace(/-/g, "");
var valuesArray = newStr.split("");
var newVal = "";
while ( i = valuesArray.shift() ){
if(newVal.length === 3){
newVal += "-";
} else if (newVal.length === 7){
newVal += "-";
}
newVal += i;
}
$(this).val(newVal);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<label for="serial">Type something magical</label>
<input type="text" id="serial" name="serial">
Use input event istead of keyup it's very useful to track input fields changes :
$('#serial').on('input', function(){
NOTE : The code seems slow because keyup won't fire until you release the key, but you can type the next character before releasing the first.
Hope this helps.
Update :
You don't need any loop here, you can use substr to cut your string and insert the separator - and use maxlength to define the max number of charaters you want to contain your serial :
$('#serial').on('input', function()
{
var input_value = $(this).val().trim().replace(/-/g, "");
if(input_value.length > 3){
input_value = input_value.substr(0, 3) + '-' + input_value.substr(3);
}
if (input_value.length > 7){
input_value = input_value.substr(0, 7) + '-' + input_value.substr(7);
}
$(this).val(input_value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="serial" name="serial" maxlength="11">
try this code, replaced inefficient regex with substring
$('#serial').input(function(){
$(this).val( $(this).val().trim() );
var str = $(this).val().trim().split( "-" ).join("");
var output = "";
while ( str.length > 3 )
{
output += str.substring(0,3) + "-";
str = str.substring(3);
}
output += str;
$(this).val(output);
});
A little further optimization
$('#serial').on('input', function() {
var str = $(this).val().trim();
var i = 3;
while (i < str.length) {
if (str.charAt(i) == '-') {
i += 4;
} else {
str = str.slice(0, i) + '-' + str.charAt(str.length-1);
}
}
$(this).val(str);
});
jsfiddle https://jsfiddle.net/h5hdvcwu/1/
Basically what I want to do is create list of characters with format like excel column name.
for example :
a,b,c,d,.....,z,aa,ab,ac,....,yz
in php you can just looping it with this code:
for($char = "A"; $char <= "Z"; $char++)
{
echo $char . "\n";
}
but when I try it in javascript :
var i3;
var text3 = "";
for(i3 = "A"; i3 <= "Z"; i3++)
{
text3 += i3 + ", ";
}
document.getElementById("pId").innerHTML = text3;
It doesn't work for me. Are there some errors in my code? Or that PHP logic doesn't work in JS? If you know how to make one please tell me, thanks.
In javacript the incrementor operator will return NaN when called on a string value.
You can use ascii code based implementation like
var i3, i4;
var text3 = "";
for (i3 = 0; i3 < 26; i3++) {
text3 += String.fromCharCode(97 + i3) + ", ";
}
for (i3 = 0; i3 < 26; i3++) {
for (i4 = 0; i4 < 26; i4++) {
text3 += String.fromCharCode(97 + i3) + String.fromCharCode(97 + i4) + ", ";
}
}
document.getElementById("pId").innerHTML = text3;
<span id="pId"></span>
Short is beautiful!
var nextChar = c=>c?String.fromCharCode(c.charCodeAt(0)+1):'A';
var nextCol = s=>s.replace(/([^Z]?)(Z*)$/, (_,a,z)=>nextChar(a) + z.replace(/Z/g,'A'));
//test:
nextCol(''); //A
nextCol('A'); //B
nextCol('Z'); //AA
nextCol('AA'); //AB
nextCol('XYZ'); //XZA
nextCol('ZZZZ'); //AAAAA
//output: A,B,C,...,ZZ
for(var i=0, s=''; i<702; i++){
s = nextCol(s);
console.log(s);
}
//output: A,B,C,...,ZZZZ
for(var i=0, s=''; i<475254; i++){
s = nextCol(s);
console.log(s);
}
I worked on a function called next, which provides the adjacent right cell.
function next(currentCell) {
let regex = /[A-Z]/g;
let numberRegex = /[0-9]/g;
let chars = currentCell.match(regex);
let nums = currentCell.match(numberRegex);
let flag = true;
let x = 1;
while (flag) {
if (chars[chars.length - x] === 'Z') {
if ((chars.length - x) === 0) {
chars[chars.length - x] = 'A';
chars.unshift('A');
flag = false;
} else {
chars[chars.length - x] = 'A';
x++;
}
} else {
chars[chars.length - x] = String.fromCharCode(chars[chars.length - x].charCodeAt(0) + 1);
flag = false;
}
}
return chars.join("") + nums.join("");
}
next('A1') // returns 'B1'
next('ZZ90') // returns 'AAA90'
Please try the below code to get done with javascript
var i3;
var text3 = "";
var c;
for(i3 = 65; 90 >= i3; i3++)
{
c = String.fromCharCode(i3);
text3 += c + ", ";
}
document.getElementById("pId").innerHTML = text3;
I followed a tutorial/modified the code to get a javascript tag cloud working in IBM Cognos (BI software). The tag cloud works fine in FireFox but in Internet Explorer I get the error:
"Message: '1' is null or not an object"
The line of code where this is present is 225 which is:
var B = b[1].toLowerCase();
I have tried many different solutions that I have seen but have been unable to get this working correctly, the rest of the code is as follows:
<script>
// JavaScript Document
// ====================================
// params that might need changin.
// DON'T forget to include a drill url in the href section below (see ###) if you want this report to be drillable
var delimit = "|";
var subdelimit = "[]"; // change this as needed (ex: Smith, Michael[]$500,000.00|)
var labelColumnNumber = 0; // first column is 0
var valueColumnNumber = 1;
var columnCount = 2; // how many columns are there in the list?
// ====================================
/*
function formatCurrency(num) {
num = num.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+ num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}
*/
function formatCurrency(num) {
num = num.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+ num.substring(num.length-(4*i+3));
return ( num );
}
function filterNum(str) {
re = /\$|,|#|#|~|`|\%|\*|\^|\&|\(|\)|\+|\=|\[|\-|\_|\]|\[|\}|\{|\;|\:|\'|\"|\<|\>|\?|\||\\|\!|\$|/g;
// remove special characters like "$" and "," etc...
return str.replace(re, "");
}
table = document.getElementById("dg");
if ( table.style.visibility != 'hidden'){ //only for visible
/*alert('Visible');*/
tags = document.getElementById("dg").getElementsByTagName("SPAN");
txt = "";
var newText = "a";
for (var i=columnCount; i<tags.length; i++) {
/*
valu = filterNum(tags[i+valueColumnNumber].innerHTML);
txt += valu;
txt += subdelimit+tags[i+labelColumnNumber].innerHTML+delimit;
i = i+columnCount;
*/
if(i%2!=0){
var newValue = filterNum(tags[i].innerHTML);
}else var newName =tags[i].innerHTML;
if((i>2) & (i%2!=0)){
newText = newText+newValue+subdelimit+newName+delimit;
if(typeof newText != 'undefined'){
txt = newText;
txt = txt.substr(9);
/* alert(txt);*/
}
}
}
}/*else alert ('Hidden');*/
function getFontSize(min,max,val) {
return Math.round((150.0*(1.0+(1.5*val-max/2)/max)));
}
function generateCloud(txt) {
//var txt = "48.1[]Google|28.1[]Yahoo!|10.5[]Live/MSN|4.9[]Ask|5[]AOL";
var logarithmic = false;
var lines = txt.split(delimit);
var min = 10000000000;
var max = 0;
for(var i=0;i<lines.length;i++) {
var line = lines[i];
var data = line.split(subdelimit);
if(data.length != 2) {
lines.splice(i,1);
continue;
}
data[0] = parseFloat(data[0]);
lines[i] = data;
if(data[0] > max)
max = data[0];
if(data[0] < min)
min = data[0];
}lines.sort(function (a,b) {
var A = a[1].toLowerCase();
var B = b[1].toLowerCase();
return A>B ? 1 : (A<B ? -1 : 0);
});
var html = "<style type='text/css'>#jscloud a:hover { text-decoration: underline; }</style> <div id='jscloud'>";
if(logarithmic) {
max = Math.log(max);
min = Math.log(min);
}
for(var i=0;i<lines.length;i++) {
var val = lines[i][0];
if(logarithmic) val = Math.log(val);
var fsize = getFontSize(min,max,val);
dollar = formatCurrency(lines[i][0]);
html += " <a href='###Some drillthrough url which includes the param "+lines[i][1]+"' style='font-size:"+fsize+"%;' title='"+dollar+"'>"+lines[i][1]+"</a> ";
}
html += "</div>";
var cloud = document.getElementById("cloud");
cloud.innerHTML = html;
var cloudhtml = document.getElementById("cloudhtml");
cloudhtml.value = html;
}
function setClass(layer,cls) {
layer.setAttribute("class",cls);
layer.setAttribute("className",cls);
}
function show(display) {
var cloud = document.getElementById("cloud");
var cloudhtml = document.getElementById("cloudhtml");if(display == "cloud") {
setClass(cloud,"visible");
setClass(cloudhtml,"hidden");
}
else if(display == "html") {
setClass(cloud,"hidden");
setClass(cloudhtml,"visible");
}
}
generateCloud(txt);
</script>
Any help or explanations is much appreciated
Sorry, I'm not seeing where a[] and b[] are defined, is this done elsewhere? Firefox and IE may be responding differently to the problem of an undefined array.