[fix] slick-router
This commit is contained in:
parent
0659567f36
commit
dcd18dd3d5
18 changed files with 618 additions and 28 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
|||
abc/
|
||||
data/
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -1,3 +1,5 @@
|
|||
{
|
||||
"basexTools.xquery.profile": "basex-10"
|
||||
"basexTools.xquery.profile": "basex-10",
|
||||
"basexTools.xquery.showHovers": "false",
|
||||
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"cells":[{"kind":1,"language":"markdown","value":"# PDFBox3 \r\nA BaseX 10+ interface to Apache PDFBox® library version 3 \r\n## Apache PDFBox® - A Java PDF Library\r\n\r\nThe Apache PDFBox® library is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents. Apache PDFBox also includes several command-line utilities. Apache PDFBox is published under the Apache License v2.0.\r\nhttps://pdfbox.apache.org/"},{"kind":1,"language":"markdown","value":"It comes with the useful PDF debug tool `java -jar debugger-app-3.0.1.jar`"},{"kind":1,"language":"markdown","value":"## Set up XQuery context for following code..."},{"kind":2,"language":"xquery","value":"(:<:)(: XQuery Context :)\r\nimport module namespace pdfbox = \"urn:expkg-zone58:pdfbox:3\" at \"../src/lib/pdfbox3.xqm\";\r\nimport module namespace pagenos = 'urn:pageno' at \"../src/lib/pageno.xqm\";\r\nimport module namespace config = 'urn:abc-clio:config' at 'C:\\Users\\mrwhe\\git\\bloomsbury\\content-architecture\\xquery\\ABC-CLIO/lib/abc-config.xqm';\r\n\r\ndeclare variable $samples:= map{\r\n \"climate\": \"drop-01d\\set\\2-6-1\\A5579C_1\\271989---Book_File-Web_PDF_9798400627484_486728.pdf\",\r\n \"women\": \"drop-01d\\set\\2-6-1\\A6229C_1\\257334---Book_File-Web_PDF_9798216172628_486742.pdf\",\r\n \"genocide\": \"drop1-pdf\\GR2967-TRD\\272791---Book_File-Web_PDF_9798400640216_486366.pdf\",\r\n \"world\": \"drop-01c\\gpg-book\\2-6\\A3506C-TRD\\256186---Book_File-Web_PDF_9798216038955_486148.pdf\"\r\n};\r\ndeclare variable $PDF:= (: $samples?women=>file:resolve-path($config:data) :)\r\n\"C:\\Users\\mrwhe\\git\\bloomsbury\\content-architecture\\xquery\\ABC-CLIO\\data\\drop-01e\\set\\2-6-1\\A5690C_1\\257107---Book_File-Web_PDF_9798400691218_486731.pdf\";"},{"kind":1,"language":"markdown","value":"# Version of pdfbox in use"},{"kind":2,"language":"xquery","value":"pdfbox:version()"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:pdfVersion()"},{"kind":1,"language":"markdown","value":"# Page count for PDF"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:page-count()"},{"kind":1,"language":"markdown","value":"## save range to new pdf"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:extract(2,12,\"c:\\tmp\\a.pdf\")"},{"kind":1,"language":"markdown","value":"## Outline / bookmarks"},{"kind":2,"language":"xquery","value":"\r\nlet $doc:=pdfbox:open($PDF)\r\nreturn pdfbox:outline($doc)"},{"kind":1,"language":"markdown","value":"## Page labels"},{"kind":2,"language":"xquery","value":"\r\nlet $doc:=pdfbox:open($PDF)\r\nreturn pdfbox:getPageLabels($doc)"},{"kind":1,"language":"markdown","value":"# getText from page index"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pdfbox:getText($doc,56)"},{"kind":1,"language":"markdown","value":"## PageNo text analysis"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pagenos:page-report($doc)\r\n"},{"kind":1,"language":"markdown","value":"# Inverted pageno map"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pagenos:page-report($doc)=>pagenos:inverted-map()"},{"kind":1,"language":"markdown","value":"## report"},{"kind":2,"language":"xquery","value":"declare variable $a:=\"C:\\Users\\mrwhe\\Desktop\\1e\\\";\r\nfor $f in file:list($a,true(),\"*.pdf\") \r\nwhere not(contains($f,\"outputs\"))\r\nlet $doc:=pdfbox:open(file:resolve-path($f,$a))\r\nlet $outline:=pdfbox:outline($doc)\r\nlet $count:=count($outline)\r\norder by $count \r\nreturn ``[`{$f}`: `{$count}`]``"}]}
|
||||
{"cells":[{"kind":1,"language":"markdown","value":"# PDFBox3 \r\nA BaseX 10+ interface to Apache PDFBox® library version 3 \r\n## Apache PDFBox® - A Java PDF Library\r\n\r\nThe Apache PDFBox® library is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents. Apache PDFBox also includes several command-line utilities. Apache PDFBox is published under the Apache License v2.0.\r\nhttps://pdfbox.apache.org/"},{"kind":1,"language":"markdown","value":"It comes with the useful PDF debug tool `java -jar debugger-app-3.0.1.jar`"},{"kind":1,"language":"markdown","value":"## Set up XQuery context for following code..."},{"kind":2,"language":"xquery","value":"(:<:)(: XQuery Context :)\r\nimport module namespace pdfbox = \"urn:expkg-zone58:pdfbox3\" at \"../src/lib/pdfbox3.xqm\";\r\nimport module namespace bookpages = 'urn:bookpages' at \"../src/lib/bookpages.xqm\";\r\nimport module namespace config = 'urn:abc-clio:config' at 'C:\\Users\\mrwhe\\git\\bloomsbury\\content-architecture\\xquery\\ABC-CLIO/lib/abc-config.xqm';\r\n\r\ndeclare variable $samples:= map{\r\n \"climate\": \"drop-01d\\set\\2-6-1\\A5579C_1\\271989---Book_File-Web_PDF_9798400627484_486728.pdf\",\r\n \"women\": \"drop-01d\\set\\2-6-1\\A6229C_1\\257334---Book_File-Web_PDF_9798216172628_486742.pdf\",\r\n \"genocide\": \"drop1-pdf\\GR2967-TRD\\272791---Book_File-Web_PDF_9798400640216_486366.pdf\",\r\n \"world\": \"drop-01c\\gpg-book\\2-6\\A3506C-TRD\\256186---Book_File-Web_PDF_9798216038955_486148.pdf\"\r\n};\r\ndeclare variable $PDF:= (: $samples?women=>file:resolve-path($config:data) :)\r\n\"C:\\Users\\mrwhe\\git\\bloomsbury\\content-architecture\\xquery\\ABC-CLIO\\data\\drop-01e\\set\\2-6-1\\A5690C_1\\257107---Book_File-Web_PDF_9798400691218_486731.pdf\";"},{"kind":1,"language":"markdown","value":"# Version"},{"kind":1,"language":"markdown","value":" ## pdfbox version"},{"kind":2,"language":"xquery","value":"pdfbox:version()"},{"kind":1,"language":"markdown","value":"PDF specification version used by document"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:pdfVersion()"},{"kind":1,"language":"markdown","value":"# Page count for PDF"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:page-count()"},{"kind":1,"language":"markdown","value":"## save range to new pdf"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:extract(2,12,\"c:\\tmp\\a.pdf\")"},{"kind":1,"language":"markdown","value":"## Outline / bookmarks"},{"kind":1,"language":"markdown","value":"### sequence of maps"},{"kind":2,"language":"xquery","value":"\r\npdfbox:open($PDF)=>pdfbox:outline()"},{"kind":1,"language":"markdown","value":"XML"},{"kind":2,"language":"xquery","value":"pdfbox:open($PDF)=>pdfbox:outline()=>pdfbox:outline-xml()"},{"kind":1,"language":"markdown","value":"## Page labels"},{"kind":2,"language":"xquery","value":"\r\npdfbox:open($PDF)=>pdfbox:getPageLabels()"},{"kind":1,"language":"markdown","value":"# getText from page index"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pdfbox:getText($doc,56)"},{"kind":1,"language":"markdown","value":"## PageNo text analysis"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pagenos:page-report($doc)\r\n"},{"kind":1,"language":"markdown","value":"# Inverted pageno map"},{"kind":2,"language":"xquery","value":"let $doc:=pdfbox:open($PDF)\r\nreturn pagenos:page-report($doc)=>pagenos:inverted-map()"},{"kind":1,"language":"markdown","value":"## report"},{"kind":2,"language":"xquery","value":"declare variable $a:=file:resolve-path(\"../data/1e/\",file:base-dir());\r\n\r\nfor $f in file:list($a,true(),\"*.pdf\") \r\nwhere not(contains($f,\"outputs\"))\r\nlet $doc:=pdfbox:open(file:resolve-path($f,$a))\r\n(: let $outline:=pdfbox:outline($doc) :)\r\nlet $count:=pdfbox:page-count($doc)\r\norder by $count \r\nreturn ``[`{$f}`: `{ $count }`]``"}]}
|
63
src/lib/bookpages.xqm
Normal file
63
src/lib/bookpages.xqm
Normal file
|
@ -0,0 +1,63 @@
|
|||
xquery version '3.1';
|
||||
(:~ describe book page numbers as sequence of ranges, similar to PDF pagelabels
|
||||
@author quodatum
|
||||
:)
|
||||
module namespace bookpages = 'urn:bookpages';
|
||||
|
||||
(:~ Invisible-xml grammar to parse custom pagelabel representation :)
|
||||
declare variable $bookpages:grammar:="
|
||||
book: pagecount,'#',range,(-',', range)*.
|
||||
pagecount:['0'-'9']+.
|
||||
range: s,from?,s,type,s,prefix?,s,offset?.
|
||||
@from: ['0'-'9']+. { pageIndex }
|
||||
@type: ['C'|'D'|'R'|'r'|'A'|'a'|'w'].
|
||||
@prefix: -':',~[',']+.
|
||||
@offset: -'@',['0'-'9']+.
|
||||
|
||||
-s: ([Zs]; #9; #a; #d)*. {Optional whitespace}
|
||||
";
|
||||
|
||||
(:~
|
||||
page number range in given style
|
||||
:)
|
||||
declare function bookpages:span($type as xs:string,$length as xs:integer,$first as xs:integer)
|
||||
as xs:string*{
|
||||
let $r:=$first to $first+$length
|
||||
return switch ($type)
|
||||
case "D" return $r!format-integer(.,"1")
|
||||
case "r" return $r!format-integer(.,"i")
|
||||
case "R" return $r!format-integer(.,"I")
|
||||
case "C" return "Cover"
|
||||
default return $r!format-integer(.,$type)
|
||||
};
|
||||
|
||||
(:~ pagelabels from text:)
|
||||
declare function bookpages:expand($pages as xs:string)
|
||||
as xs:string*{
|
||||
let $x:=bookpages:parse($pages)
|
||||
let $last:=head($x)=>xs:integer()
|
||||
return hof:until(
|
||||
function($m){ empty($m?ranges) or count($m?result)eq $last },
|
||||
function($m){
|
||||
let $range:=head($m?ranges)=>trace("SS")
|
||||
let $start:=if($range/@offset)then xs:integer($range/@offset) else 1
|
||||
let $end:=($m?ranges[2]/xs:integer(@from)-1) otherwise $last
|
||||
let $length:=$end -count($m?result)-1
|
||||
let $span:=bookpages:span($range/@type,$length,$start)
|
||||
let $span:=if($range/@prefix)then $span!concat($range/@prefix,.) else $span
|
||||
return map {
|
||||
'ranges': tail($m?ranges),
|
||||
'result': ($m?result, $span)
|
||||
}},
|
||||
|
||||
(: initial input = grammar ranges :)
|
||||
map { 'ranges': tail($x) , 'result': () }
|
||||
)?result
|
||||
};
|
||||
|
||||
(:~ parse pagenumber description to xml :)
|
||||
declare function bookpages:parse($pages as xs:string)
|
||||
as element(range)*{
|
||||
invisible-xml($bookpages:grammar)($pages)/*
|
||||
};
|
||||
|
|
@ -2,12 +2,12 @@ xquery version '3.1';
|
|||
(:~
|
||||
pdfbox 3.0 https://pdfbox.apache.org/ BaseX 10.7+ interface library,
|
||||
requires pdfbox jar on classpath
|
||||
3.02 required tested with pdfbox-app-3.0.2-20240121.184204-66.jar
|
||||
3.02+ required tested with pdfbox-app-3.0.2.jar
|
||||
@see https://repository.apache.org/content/groups/snapshots/org/apache/pdfbox/pdfbox-app/3.0.2-SNAPSHOT/
|
||||
@javadoc https://javadoc.io/static/org.apache.pdfbox/pdfbox/3.0.0/
|
||||
|
||||
:)
|
||||
module namespace pdfbox="urn:expkg-zone58:pdfbox:3";
|
||||
module namespace pdfbox="urn:expkg-zone58:pdfbox3";
|
||||
|
||||
declare namespace Loader ="java:org.apache.pdfbox.Loader";
|
||||
declare namespace PDFTextStripper = "java:org.apache.pdfbox.text.PDFTextStripper";
|
||||
|
@ -96,7 +96,7 @@ as map(*)*{
|
|||
};
|
||||
|
||||
(: return bookmark info for children of $outlineItem as seq of maps :)
|
||||
declare function pdfbox:outline($doc,$outlineItem )
|
||||
declare function pdfbox:outline($doc as item(),$outlineItem as item()?)
|
||||
as map(*)*
|
||||
{
|
||||
let $find:=hof:until(
|
||||
|
@ -143,7 +143,7 @@ as map(*)
|
|||
}
|
||||
};
|
||||
|
||||
declare function pdfbox:outx($page,$document)
|
||||
declare function pdfbox:outx($page ,$document)
|
||||
{
|
||||
let $currentPage := PDOutlineItem:findDestinationPage($page,$document)
|
||||
let $pageNumber := pdfbox:pageIndex($currentPage,$document)
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
xquery version '3.1';
|
||||
(:~ look for pagenos in pdf text
|
||||
pagenos:page-report($doc )=>pagenos:inverted-map()
|
||||
pdfscrape:page-report($doc )=>pdfscrape:inverted-map()
|
||||
:)
|
||||
module namespace pagenos = 'urn:pageno';
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox:3" at "pdfbox3.xqm";
|
||||
module namespace pdfscrape = 'urn:pdfscrape';
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox3" at "pdfbox3.xqm";
|
||||
|
||||
(: look for possible page number in first/last line of page text
|
||||
@todo last line and roman
|
||||
1=Number system ( D=decimal, R=Roman)
|
||||
2=Side L=left,R=right
|
||||
:)
|
||||
declare variable $pagenos:pats:=map{
|
||||
declare variable $pdfscrape:pats:=map{
|
||||
"DL": "^([1-9][0-9]*).*",
|
||||
"DR": ".*[^0-9]([1-9][0-9]*)$",
|
||||
"RL": "^([ivxlc]+).*",
|
||||
|
@ -18,47 +18,56 @@ declare variable $pagenos:pats:=map{
|
|||
};
|
||||
|
||||
(: page-reports for all pages :)
|
||||
declare function pagenos:page-report($doc as item())
|
||||
declare function pdfscrape:page-report($doc as item())
|
||||
as element(page)*{
|
||||
let $count:=pdfbox:page-count($doc)=>trace("Pages: ")
|
||||
return (0 to $count -1)!pagenos:page-report($doc,.)
|
||||
return (1 to $count )!pdfscrape:page-report($doc,.)
|
||||
};
|
||||
|
||||
(: page-report for given page :)
|
||||
declare function pagenos:page-report($doc as item(), $page as xs:integer)
|
||||
declare function pdfscrape:page-report($doc as item(), $page as xs:integer)
|
||||
as element(page){
|
||||
let $txt:=pdfbox:getText($doc,$page)
|
||||
let $line1:=substring-before($txt,file:line-separator())
|
||||
let $fn:=function($acc,$this){ $acc otherwise pagenos:line-report($this,$line1)}
|
||||
let $found:=map:keys($pagenos:pats)=>fold-left( (),$fn)
|
||||
let $fn:=function($acc,$this){ $acc otherwise pdfscrape:line-report($this,$line1)}
|
||||
let $found:=map:keys($pdfscrape:pats)=>fold-left( (),$fn)
|
||||
|
||||
return <page index="{ $page }">{ $found, $line1 }</page>
|
||||
};
|
||||
|
||||
(: empty or attributes created by matching $style with $line1 :)
|
||||
declare function pagenos:line-report($style as xs:string, $line1 as xs:string)
|
||||
declare function pdfscrape:line-report($style as xs:string, $line1 as xs:string)
|
||||
as attribute(*)*{
|
||||
if(matches($line1,$pagenos:pats?($style)))
|
||||
if(matches($line1,$pdfscrape:pats?($style)))
|
||||
then (
|
||||
attribute {"style"} { substring($style,1,1) } ,(: 1st key:)
|
||||
attribute {"LR"} { substring($style,2,1) } ,(: 2nd key:)
|
||||
attribute {"number"} { replace($line1,$pagenos:pats?($style),"$1") }
|
||||
attribute {"number"} { replace($line1,$pdfscrape:pats?($style),"$1") }
|
||||
)
|
||||
};
|
||||
|
||||
(:~ keys are parsed pageno values are pageindices where found:)
|
||||
declare function pagenos:inverted-map($pages as element(page)*)
|
||||
declare function pdfscrape:inverted-map($pages as element(page)*)
|
||||
as map(*) {
|
||||
$pages[@number]!map:entry(string(@number),string(@index))
|
||||
=>map:merge(map{"duplicates":"combine"})
|
||||
};
|
||||
(:~ %match
|
||||
$l page labels
|
||||
:)
|
||||
declare function pdfscrape:score($l as xs:string*,$report as element(page)*)
|
||||
{
|
||||
let $s:=$report!(if(@number)then string(@number) else "")
|
||||
let $match:= for-each-pair($l,$s,function($l,$s){if($s eq "")then 0 else if ($s eq $l)then 1 else -1})
|
||||
return round(sum($match) div count($l) *100,0)
|
||||
};
|
||||
|
||||
(:~ convert roman to integer, zero if invalid
|
||||
@see https://joewiz.org/2021/05/30/converting-roman-numerals-with-xquery-xslt/
|
||||
:)
|
||||
declare function pagenos:decode-roman-numeral($roman-numeral as xs:string)
|
||||
declare function pdfscrape:decode-roman-numeral($roman-numeral as xs:string)
|
||||
as xs:integer{
|
||||
$roman-numeral => upper-case() => pagenos:characters()
|
||||
$roman-numeral => upper-case() => characters()
|
||||
=> for-each(map { "M": 1000, "D": 500, "C": 100, "L": 50, "X": 10, "V": 5, "I": 1 })
|
||||
=> fold-right([0,0], function($number,$accumulator) {
|
||||
if ($number lt $accumulator?2)
|
||||
|
@ -67,8 +76,3 @@ as xs:integer{
|
|||
=> array:head()
|
||||
};
|
||||
|
||||
(:~ xpath 4:)
|
||||
declare function pagenos:characters($value as xs:string?)
|
||||
as xs:string*{
|
||||
fn:string-to-codepoints($value) ! fn:codepoints-to-string(.)
|
||||
};
|
26
src/scratch/abc.xq
Normal file
26
src/scratch/abc.xq
Normal file
|
@ -0,0 +1,26 @@
|
|||
(: test use of pageIndex :)
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox:3" at "../src/lib/pdfbox3.xqm";
|
||||
import module namespace pagenos = 'urn:pageno' at "../src/lib/pageno.xqm";
|
||||
declare variable $base:=file:base-dir();
|
||||
declare function local:go($doc,$pdf as element(pdf)){
|
||||
let $range:=$pdf/@pages/tokenize(.,"–")
|
||||
let $start:=$range[1]
|
||||
let $end:=if(count($range) eq 1) then $range[1] else $range[2]
|
||||
|
||||
return ``[ `{$start}` ;;; `{ $end }` ]``
|
||||
};
|
||||
let $src:="257107---Book_File-Web_PDF_9798400691218_486731.pdf"=>file:resolve-path($base)
|
||||
let $doc:=pdfbox:open($src)
|
||||
let $labels:= pdfbox:getPageLabels($doc)
|
||||
let $pdfs:=doc("pdfs\chunks-docbook.xml")/chunks/pdf
|
||||
for $pdf in $pdfs
|
||||
let $range:=$pdf/@pages/tokenize(.,"–")
|
||||
let $start:=$range[1]
|
||||
let $end:=if(count($range) eq 1) then $range[1] else $range[2]
|
||||
let $startIndex:=index-of($labels,$start)
|
||||
let $endIndex:=index-of($labels,$end)
|
||||
return if(exists($startIndex) and exists($endIndex))
|
||||
then $pdf/@pages || " " || $startIndex || ":" || $endIndex
|
||||
(: pdfbox:extract($doc,$startIndex,$endIndex,file:resolve-path($pdf/@fileref,$base)) :)
|
||||
else $pdf/@pages
|
||||
|
20
src/scratch/nos.xq
Normal file
20
src/scratch/nos.xq
Normal file
|
@ -0,0 +1,20 @@
|
|||
(:~ describe book page numbering :)
|
||||
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox3" at "../lib/pdfbox3.xqm";
|
||||
import module namespace bookpages="urn:bookpages" at "../lib/bookpages.xqm";
|
||||
import module namespace pdfscrape="urn:pdfscrape" at "../lib/pdfscrape.xqm";
|
||||
|
||||
declare variable $base:="C:\Users\mrwhe\Desktop\1e\";
|
||||
declare variable $tests:=map{
|
||||
"simple":"20#C,R,7D",
|
||||
"set\2-6-2\A5267C": "1037#C,r,28D,520r:V2,526D@493",
|
||||
"gpg-book\2-3\A3581C-TRD": "848#C,r:Vol1:,28D,400r:Vol2:,438D@401"
|
||||
};
|
||||
let $pdf:=pdfbox:open("C:\Users\mrwhe\Desktop\1e\set\2-6-2\A5267C\257273---Book_File-Web_PDF_9798400612572_486638.pdf")
|
||||
let $l:=pdfbox:getPageLabels($pdf)
|
||||
|
||||
let $index:=bookpages:expand($tests?"set\2-6-2\A5267C")
|
||||
return pdfscrape:score($l,pdfscrape:page-report($pdf))
|
||||
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
(: PDFBOX experiments
|
||||
:)
|
||||
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox:3" at "../lib/pdfbox3.xqm";
|
||||
import module namespace pdfbox="urn:expkg-zone58:pdfbox3" at "../lib/pdfbox3.xqm";
|
||||
|
||||
|
||||
declare variable $samples:= map{
|
||||
|
|
87
src/webapp/pdf/app.xqm
Normal file
87
src/webapp/pdf/app.xqm
Normal file
|
@ -0,0 +1,87 @@
|
|||
(:~
|
||||
: Common RESTXQ access points.
|
||||
:
|
||||
: @author Christian Grün, BaseX Team 2005-23, BSD License
|
||||
:)
|
||||
module namespace pdf = 'pdf/common';
|
||||
|
||||
|
||||
|
||||
(:~
|
||||
: Redirects to the start page.
|
||||
: @return redirection
|
||||
:)
|
||||
declare
|
||||
%rest:path('/pdf')
|
||||
function pdf:home() as element() {
|
||||
web:forward('/pdf/static/index.html')
|
||||
};
|
||||
declare
|
||||
%rest:path('/pdf/{$file=.+}')
|
||||
function pdf:spa($file)as element(){
|
||||
pdf:home()
|
||||
};
|
||||
(:~ list slugs :)
|
||||
declare
|
||||
%rest:path('/pdf/api/sources')
|
||||
%output:method("json")
|
||||
%output:json("format=xquery")
|
||||
function pdf:apt()
|
||||
{
|
||||
let $base:="C:/Users/mrwhe/git/expkg-zone58/pdfbox/data/"
|
||||
let $d:="1e/"
|
||||
let $f:=file:list($base || $d,true(),"*.pdf")[not(contains(.,"\outputs\"))]
|
||||
return map{
|
||||
"count": count($f),
|
||||
"items": array{$f!map{"id":position(),"name":.}}
|
||||
}
|
||||
};
|
||||
|
||||
(:~
|
||||
: Returns a file.
|
||||
: @param $file file or unknown path
|
||||
: @return rest binary data
|
||||
:)
|
||||
declare
|
||||
%rest:path('/pdf/static/{$file=.+}')
|
||||
%output:method('basex')
|
||||
%perm:allow('public')
|
||||
function pdf:file(
|
||||
$file as xs:string
|
||||
) as item()+ {
|
||||
let $path := file:base-dir() || "static/" || $file
|
||||
return if(file:exists($path))
|
||||
then (
|
||||
web:response-header(
|
||||
map { 'media-type': web:content-type($path) },
|
||||
map { 'Cache-Control': 'max-age=3600,public', 'Content-Length': file:size($path) }
|
||||
),
|
||||
file:read-binary($path)
|
||||
)else
|
||||
web:forward("/pdf/api/404")
|
||||
|
||||
};
|
||||
|
||||
(:~
|
||||
: Shows a 'page not found' error.
|
||||
: @param $path path to unknown page
|
||||
: @return page
|
||||
:)
|
||||
declare
|
||||
%rest:path('/pdf/api/404')
|
||||
%output:method('html')
|
||||
function pdf:unknown(
|
||||
$path as xs:string
|
||||
) as element(*) {
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<h2>Page not found:</h2>
|
||||
<ul>
|
||||
<li>Page: dba/{ $path }</li>
|
||||
<li>Method: { request:method() }</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
};
|
15
src/webapp/pdf/readme.md
Normal file
15
src/webapp/pdf/readme.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
Uses
|
||||
* https://www.npmjs.com/package/slick-router
|
||||
<style>table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}</style>
|
||||
<table >
|
||||
<caption>Sample table</caption>
|
||||
<tr>
|
||||
<td>Foo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
</table>
|
53
src/webapp/pdf/static/animations.css
Normal file
53
src/webapp/pdf/static/animations.css
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* extracted from https://vuejs.org/v2/guide/transitions.html */
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Enter and leave animations can use different */
|
||||
/* durations and timing functions. */
|
||||
.slide-fade-enter-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
|
||||
}
|
||||
|
||||
.slide-fade-enter, .slide-fade-leave-to {
|
||||
transform: translateX(1000px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bounce-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bounce-enter-active {
|
||||
animation: bounce-in 0.8s;
|
||||
}
|
||||
|
||||
.bounce-leave-active {
|
||||
animation: bounce-in 0.8s reverse;
|
||||
}
|
||||
|
||||
@keyframes bounce-in {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
80% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
router-outlet > * {
|
||||
display: block;
|
||||
}
|
139
src/webapp/pdf/static/components.js
Normal file
139
src/webapp/pdf/static/components.js
Normal file
|
@ -0,0 +1,139 @@
|
|||
import { withRouterLinks } from 'https://unpkg.com/slick-router@2.5.0/middlewares/router-links.js'
|
||||
|
||||
class ApplicationView extends withRouterLinks(HTMLElement) {
|
||||
constructor() {
|
||||
super()
|
||||
this.addEventListener('change', e => {
|
||||
if (e.target.matches('#animation-type')) {
|
||||
const animation = e.target.value
|
||||
if (animation) {
|
||||
this.outlet.setAttribute('animation', e.target.value)
|
||||
} else {
|
||||
this.outlet.removeAttribute('animation')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback()
|
||||
this.innerHTML = `
|
||||
<div class='App'>
|
||||
<div class='App-header'>
|
||||
<h1>Application</h1>
|
||||
<ul class='Nav' routerlinks>
|
||||
<li class='Nav-item'><a route="home" >Home</a></li>
|
||||
<li class='Nav-item'><a route="messages">Messages</a></li>
|
||||
<li class='Nav-item'><a route="profile.index" param-user="scrobblemuch">Profile</a></li>
|
||||
<li class='Nav-item'><a route="settings" >Settings</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
<router-outlet animation="fade"></router-outlet>
|
||||
|
||||
<div class="App-footer">
|
||||
<div>
|
||||
Animation
|
||||
<select id="animation-type">
|
||||
<option value="">None</option>
|
||||
<option value="fade" selected>Fade</option>
|
||||
<option value="slide-fade">Slide Fade</option>
|
||||
<option value="bounce">Bounce</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`
|
||||
this.outlet = this.querySelector('router-outlet')
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('application-view', ApplicationView)
|
||||
|
||||
class HomeView extends withRouterLinks(HTMLElement) {
|
||||
connectedCallback() {
|
||||
super.connectedCallback()
|
||||
this.innerHTML = `
|
||||
<div class='Home' routerlinks>
|
||||
<h2>Tweets</h2>
|
||||
<div class='Tweet'>
|
||||
<div class='Tweet-author'>
|
||||
<a route="profile.index" param-user="dan_abramov">Dan Abramov @dan_abramov</a>
|
||||
</div>
|
||||
<div class='Tweet-time'>12m12 minutes ago</div>
|
||||
<div class='Tweet-content'>Another use case for \`this.context\` I think might be valid: forms. They're too painful right now.</div>
|
||||
</div>
|
||||
<div class='Tweet'>
|
||||
<div class='Tweet-author'>
|
||||
<a route="profile.index" param-user="afanasjevas">Eduardas Afanasjevas @afanasjevas</a>
|
||||
</div>
|
||||
<div class='Tweet-time'>12m12 minutes ago</div>
|
||||
<div class='Tweet-content'>I just published “What will Datasmoothie bring to the analytics startup landscape?” https://medium.com/@afanasjevas/what-will-datasmoothie-bring-to-the-analytics-startup-landscape-f7dab70d75c3?source=tw-81c4e81fe6f8-1427630532296</div>
|
||||
</div>
|
||||
<div class='Tweet'>
|
||||
<div class='Tweet-author'>
|
||||
<a route="profile.index" param-user="LNUGorg">LNUG @LNUGorg</a>
|
||||
</div>
|
||||
<div class='Tweet-time'>52m52 minutes ago</div>
|
||||
<div class='Tweet-content'> new talks uploaded on our YouTube page - check them out http://bit.ly/1yoXSAO</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('home-view', HomeView)
|
||||
|
||||
class MessagesView extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<div class='Messages'>
|
||||
<h2>Messages</h2>
|
||||
<p>You have no direct messages</p>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
customElements.define('messages-view', MessagesView)
|
||||
|
||||
class SettingsView extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<div class='Messages'>
|
||||
<h2>Sett</h2>
|
||||
<p>You have no direct messages</p>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
customElements.define('settings-view', SettingsView)
|
||||
|
||||
class ProfileView extends HTMLElement {
|
||||
static get outlet() {
|
||||
return '.Container'
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<div class='Profile'>
|
||||
<div class='Container'></div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('profile-view', ProfileView)
|
||||
|
||||
class ProfileIndexView extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<div class='ProfileIndex'>
|
||||
<h2>${this.$route.params.user} profile</h2>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('profile-index-view', ProfileIndexView)
|
BIN
src/webapp/pdf/static/favicon.png
Normal file
BIN
src/webapp/pdf/static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
18
src/webapp/pdf/static/index.html
Normal file
18
src/webapp/pdf/static/index.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<base href="/pdf/static/"/>
|
||||
<title>PDFS453 </title>
|
||||
|
||||
<link rel="icon" href="favicon.png">
|
||||
<script type="module" src="index.js"></script>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<link rel="stylesheet" href="animations.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
41
src/webapp/pdf/static/index.js
Normal file
41
src/webapp/pdf/static/index.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { Router } from 'https://unpkg.com/slick-router@2.5.0/slick-router.js?module'
|
||||
import { wc } from 'https://unpkg.com/slick-router@2.5.0/middlewares/wc.js'
|
||||
import { events } from 'https://unpkg.com/slick-router@2.5.0/middlewares/events.js'
|
||||
import { routerLinks } from 'https://unpkg.com/slick-router@2.5.0/middlewares/router-links.js'
|
||||
import { AnimatedOutlet } from 'https://unpkg.com/slick-router@2.5.0/components/animated-outlet.js'
|
||||
|
||||
import './components.js'
|
||||
|
||||
customElements.define('router-outlet', AnimatedOutlet)
|
||||
|
||||
// create the router
|
||||
const router = new Router({
|
||||
pushState: true,
|
||||
|
||||
log: true
|
||||
})
|
||||
|
||||
// provide your route map
|
||||
// in this particular case we configure components by its tag name
|
||||
|
||||
router.map(route => {
|
||||
route('application', { path: '/pdf/', component: 'application-view' }, () => {
|
||||
route('home', { path: '', component: 'home-view' })
|
||||
route('messages', { component: 'messages-view' })
|
||||
route('status', { path: ':user/status/:id' })
|
||||
route('profile', { path: 'profile/:user', component: 'profile-view' }, () => {
|
||||
route('profile.index', { path: '', component: 'profile-index-view' })
|
||||
route('profile.lists')
|
||||
route('profile.edit')
|
||||
})
|
||||
route('settings',{path: 'settings',component:'settings-view'})
|
||||
})
|
||||
})
|
||||
|
||||
// install middleware that will handle transitions
|
||||
router.use(wc)
|
||||
router.use(routerLinks)
|
||||
router.use(events)
|
||||
|
||||
// start listening to browser's location bar changes
|
||||
router.listen()
|
75
src/webapp/pdf/static/styles.css
Normal file
75
src/webapp/pdf/static/styles.css
Normal file
|
@ -0,0 +1,75 @@
|
|||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700');
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
.App {
|
||||
width: 800px;
|
||||
margin: 0 auto 20px auto;
|
||||
}
|
||||
|
||||
.App-header {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.App-header .active {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.App-footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
text-align: center;
|
||||
background-color: bisque;
|
||||
}
|
||||
|
||||
.App h1 {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Nav {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Nav-item {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Nav-item a {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.Tweet {
|
||||
border: 1px solid #eee;
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.Tweet:last-child {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.Tweet-author {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Tweet-time {
|
||||
color: #888;
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
router-outlet > * {
|
||||
display: block;
|
||||
}
|
47
src/webapp/pdf/static/summary-display.js
Normal file
47
src/webapp/pdf/static/summary-display.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
customElements.define('summary-display',
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const template = document.getElementById('summary-display-template');
|
||||
const templateContent = template.content;
|
||||
|
||||
const shadowRoot = this.attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(templateContent.cloneNode(true));
|
||||
|
||||
const items = Array.from(this.querySelectorAll('li'));
|
||||
const descriptions = Array.from(this.querySelectorAll('p'));
|
||||
|
||||
items.forEach(item => {
|
||||
handleClick(item);
|
||||
});
|
||||
|
||||
function handleClick(item) {
|
||||
item.addEventListener('click', function() {
|
||||
items.forEach(item => {
|
||||
item.style.backgroundColor = 'white';
|
||||
});
|
||||
|
||||
descriptions.forEach(description => {
|
||||
updateDisplay(description, item);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateDisplay(description, item) {
|
||||
description.removeAttribute('slot');
|
||||
|
||||
if(description.getAttribute('data-name') === item.textContent) {
|
||||
description.setAttribute('slot', 'choice');
|
||||
item.style.backgroundColor = '#bad0e4';
|
||||
}
|
||||
}
|
||||
|
||||
const slots = this.shadowRoot.querySelectorAll('slot');
|
||||
slots[1].addEventListener('slotchange', function(e) {
|
||||
const nodes = slots[1].assignedNodes();
|
||||
console.log(`Element in Slot "${slots[1].name}" changed to "${nodes[0].outerHTML}".`);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
Loading…
Add table
Reference in a new issue