i'm making a chords app and i need the following pattern:
Am F G Am Ab Gdim A#
Hello this is are lyrics just for demonstration hey hey hello
to turn into this:
Am F G Am
Hello this is are lyrics just
Ab Gdim A#
for demonstration hey hey hello
when reaching end of div
i saw a similar question in android, and they suggested using a linear layout to achieve this.
edit: as requested, this is the code i currently have:
<div class="container">
<div class="line">hello this is my first line, it has a lot of words and will wrap to the next line</div>
<div class="line">A B C D E F G H I J K L</div>
</div>
there is no css right now, the classes are empty
Edit: the break should happen at the end of the div, when the word is supposed to wrap, so that the two lines are acting as one line at the break (like in the example)
If you know the amount of characters you want per-line, you can achieve this using javascript: https://codepen.io/schart/pen/OJwdexj
In the solution above, what I'm doing is
Getting the text content of both of the lines
Splitting them both up into chunks of a given length of characters
Creating new HTML using these lists to map them into pairs of lines.
Here is the Javascript, in case the link ever expires:
const charsPerLine = 38;
const computeLine = (line) => {
const regexp = `.{1,${charsPerLine}}`
const newLines = line.match(new RegExp(regexp, "g"));
return newLines;
}
const computeLines = () => {
const [text, notes] = [...document.querySelectorAll(".line-container > .line")].map((line) => line.textContent);
const [textLines, notesLines] = [text, notes].map((line) => computeLine(line));
const maxLines = Math.max(textLines.length, notesLines.length);
let newHTML = "";
for (let i = 0; i < maxLines; i++) {
newHTML += `<div class="line">${textLines[i] ?? ""}</div>`;
newHTML += `<div class="line">${notesLines[i] ?? ""}</div>`;
}
document.querySelector(".line-container").innerHTML = newHTML;
}
computeLines();
This solution assumes that you have all the text in the first .line and all the notes in the second .line
Related
I have a 20 line script, and I want to make sure that each paragraph is indented exactly once.
function myFunction() {
/*
This function turns the document's format into standard MLA.
*/
var body = DocumentApp.getActiveDocument().getBody();
body.setFontSize(12); // Set the font size of the contents of the documents to 9
body.setForegroundColor('#000000');
body.setFontFamily("Times New Roman");
// Loops through paragraphs in body and sets each to double spaced
var paragraphs = body.getParagraphs();
for (var i = 3; i < paragraphs.length; i++) { // Starts at 3 to exclude first 4 developer-made paragraphs
var paragraph = paragraphs[i];
paragraph.setLineSpacing(2);
// Left align the first cell.
paragraph.setAlignment(DocumentApp.HorizontalAlignment.LEFT);
// One indent
paragraph.editAsText().insertText(0, "\t"); // Adds one tab every time
}
var bodyText = body.editAsText();
bodyText.insertText(0, 'February 3, 1976\nMrs. Smith\nYour Name Here\nSocial Studies\n');
bodyText.setBold(false);
}
The code I have tried doesn't work. But my expected results are that for every paragraph in the for loop in myFunction(), there are exactly 4 spaces before the first word in each paragraph.
Here is a sample: https://docs.google.com/document/d/1sMztzhOehzheRdqumC6PLnvk4qJgUCSE0irjTZ0FjTQ/edit?usp=sharing
If the user uses Autoformat, but already has the paragraphs indented...
Update
I have investigated use of the Paragraph.setIndentFirstLine() method. When I set it to four, it sets it to 1 space. Now I realize this is because points and spaces are not the same thing. What number do I need to multiply by to get four spaces in points?
Let us consider a few basic identing operations: manual and by script.
The following image shows how to indent current paragraph (cursor stays inside this one).
Please note, the units are centimetres. Also note, that the paragraph does not include leading spaces or tabs, we have no need of them.
Suppose we would like to get the indent values in the script and apply them to the next paragraph. Look at the code below:
function myFunction() {
var ps = DocumentApp.getActiveDocument().getBody().getParagraphs();
// We work with the 5-th and 6-th paragraphs indeed
var iFirst = ps[5].getIndentFirstLine();
var iStart = ps[5].getIndentStart();
var iEnd = ps[5].getIndentEnd();
Logger.log([iFirst, iStart, iEnd]);
ps[6].setIndentFirstLine(iFirst);
ps[6].setIndentStart(iStart);
ps[6].setIndentEnd(iEnd);
}
If you run and look at the log, you will see something like this: [92.69291338582678, 64.34645669291339, 14.173228346456694]. No surprise, we have typographic points instead of centimetres. (1cm=28.3465pt) So we can measure and modify any paragraph indent values precisely.
Addition
For some reasons you might want to control spaces number at the beginning of the paragraph. It is also possible by scripting, but it has no effect on the paragraph's "left" or "right" indents.
Sample code below is for similar task: count leading spaces number of the 5-th paragraph and make the same number of spaces at the beginning of the next one.
function mySpaces() {
var ps = DocumentApp.getActiveDocument().getBody().getParagraphs();
// We work with the 5-th and 6-th paragraphs indeed
var spacesCount = getLeadingSpacesCount(ps[5]);
Logger.log(spacesCount);
var diff = getLeadingSpacesCount(ps[6]) - spacesCount;
if (diff > 0) {
ps[6].editAsText().deleteText(0, diff - 1);
} else if (diff < 0) {
var s = Array(1 - diff).join(' ');
ps[6].editAsText().insertText(0, s);
}
}
function getLeadingSpacesCount(p) {
var found = p.findText("^ +");
return found ? found.getEndOffsetInclusive() + 1 : 0;
}
We have used methods deleteText() and insertText() of the class Text for proper corrections and findText() to locate the spaces if any. Note, the last method argument is a string, representing a regular expression. It matches "all leading spaces", if they exist. See more details about regular expression syntax.
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);
})
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')
}
I have a column on my kendoUi grid that has anchor tags for the entire column including the footer, here is my code for that:
columns.Bound(p => p.NonFlagged).Title("Non Flagged").Width(100)
.ClientTemplate(
"<a onclick='ShowPatientGapDetailsModal(" + "#=MeasureId#" + ")' href='\\#'>#=NonFlagged#</a>")
.ClientFooterTemplate("<a onclick='ShowPatientGapDetailsModal()' href='\\#'>#=sum#</a>");
It works fine for all the rows except the footer, which shows the full html anchor tag as you can see here:
Has anyone seen this before or have any suggestions?
it is because grid exports only data. Not templates. For usage templates into excel export you have to use ExcelExport event.
Here is small code snippet which I hope helps you.
Anyway I didn't work with footers and excel yet but I am sure there will be same rules like with normal data. Probably it will not work as you need but can kick you right direction.
I have met this behaviour when I had checkboxes in cells or datefields etc.
excelExport: function (e) {
var sheet = e.workbook.sheets[0];
var data = [];
for (var i = 1; i < sheet.rows.length; i++) {
var dataItem = {
FieldWithMyTemplate: e.data[i].FieldWithMyTemplate, // In e.data are data from row in grid
};
var row = sheet.rows[i];
for (var j = 0; j < row.cells.length; j++) {
var template = kendo.template(this.columns[j].template);
row.cells[j].value = template(dataItem);
}
}
};
Edit: Forgot to mention that in e.Data at first index ([0]) are data from headers. So on the last one will be your footer data.
I have a file text more than 1 000 000 lines that begins by the character C and other one by M
Example:
C9203007870000000000000006339912610971240095400111200469300000 16122011AMI 00000100010000315 080
C9203007870000000000000006339912610971240095400111200469300000 09122011B 590001000100000270016092100
M920300787000000000000000633991261097124009540011120046930000031122011JVJF004 10 N
M920300787000000000000000633991261097124009540011120046930000009122011DEQP003 10 N
M920300787000000000000000633991261097124009540011120046930000012122011ACQK001 10Z N
C9203007870000000000000006339912610971240095400111200469300000 24122011AMI 00000100010000315 080
C9203007870000000000000006339912610971240095400111200469300000 24122011AMI 00000100010000315 080
I want to put in my array only the lines who begins with the character M
How I can add in my split: var pattern:RegExp = /^M/;
var mFileReference:FileReference;
var mArray:Array = new Array();
function onFileLoaded(event:Event):void
{
mFileReference = event.target as FileReference;
data = mFileReference["data"];
mArray = (data.toString()).split("\n");
}
I don’t want to pass by the loop ‘for’ its take a lot of time and resources
I want to add /^M/ to my split is it possible?
for each (var s:String in mArray)
{
if (pattern.test(s)) {
values.push(s);
}
}
Thanks everybody.
Try this regular expression:
/^M.*/gm
This should match all lines that begin with M and nothing else.
It uses the g flag to match all cases of the expression in the string, and it uses m for multiline mode, so ^ and $ will match the beginning/end of lines instead of the beginning/end of the string.
You can get get your array like this:
mArray = data.toString().match(/^M.*/gm);