Multiple-page printing from datagrid - actionscript-3

From this tutorial i've got a good result printing , and this tutorial on how to print multiple pages from html, i'm trying to do the same with a Datagrid.
my problem is when the number of rows exceed the height of Datagrid so i tried to break it down to several pages, this is my code:
protected function button3_clickHandler(event:MouseEvent):void
{
var success:Boolean = printJob.start2(disablePageRange.selected ? this.printUIOptions : null, false);
var pjo:PrintJobOptions = new PrintJobOptions;
if (methodBitmap.selected){
pjo.printMethod = PrintMethod.BITMAP;
}
else if (methodVector.selected){
pjo.printMethod = PrintMethod.VECTOR;
}
else{
pjo.printMethod = PrintMethod.AUTO;
}
if (printJob.maxPixelsPerInch > 600){
pjo.pixelsPerInch = 600;
}
updateForm();
updateThePage();
updateTheWindow();
//--------------------------------------
var b:int = 0;
var H:int = myDataGrid.rowHeight *2;
for each (var item:Object in meme as ArrayCollection ){
if (H > myDataGrid.height){
myDataGrid.dataProvider = arlst;
printJob.addPage(thePrintableArea, null, pjo);
arlst.removeAll();
H = myDataGrid.rowHeight *2;
b++;
//Alert.show(b.toString());
}else{
arlst.addItem(item);
H += myDataGrid.rowHeight;
}
}
printJob.send();
}
The result: i get the first page but the rest are just blank Datagrid:

This answers: http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7c7e.html
Summary:
create external Itemrenderer and populate the data to it.

Related

Google Apps Script. Get all links from document

Hi all) I need to get all links from google document. I found that general approach:
function getAllLinks(element) {
var links = [];
element = element || DocumentApp.getActiveDocument().getBody();
if (element.getType() === DocumentApp.ElementType.TEXT) {
var textObj = element.editAsText();
var text = element.getText();
Logger.log("text " + text);
var inUrl = false;
for (var ch=0; ch < text.length; ch++) {
var url = textObj.getLinkUrl(ch);
if (url != null) {
if (!inUrl) {
// We are now!
inUrl = true;
var curUrl = {};
curUrl.element = element;
curUrl.url = String( url ); // grab a copy
curUrl.startOffset = ch;
}
else {
curUrl.endOffsetInclusive = ch;
}
}
else {
if (inUrl) {
// Not any more, we're not.
inUrl = false;
links.push(curUrl); // add to links
curUrl = {};
}
}
}
}
else {
var numChildren = element.getNumChildren();
for (var i=0; i<numChildren; i++) {
links = links.concat(getAllLinks(element.getChild(i)));
}
}
Logger.log(links);
}
It works perfectly fine if i, for example, type url in text, but if add link via menu ("Insert" -> "Link") it doesn't work, function getLinkUrl() returns null. Documentation contains info about Link class, i thought all links represented by it, but don't understand why i can't get link inserted via menu.
I thought maybe i can use some regular expression on text of document element, but if i add link via menu item i can specify custom label for link, which may not contain url in it.
Have anyone faced this scenario? What i missed?

How to use external data plot a multi lineseries chart

I am using amcharts4 plugin to plot a multi-lineseries graph.
But the plotted points do not locate at the right position (Blue dot at the edge of y-axe)
Here is the output chart that I get. (pls see the attached above)
Not sure what had done wrong with the following codes. Hope someone can help me out.
Thanks in advance!
var chart = am4core.create("chartdiv", am4charts.XYChart);
//Create axes
var categoryAxis = chart.xAxes.push(new
am4charts.CategoryAxis()); categoryAxis.dataFields.category = "date";
categoryAxis.title.text = "Month-Year";
categoryAxis.title.fontWeight = "bold";
/* Create value axis */
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.title.text = "Total Sales ($)";
valueAxis.title.fontWeight = "bold";
/* Add data */
var ds = new am4core.DataSource();
ds.url = window.location.origin+"/home/salesVolumnVersusPeriod"; //Sample of external JSON DATA = [{"date":"02-2020","FS":6288, 'IO':2342}]
ds.events.on("done", function(ev) {
chart.config = ev.data;
var u = ev.data; var data =
ev.target.data[0]; var datakey = Object.keys(data);
var text = '';
for (var i = 1; i < datakey.length; i++) {
addSeries(datakey[i], u);
text += datakey[i]+' : {'+datakey[i]+'}'+"\n";
}
$('#chartdiv').append('<div id="test">'+text+'</div>');
});
ds.load();
/* Create series */
function addSeries(b, data) {
// Create series
var series = new am4charts.LineSeries();
series.data = data;
series.dataFields.valueY = b;
series.dataFields.categoryX = "date";
series.name = b;
series.strokeWidth = 3;
series.tensionX = 0.7;
series.bullets.push(new am4charts.CircleBullet());
series = chart.series.push(series);
series.events.on("hidden", updateTooltipText);
series.events.on("shown", updateTooltipText);
}
function getToolstipItemValue(text) {
return `[bold]Date {categoryX}[/]
---- `+text;
}
/* Set up tooltip attachment to other series whenever series is hidden */
function updateTooltipText() {
var added = false;
tooltipText = $('#test').text();
chart.series.each(function(series)
{
if (series.visible && !added) {
series.tooltipText = getToolstipItemValue(tooltipText);
added = true;
}
else {
series.tooltipText = "";
}
});
}
/* Add legend */
chart.legend = new am4charts.Legend();
/* Create a cursor */
chart.cursor = new am4charts.XYCursor();
Finally knew what is wrong. It should use chart.data instead of chart.config.
Now the graph works. Hope this could help you too. Cheers!
chart.config = ev.data;

Can Google apps script be used to randomize page order on Google forms?

Update #2: Okay, I'm pretty sure my error in update #1 was because of indexing out of bounds over the array (I'm still not used to JS indexing at 0). But here is the new problem... if I write out the different combinations of the loop manually, setting the page index to 1 in moveItem() like so:
newForm.moveItem(itemsArray[0][0], 1);
newForm.moveItem(itemsArray[0][1], 1);
newForm.moveItem(itemsArray[0][2], 1);
newForm.moveItem(itemsArray[1][0], 1);
newForm.moveItem(itemsArray[1][1], 1);
newForm.moveItem(itemsArray[1][2], 1);
newForm.moveItem(itemsArray[2][0], 1);
...
...I don't get any errors but the items end up on different pages! What is going on?
Update #1:: Using Sandy Good's answer as well as a script I found at this WordPress blog, I have managed to get closer to what I needed. I believe Sandy Good misinterpreted what I wanted to do because I wasn't specific enough in my question.
I would like to:
Get all items from a page (section header, images, question etc)
Put them into an array
Do this for all pages, adding these arrays to an array (i.e: [[all items from page 1][all items from page 2][all items from page 3]...])
Shuffle the elements of this array
Repopulate a new form with each element of this array. In this way, page order will be randomized.
My JavaScript skills are poor (this is the first time I've used it). There is a step that produces null entries and I don't know why... I had to remove them manually. I am not able to complete step 5 as I get the following error:
Cannot convert Item,Item,Item to (class).
"Item,Item,Item" is the array element containing all the items from a particular page. So it seems that I can't add three items to a page at a time? Or is something else going on here?
Here is my code:
function shuffleForms() {
var itemsArray,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,shuffle, sections;
// Copy template form by ID, set a new name
newFormFile = DriveApp.getFileById('1prfcl-RhaD4gn0b2oP4sbcKaRcZT5XoCAQCbLm1PR7I')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
// Get ID of new form and open it
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
// Initialize array to put IDs in
itemsArray = [];
function getPageItems(thisPageNum) {
Logger.log("Getting items for page number: " + thisPageNum );
var thisPageItems = []; // Used for result
var thisPageBreakIndex = getPageItem(thisPageNum).getIndex();
Logger.log( "This is index num : " + thisPageBreakIndex );
// Get all items from page
var allItems = newForm.getItems();
thisPageItems.push(allItems[thisPageBreakIndex]);
Logger.log( "Added pagebreak item: " + allItems[thisPageBreakIndex].getIndex() );
for( var i = thisPageBreakIndex+1; ( i < allItems.length ) && ( allItems[i].getType() != FormApp.ItemType.PAGE_BREAK ); ++i ) {
thisPageItems.push(allItems[i]);
Logger.log( "Added non-pagebreak item: " + allItems[i].getIndex() );
}
return thisPageItems;
}
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
Logger.log('shuffle ran')
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function shuffleAndMove() {
// Get page items for all pages into an array
for(i = 2; i <= 5; i++) {
itemsArray[i] = getPageItems(i);
}
// Removes null values from array
itemsArray = itemsArray.filter(function(x){return x});
// Shuffle page items
itemsArray = shuffle(itemsArray);
// Move page items to the new form
for(i = 2; i <= 5; ++i) {
newForm.moveItem(itemsArray[i], i);
}
}
shuffleAndMove();
}
Original post: I have used Google forms to create a questionnaire. For my purposes, each question needs to be on a separate page but I need the pages to be randomized. A quick Google search shows this feature has not been added yet.
I see that the Form class in the Google apps script has a number of methods that alter/give access to various properties of Google Forms. Since I do not know Javascript and am not too familiar with Google apps/API I would like to know if what I am trying to do is even possible before diving in and figuring it all out.
If it is possible, I would appreciate any insight on what methods would be relevant for this task just to give me some direction to get started.
Based on comments from Sandy Good and two SE questions found here and here, this is the code I have so far:
// Script to shuffle question in a Google Form when the questions are in separate sections
function shuffleFormSections() {
getQuestionID();
createNewShuffledForm();
}
// Get question IDs
function getQuestionID() {
var form = FormApp.getActiveForm();
var items = form.getItems();
arrayID = [];
for (var i in items) {
arrayID[i] = items[i].getId();
}
// Logger.log(arrayID);
return(arrayID);
}
// Shuffle function
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
// Shuffle IDs and create new form with new question order
function createNewShuffledForm() {
shuffle(arrayID);
// Logger.log(arrayID);
var newForm = FormApp.create('Shuffled Form');
for (var i in arrayID) {
arrayID[i].getItemsbyId();
}
}
Try this. There's a few "constants" to be set at the top of the function, check the comments. Form file copying and opening borrowed from Sandy Good's answer, thanks!
// This is the function to run, all the others here are helper functions
// You'll need to set your source file id and your destination file name in the
// constants at the top of this function here.
// It appears that the "Title" page does not count as a page, so you don't need
// to include it in the PAGES_AT_BEGINNING_TO_NOT_SHUFFLE count.
function shuffleFormPages() {
// UPDATE THESE CONSTANTS AS NEEDED
var PAGES_AT_BEGINNING_TO_NOT_SHUFFLE = 2; // preserve X intro pages; shuffle everything after page X
var SOURCE_FILE_ID = 'YOUR_SOURCE_FILE_ID_HERE';
var DESTINATION_FILE_NAME = 'YOUR_DESTINATION_FILE_NAME_HERE';
// Copy template form by ID, set a new name
var newFormFile = DriveApp.getFileById(SOURCE_FILE_ID).makeCopy();
newFormFile.setName(DESTINATION_FILE_NAME);
// Open the duplicated form file as a form
var newForm = FormApp.openById(newFormFile.getId());
var pages = extractPages(newForm);
shuffleEndOfPages(pages, PAGES_AT_BEGINNING_TO_NOT_SHUFFLE);
var shuffledFormItems = flatten(pages);
setFormItems(newForm, shuffledFormItems);
}
// Builds an array of "page" arrays. Each page array starts with a page break
// and continues until the next page break.
function extractPages(form) {
var formItems = form.getItems();
var currentPage = [];
var allPages = [];
formItems.forEach(function(item) {
if (item.getType() == FormApp.ItemType.PAGE_BREAK && currentPage.length > 0) {
// found a page break (and it isn't the first one)
allPages.push(currentPage); // push what we've built for this page onto the output array
currentPage = [item]; // reset the current page to just this most recent item
} else {
currentPage.push(item);
}
});
// We've got the last page dangling, so add it
allPages.push(currentPage);
return allPages;
};
// startIndex is the array index to start shuffling from. E.g. to start
// shuffling on page 5, startIndex should be 4. startIndex could also be thought
// of as the number of pages to keep unshuffled.
// This function has no return value, it just mutates pages
function shuffleEndOfPages(pages, startIndex) {
var currentIndex = pages.length;
// While there remain elements to shuffle...
while (currentIndex > startIndex) {
// Pick an element between startIndex and currentIndex (inclusive)
var randomIndex = Math.floor(Math.random() * (currentIndex - startIndex)) + startIndex;
currentIndex -= 1;
// And swap it with the current element.
var temporaryValue = pages[currentIndex];
pages[currentIndex] = pages[randomIndex];
pages[randomIndex] = temporaryValue;
}
};
// Sourced from elsewhere on SO:
// https://stackoverflow.com/a/15030117/4280232
function flatten(array) {
return array.reduce(
function (flattenedArray, toFlatten) {
return flattenedArray.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
},
[]
);
};
// No safety checks around items being the same as the form length or whatever.
// This mutates form.
function setFormItems(form, items) {
items.forEach(function(item, index) {
form.moveItem(item, index);
});
};
I tested this code. It created a new Form, and then shuffled the questions in the new Form. It excludes page breaks, images and section headers. You need to provide a source file ID for the original template Form. This function has 3 inner sub-functions. The inner functions are at the top, and they are called at the bottom of the outer function. The arrayOfIDs variable does not need to be returned or passed to another function because it is available in the outer scope.
function shuffleFormSections() {
var arrayOfIDs,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,items,shuffle;
newFormFile = DriveApp.getFileById('Put the source file ID here')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
arrayOfIDs = [];
fncGetQuestionID = function() {
var i,L,thisID,thisItem,thisType;
items = newForm.getItems();
L = items.length;
for (i=0;i<L;i++) {
thisItem = items[i];
thisType = thisItem.getType();
if (thisType === FormApp.ItemType.PAGE_BREAK ||
thisType === FormApp.ItemType.SECTION_HEADER ||
thisType === FormApp.ItemType.IMAGE) {
continue;
}
thisID = thisItem.getId();
arrayOfIDs.push(thisID);
}
Logger.log('arrayOfIDs: ' + arrayOfIDs);
//the array arrayOfIDs does not need to be returned since it is available
//in the outermost scope
}// End of fncGetQuestionID function
shuffle = function() {// Shuffle function
var j, x, i;
Logger.log('shuffle ran')
for (i = arrayOfIDs.length; i; i--) {
j = Math.floor(Math.random() * i);
Logger.log('j: ' + j)
x = arrayOfIDs[i - 1];
Logger.log('x: ' + x)
arrayOfIDs[i - 1] = arrayOfIDs[j];
arrayOfIDs[j] = x;
}
Logger.log('arrayOfIDs: ' + arrayOfIDs)
}
shuffleQuestionsInNewForm = function() {
var i,L,thisID,thisItem,thisQuestion,questionType;
L = arrayOfIDs.length;
for (i=0;i<L;i++) {
thisID = arrayOfIDs[i];
Logger.log('thisID: ' + thisID)
thisItem = newForm.getItemById(thisID);
newForm.moveItem(thisItem, i)
}
}
fncGetQuestionID();//Get all the question ID's and put them into an array
shuffle();
shuffleQuestionsInNewForm();
}

How do I find and select a next bold word

From the https://gist.github.com/oshliaer/d468759b3587cfb424348fa722765187 , It is possible to select a particular word from the findText, I want to implement the same for bold words only
I have a function to find bold. How do I modify the above gist?
var startFlag = x;
var flag = false;
for (var i = x; i < y; i++) {
if (text.isBold(i) && !flag) {
startFlag = i;
flag = true;
} else if (!text.isBold(i) && flag) {
flag = false;
rangeBuilder.addElement(text, startFlag, i - 1);
doc.setSelection(rangeBuilder.build());
return;
}
}
if (flag) {
rangeBuilder.addElement(text, startFlag, i - 1);
doc.setSelection(rangeBuilder.build());
return;
}
Let's assume another algorithm
/*
* #param {(DocumentApp.ElementType.LIST_ITEM | DocumentApp.ElementType.PARAGRAPH)} element
*/
function hasBold(element, start) {
var text = element.editAsText();
var length = element.asText().getText().length;
var first = -1;
var end = -1;
while (start < length) {
if (first < 0 && text.isBold(start)) {
first = start;
}
if (first > -1 && !text.isBold(start)) {
end = start - 1;
return {
s: first,
e: end
}
}
start++;
}
if (first > -1) {
return {
s: first,
e: length - 1
}
}
return false;
}
It's not clean but I've tested it and it works fine.
hasBold lets us finding bolds in the current element.
Finally, we have to loop this feature within document.getBody().
You could to get the full code here find next bold text in google document.
Also you could try it on a copy
A new idea
The Direct searcing
The best way is to use a callback while it is checked
var assay = function (re) {
var text = re.getElement()
.asText();
for (var offset = re.getStartOffset(); offset <= re.getEndOffsetInclusive(); offset++) {
if (!text.isBold(offset)) return false;
}
return true;
}
function findNextBold() {
var sp = 'E.';
Docer.setDocument(DocumentApp.getActiveDocument());
var rangeElement = Docer.findText(sp, Docer.getActiveRangeElement(), assay);
rangeElement ? Docer.selectRangeElement(rangeElement) : Docer.setCursorBegin();
}
The Approx searching
var assay = function(re) {
var text = re.getElement().asText();
var startOffset = re.getStartOffset();
var endOffset = re.getEndOffsetInclusive() + 1;
for (var offset = startOffset; offset < endOffset; offset++) {
if (!text.isBold(offset)) return false;
}
return this.test(text.getText().slice(startOffset, endOffset));
}
function findNextBold() {
var searchPattern = '[^ ]+#[^ ]+';
var testPattern = new RegExp('^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$');
Docer.setDocument(DocumentApp.getActiveDocument());
var rangeElement = Docer.findText(searchPattern, Docer.getActiveRangeElement(), assay.bind(testPattern));
rangeElement ? Docer.selectRangeElement(rangeElement) : Docer.setCursorBegin();
}
Docer
Yes. it is possible to find bold text. You need to use findText(searchPattern) to search the contents of the element for the specific text pattern using regular expressions. The provided regular expression pattern is independently matched against each text block contained in the current element. Then, use isBold() to retrieve the bold setting. It is a Boolean which returns whether the text is bold or null.

AS3 many buttons with boolean function - less verbose?

I have twenty eight instances of a two-frame MovieClip (frame1 = off - frame 2 = on) to select PDFs to send. The following code works fine, but I am looking to tighten it up and make it less verbose and easier to read. I include only one reference to an instance for space and sanity sake.
function PDFClick(e:MouseEvent):void {
targetPDF = e.target.ID;
trace("targetPDF " +targetPDF);
if (targetPDF == "PDF1")
if (pdf.pcconnectionPDF1.currentFrame == 1)
{
pdf.pcconnectionPDF1.gotoAndPlay(2);
PDF1 = 1;
trace("PDF1 is "+PDF1);
}else{
pdf.pcconnectionPDF1.gotoAndPlay(1);
PDF1 = 0;
trace("PDF1 is "+PDF1);
}
Thanks! trying to learn
You'll want to generalize your calls to your ID, that way you don't need special code for each condition.
function PDFClick(e:MouseEvent):void {
var ID:String = e.target.ID;
var mc = pdf["pcconnection" + ID];
if (mc.currentframe == 1) {
mc.gotoAndPlay(2);
this[ID] = 1;
} else {
mc.gotoAndPlay(1);
this[ID] = 0;
}
}
How about this:
function PDFClick(e:MouseEvent):void {
targetPDF = e.target.ID;
trace("targetPDF " +targetPDF);
if (targetPDF == "PDF1") {
var frame:int = pdf.pconnectionPDF1.currentFrame;
pdf.pconnectionPDF1.gotoAndPlay( frame == 1 ? (PDF1 = 1)+1 : (PDF1 = 0)+1 );
}
}
I think that's about what you are looking for.