Forum How do I...?

How do I generate line numbers - How do I reset a counter on a page break

sfinktah
Sorry, this seems to be the dumbest question... but I have searched and searched and found no answer.

I'm sure the answer is obvious, but it is eluding me.

<!DOCTYPE html>
<html lang="en">
<head>
<style>
	/* Attempt to reset a counter within @page */
	@page {
		counter-reset: line-no;
	}
	div.numbered {
		counter-increment: line-no;
		height: 5cm;
	}
	div.numbered::before {
		content: counter(line-no) ') ';
	}
</style>
</head>
<body>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
</body>
</html>


I'm just looking for an output such as this:

--[page]--
1.
2.
3.
4.
--[page]--
1.
2.
3.
4.

etc

Edited by sfinktah

mikeday
Actually I don't think this is possible yet, at the moment only the "page", "pages", and "footnote" counters can be reset in @page rules.
sfinktah
Ahh.. FTR, I also tried sneaking a reset into a table header. :p

However, I'm sure I could re-purpose footnotes to do the deed on this occasion. :)

But this reminds me of a thought I had regarding de-duplication of page-numbers in a TOC whilst reading your javascript 2-pass solution...

The terminology escape me (4am), but could one (for arguments sake) do something like this (exact syntax may be faulty, see previous ref.):

<style>
@page { @top { content: prince-javascript( sfinktah.pageCounter ) }}
div::before { content: prince-javascript( sfinktah.myCounter ) }

<script>
sfinktah = {
   _counter = 0,
   myCounter = function() { return "" + ++sfinktah._counter },
   pageCounter = function() { sfinktah._counter = 0 }
} 


I assume this would be an epic fail, because content generation must necessarily take place before pagination, ergo javascript functions do not necessarily get called in a "top-to-bottom per page" kind of way. But, some trickery may still be possible... (eg, javascript content in that table header or somesuch)....

... or de-duplication of page numbers in a TOC. (Assuming the script is passed something like the _element_ so that it can keep track of what page numbers it's spat out for whom)
mikeday
Good idea! If you pass the page counter to the JavaScript function, then it will know which page it is on and can return the right counter value. Something like this:
function getLineNum(currPage) { ... }

Prince.addScriptFunc("getLineNum", getLineNum);

div::before { content: prince-javascript(getLineNum, counter(page)) }

It may require some trickery in the getLineNum function, and Prince may call it multiple times if the document requires multiple passes to resolve cross-references. So it might be necessary to give each div an explicit index attribute, like an ID with a number, and pass that in to the script function as well.
sfinktah
Good to know that you can pass in attr() to javascript functions...

just a though, but if you made prince-script calls a little bit more like events (which get passed both the element and the event) -- or in this case, element and css_thingy you might be able to start relegating new features into javascript modules. :)

Here's the working solution I came up with, I think you'll like it.

<!DOCTYPE html>
<html lang="en">
<head>
	<style>
		div.numbered {
			counter-increment: line-no; 
			height: 5cm;
		}
		div.numbered::before {
			content: prince-script(getLineNum, counter(page), counter(line-no)) ') '; 
		}
	</style>
	<script>

		lastPage = 0,
		lastLine = 0,
		rollingLine = 0;

		Prince.addScriptFunc("getLineNum", function(page, line) {
			if (page > lastPage) {
				lastPage = page;
				lastLine = 0;
				rollingLine = 0;
			}
			if (line > lastLine) {
				lastLine = line;
				rollingLine ++;
			}
			return '' + rollingLine; 
		});
	</script>
</head>
<body>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
	<div class="numbered">Lorum Ipsum</div>
</body>
</html>
mikeday
Looks good! I think it just needs one small change:
Prince.addScriptFunc("getLineNum", function(page, line) {
    page = Number(page);
    line = Number(line);

Since counter values are passed as strings, doing a direct comparison on them can give odd results, eg. "10" < "2". Converting them to numbers first will avoid this.
sfinktah
I opted for keeping them as strings, and doing a !=.

Saves superfluous casting, and will safely handle strange situations like page number resets.

	sfinktah = {
		lastPage: 0,
		lastLine: 0,
		rollingLine: 0,
		getLineNum: function(counter_page, counter_line) {
			if (counter_page != sfinktah.lastPage) {
				sfinktah.lastPage = counter_page;
				sfinktah.lastLine = 0;
				sfinktah.rollingLine = 0;
			} 
			if (counter_line != sfinktah.lastLine) {
				sfinktah.lastLine = counter_line;
				sfinktah.rollingLine ++;
			}
			return '' + sfinktah.rollingLine; 
		}
	};

	Prince.addScriptFunc("getLineNum", function(page, line) {
		return sfinktah.getLineNum(page, line);
	});