In Adobe Acrobat Javascript, how can I force a page to become "editable" before a certain part of a script acts upon it? - pdf

What I'm trying to do: Iterate over each page in a PDF, and extract the number of words on each page.
What is happening instead: The code below will return 0 words for any page that has not become "editable". Although I have selected for all pages to become editable at once, Adobe will not maintain the editability of a page for very long after I have left that page. Side note: It also seems to cap how many pages I can have "editable" at once. This is a problem because right now I'm working with a 10 page selection of a pdf file. This same code will have to work with a 120+ page pdf. Please click 'Edit PDF'-->'Scanned Documents'-->'Settings' to see what I mean by "editable". I have already selected the option to have all pages become editable at once.
What I've tried so far: I've tried various ways to get Acrobat to make the page being iterated upon the "active one" so that it would become editable. I've tried manually setting the page number after each iteration of the for loop, and including an artificial delay like with the h variabled for loop in the sample code. I've tried looking for some sort of method that determines which page is the "active one" but I've had no luck so far.
CurrDoc = app.activeDocs[0]
CurrDoc.title;
NumPagesInDoc = CurrDoc.numPages;
console.println("Document has "+NumPagesInDoc+" pages");
for (j=0; j<NumPagesInDoc; j++)
{
NumWordsOnPage = CurrDoc.getPageNumWords(j);
CurrDoc.pageNum = j;
for(h=0; h<10000;h++); //<--I've tried adding in delays to give time so that
//Acrobat can catch up, but this hasn't worked.
console.println("Page number: "+j+" has this number of words: "+ NumWordsOnPage);
};
Output:
Document has 10 pages
Page number: 0 has this number of words: 309
Page number: 1 has this number of words: 0
Page number: 2 has this number of words: 0
Page number: 3 has this number of words: 0
Page number: 4 has this number of words: 0
Page number: 5 has this number of words: 0
Page number: 6 has this number of words: 0
Page number: 7 has this number of words: 0
Page number: 8 has this number of words: 0
Page number: 9 has this number of words: 158
true
Note: Different pages might work on the output at different times depending on which pages I've clicked on most recently before running the script.
Any guidance or help would be greatly appreciated. Thank you for your time.

So. I'm still not entirely sure what the issue is, but I've found a way to get acrobat to function most of the time.
Before clicking the "make all pages editable" option, zoom all the way out until you can see all the pages in the document. For whatever reason, when I did this, it would seem to refresh something about the settings and once again make all the pages editable. This even seemed to work when I opened a totally different pdf and pressed "make all pages editable" even without zooming out.

Related

composeTestRule checking that atleast 1 item exists

I have a list which has 2 different items. However, if the user gets close to the end of the list then the 2 same items are added again and again to create an infinite scrolling feel.
I've created a test to basically verify that the item exists like so:
composeTestRule
.onAllNodesWithContentDescription("Home")
.assertCountEquals(2)
As you can see this just finds nodes with the content description of "Home" and checks if their are 2.
Currently, this works as the screen size is small but let's say the screen size is doubled then this will fail as the assertCountEquals(2) would need to check for 4.
I was wondering to make this code better, is there a way to basically check that atleast 1 exists?
onAllNodes methods return an array, grab the first element and check whether it exists or is displayed.
composeTestRule
.onAllNodesWithContentDescription("Home")
.onFirst().assertExists()

Can I count rows across multiple pages of a table with robot framework?

I am quite new to robot, and have only been working solo on it at work for a month or so.
Currently I am trying to count the total number on rows in a table within the application I am testing. (chrome based)
This is what I am using:
${count}= get element count //table[#class='options-table']/tbody/tr
Which brings back a value of 5 - this is counting the first page. However, I'm expecting it to bring back 76 as there are multiple pages.
Can anyone help on how to bring back the amount of rows across multiple pages?
${count}= get element count //table[#class='options-table']/tbody/tr
Expected result: 76
Actual result: 5 (only the first page)
To avoid a slightly complex logic (iterating through pages, summing up element counts) in a Robot Framework keyword you could write your own keyword in Python for example.
In this case you need a keyword that takes an element locator (//table[#class='options-table']/tbody/tr to be specific) and a list of page urls.
To implement such keyword, create a file like ExtendedSeleniumLib.py:
from robot.libraries.BuiltIn import BuiltIn
def get_element_count_from_pages(locator, *page_urls):
seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
element_count = 0
for url in page_urls:
seleniumlib.go_to(url)
element_count += seleniumlib.get_element_count(locator)
return element_count
and from your test code you can use it like:
*** Settings ***
Library SeleniumLibrary
Library ExtendedSeleniumLib
*** Variables ***
${SE HEADER LOCATOR} //a[#class='site-header--link fs-headline1 fw-bold']
*** Test Cases ***
Count Elements On Multiple Pages Example
[Setup] Open Browser https://stackoverflow.com Firefox
Maximize Browser Window
Set Selenium Speed 0.1
${count}= Get Element Count From Pages ${SE HEADER LOCATOR}
... https://iot.stackexchange.com/
... https://sqa.stackexchange.com/
... https://robotics.stackexchange.com/
Should Be Equal As Integers ${count} 3
[Teardown] Close Browser
This example iterates through three Stack Exchange sites and counts the header elements. As there should be only one on each page the expected result is 3. Based on this you should be able to count the table rows on your pages.
About how to configure search path for libraries and resources, check the relevant chapter form the Robot Framework User Guide; Configuring where to search libraries and other extensions. If you place the python file into the same directory where your robot file is, then you do not need anything to do.
Please check below code, it assumes that the total number of pages will not be more than 100 since I'm not aware of the webpage, you can either take this number from webpage if available. Also, if you are sure that total number of rows per page is always 5 then you can use below formula
[ 5 * (total number of pages - 1 ) + row count of the last page]
This can give you total row count across all pages without traversing through all the pages. Also, please add any time synchronisation steps for the successful run.
Get Count of All Pages
${next_page_locator} Set Variable enter next page icon/link xpath here
${first_row_locator} Set Variable enter first row xpath here
${total_count} set variable 0
: FOR ${index} IN RANGE 1 100
\ Wait Until Element Is Visible ${first_row_locator}
\ ${count} get element count //table[#class='options-table']/tbody/tr
\ ${total_count} evaluate ${count} + ${total_count}
\ ${next_link_present} Run Keyword And Return Status Page Should Contain Element ${next_page_locator}
\ exit for loop if ${next_link_present} is ${False}
\ Click Element ${next_page_locator}

Limit rows on auto growing text area (Sencha Touch)

I have the following snippet of code for auto expanding the textarea in sencha touch. I need to cap it out at a set number of rows.
Any ideas?
http://www.senchafiddle.com/#Q9gjN
Wouldn't this be great if it were a nice, easy to use property.
At first I thought it would be the maxRows property but this is just the number of rows to display before the vertical scrollbar appears.
It may be that the only way would be a complicated solution such as this: http://www.codeproject.com/Articles/56392/How-to-Limit-the-Number-of-Lines-and-Characters-in
or
Limiting number of lines in textarea
EDIT: I needed to cap the number of rows in an address to 5 lines.
One approach could be to listen to the keyup event on the textareafield, check for the 'Enter' key and then revert back to previous input.
The approach I have taken is just to add validation to the model, which works great.
{ type: 'format', field: 'Address', message: 'Address cannot be more than 5 lines.', matcher: /^([^\r\n]{0,50}(\r?\n|$)){5}$/ }
The regex restricts saving a record to the store that has more than 5 lines, of more than 50 chars.

Display (include) MediaWiki table of contents (TOC) on another page

In MediaWiki, we would like to display tables of contents (from multiple pages) on one other page. We know that this can be done automatically, e.g. if we include pages 1, 2 & 3 like this:
{{:Page 1}}
{{:Page 2}}
{{:Page 3}}
on page X, then page X displays a combined TOC for pages 1, 2 & 3.
But we want a table on page X which shows each TOC in a separate cell. Is there any way to include each TOC individually?
I have tried using <noinclude></noinclude> tags around the text on pages 1, 2 & 3 and then forcing a table of contents outside (using __TOC__) but that only creates a TOC on page X (using the contents of page X).
You can't. The table of contents is generated dynamically in each page, for all the sections that appear in the current page.
When you include the sections (or at least the section headings) of the other pages, they will show up in the TOC of page X. If you include the __TOC__ magic word, it means only to generate the toc for page X.
Three solutions:
Include the section (headings) of pages 1, 2 and 3. They will show up in the toc of page X even when contained in a <div style="display:none;"> - a really ugly way.
Copy the TOC tables manually to page X. You can view their HTML by looking in the generated HTML source of pages 1, 2 and 3 with your browser.
Write an extension that allows transclusion of TOCs from other pages. It might introduce a new parserfunction {{toc:<pagename>}} and be able to call the toc-generating function in the context of another page.
Include only the section headings as a list. In the pages 1, 2 and 3 you will need to write
== <onlyinclude><includeonly>##</includeonly> Heading Number One </onlyinclude> ==
=== <onlyinclude><includeonly>###</includeonly> Part One of Heading Number One </onlyinclude> ===
...
which you will be able to include in the table at Page X with
{{:Page 1}}
It should show up as a numbered list, like the TOC.

Rebol/View: How to assign images to layout already created?

Using Rebol/View 2.7.7, I'm trying to create a card game based on Nick's Rebol tutorial at: http://re-bol.com/rebol.html#section-10.18. What I want to do though is read the cards from the binary file Nick created, discard some of the data, and use it to layout a tableau of cards, 4 rows of 3 columns, with the 2 center card locations not used.
Here's my code:
protect-system
random/seed now
do %cards.r ;--include the binary card data
the-tableau: [
size 320x480 backdrop 0.170.0
style tabstyle image 80x100 teal
style holdplace box 80x100 coal
across
at 30x20 tc1: tabstyle
tc2: tabstyle
tc3: tabstyle return
at 30x130 tc4: tabstyle
tc100: holdplace
tc5: tabstyle return
at 30x240 tc6: tabstyle
tc200: holdplace
tc7: tabstyle return
at 30x350 tc8: tabstyle
tc9: tabstyle
tc10: tabstyle
]
lc: copy []
lc: [tc1 tc2 tc3 tc4 tc5 tc6 tc7 tc8 tc9 tc10]
deck-cards: copy [] ; The deck holds all of the cards from the binary file
deck-cards-num: copy []
deck-cards-color: copy []
lay: layout the-tableau
foreach [card label num color pos] cards [
dimg: load to-binary decompress (card)
append deck-cards dimg ;feel movestyle
throw-away-label: label
append deck-cards-num num
append deck-cards-color color
throw-away-pos: pos
]
random-card: does [pick deck-cards random length? deck-cards]
foreach c lc [set-face get c deck-cards]
view lay
do-events
But this doesn't show the cards at all. I'm not even sure it's reading the correctly? Where is the problem?
Actually you didn't use the random-card function in your for loop at the end... :-)
foreach c lc [get c set-face get c random-card ]
You note that you are not sure if data was loaded correctly...
here is a simple way to find out... just print/probe the TYPE? of that data
dimg: load to-binary decompress (card)
probe type? dimg
In this case it will print out image! in the console... so yep... that's working. :-)
As an added little detail, I noticed you didn't compensate your random for the "back face" image in the card data (which is at its end), so the random-card function should be fixed like so:
random-card: does [pick deck-cards random (length? deck-cards) - 1] ; - 1 since we don't want the back face to be picked.
You only need 'do-events if the event loop is not started.
View/new does not start the event loop .. but View does
I'm not addressing your actual problem though :(
to make the do-events note clear, I added a little answer here so I can add some inline code....
here is an example where you'd want your do-events to be used.
view/new lay ; display the interface right now. (with no cards)
random-card: does [pick deck-cards random (length? deck-cards) - 1] ; - 1 since we don't want the back face to be picked.
; deal cards with a half second delay.
foreach c lc [f: get c set-face get c random-card wait 0.5]
do-events
here, any code you put after 'DO-EVENTS will be executed once all view windows have closed.
which can be things like tmp file cleanup, save on exit, "save changes" dialogs, etc.
additional note:
While building graphics code, its a good habit to place this at the very start of you application:
print " "
It will open up the console, and then any view windows will show up in front of it.
When ready to share, just comment the line and remove any print statements in your code.
this is useful for 3 things:
1) Its usually highly annoying when the console always pops-up over your application while its tracing (print/probe/etc) some stuff after your window opens.
2) This also has the more useful side-effect of showing you if your application quit correctly since the console will ALSO quit when all waits have terminated correctly.
In your original example, if you add the above print, then you'll see that the console never closes, so this means the application is still running with no more application windows listening to events.
3) It also has the advantage that you can terminate the graphic app directly by closing the console window. This effectively closes all windows and waits immediately and shortcuts any "on application quit" code you might have (code after do-events).