diff --git a/.gitignore b/.gitignore index 84bfa3f..adbb97d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -abc/ \ No newline at end of file +data/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 06abc03..97714d5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "basexTools.xquery.profile": "basex-10" + "basexTools.xquery.profile": "basex-10", + "basexTools.xquery.showHovers": "false", + } \ No newline at end of file diff --git a/docs/pdfbox.xqbk b/docs/pdfbox.xqbk index 92162e3..9fbb506 100644 --- a/docs/pdfbox.xqbk +++ b/docs/pdfbox.xqbk @@ -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}`]``"}]} \ No newline at end of file +{"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 }`]``"}]} \ No newline at end of file diff --git a/src/lib/bookpages.xqm b/src/lib/bookpages.xqm new file mode 100644 index 0000000..a4edb34 --- /dev/null +++ b/src/lib/bookpages.xqm @@ -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)/* +}; + diff --git a/src/lib/pdfbox3.xqm b/src/lib/pdfbox3.xqm index 3c1c940..5702198 100644 --- a/src/lib/pdfbox3.xqm +++ b/src/lib/pdfbox3.xqm @@ -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) diff --git a/src/lib/pageno.xqm b/src/lib/pdfscrape.xqm similarity index 55% rename from src/lib/pageno.xqm rename to src/lib/pdfscrape.xqm index 2f9a65d..f5fe8c6 100644 --- a/src/lib/pageno.xqm +++ b/src/lib/pdfscrape.xqm @@ -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 { $found, $line1 } }; (: 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(.) -}; \ No newline at end of file diff --git a/src/scratch/abc.xq b/src/scratch/abc.xq new file mode 100644 index 0000000..2ff4ef1 --- /dev/null +++ b/src/scratch/abc.xq @@ -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 + diff --git a/src/scratch/nos.xq b/src/scratch/nos.xq new file mode 100644 index 0000000..b467d60 --- /dev/null +++ b/src/scratch/nos.xq @@ -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)) + + + diff --git a/src/scratch/pdfbox.xq b/src/scratch/pdfbox.xq index 747aae5..db0ebca 100644 --- a/src/scratch/pdfbox.xq +++ b/src/scratch/pdfbox.xq @@ -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{ diff --git a/src/webapp/pdf/app.xqm b/src/webapp/pdf/app.xqm new file mode 100644 index 0000000..0dab125 --- /dev/null +++ b/src/webapp/pdf/app.xqm @@ -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(*) { + + + +

Page not found:

+ + + + +}; diff --git a/src/webapp/pdf/readme.md b/src/webapp/pdf/readme.md new file mode 100644 index 0000000..a4e68c2 --- /dev/null +++ b/src/webapp/pdf/readme.md @@ -0,0 +1,15 @@ +Uses +* https://www.npmjs.com/package/slick-router + + + + + + + + + +
Sample table
Foo
3
\ No newline at end of file diff --git a/src/webapp/pdf/static/animations.css b/src/webapp/pdf/static/animations.css new file mode 100644 index 0000000..fad7e5c --- /dev/null +++ b/src/webapp/pdf/static/animations.css @@ -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; +} diff --git a/src/webapp/pdf/static/components.js b/src/webapp/pdf/static/components.js new file mode 100644 index 0000000..2c597e5 --- /dev/null +++ b/src/webapp/pdf/static/components.js @@ -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 = ` +
+
+

Application

+ + + +
+ + + + +
+ ` + this.outlet = this.querySelector('router-outlet') + } +} + +customElements.define('application-view', ApplicationView) + +class HomeView extends withRouterLinks(HTMLElement) { + connectedCallback() { + super.connectedCallback() + this.innerHTML = ` +
+

Tweets

+
+ +
12m12 minutes ago
+
Another use case for \`this.context\` I think might be valid: forms. They're too painful right now.
+
+
+ +
12m12 minutes ago
+
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
+
+
+ +
52m52 minutes ago
+
new talks uploaded on our YouTube page - check them out http://bit.ly/1yoXSAO
+
+
+ ` + } +} + +customElements.define('home-view', HomeView) + +class MessagesView extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+

Messages

+

You have no direct messages

+
+ ` + } +} +customElements.define('messages-view', MessagesView) + +class SettingsView extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+

Sett

+

You have no direct messages

+
+ ` + } +} +customElements.define('settings-view', SettingsView) + +class ProfileView extends HTMLElement { + static get outlet() { + return '.Container' + } + + connectedCallback() { + this.innerHTML = ` +
+
+
+ ` + } +} + +customElements.define('profile-view', ProfileView) + +class ProfileIndexView extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+

${this.$route.params.user} profile

+
+ ` + } +} + +customElements.define('profile-index-view', ProfileIndexView) diff --git a/src/webapp/pdf/static/favicon.png b/src/webapp/pdf/static/favicon.png new file mode 100644 index 0000000..1c0d0cb Binary files /dev/null and b/src/webapp/pdf/static/favicon.png differ diff --git a/src/webapp/pdf/static/index.html b/src/webapp/pdf/static/index.html new file mode 100644 index 0000000..63b5a28 --- /dev/null +++ b/src/webapp/pdf/static/index.html @@ -0,0 +1,18 @@ + + + + + + + + PDFS453 + + + + + + + + + + diff --git a/src/webapp/pdf/static/index.js b/src/webapp/pdf/static/index.js new file mode 100644 index 0000000..c597b1b --- /dev/null +++ b/src/webapp/pdf/static/index.js @@ -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() diff --git a/src/webapp/pdf/static/styles.css b/src/webapp/pdf/static/styles.css new file mode 100644 index 0000000..eeeeb6a --- /dev/null +++ b/src/webapp/pdf/static/styles.css @@ -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; +} diff --git a/src/webapp/pdf/static/summary-display.js b/src/webapp/pdf/static/summary-display.js new file mode 100644 index 0000000..474c22e --- /dev/null +++ b/src/webapp/pdf/static/summary-display.js @@ -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}".`); + }); + } + } +);