├── .existdb.json ├── .gitignore ├── README.md ├── build.properties ├── build.xml ├── cex-demo.html ├── collection.xconf ├── controller.xql ├── data.xconf ├── data ├── addresses │ ├── 0ff8612a-b998-4677-84a3-73e9ef84ba5f.xml │ ├── 19791b37-f546-4dc0-9bb4-ba3c36f9bb35.xml │ ├── 2895645b-d16f-415e-a99a-a4504faaa6c2.xml │ ├── 49ce9014-b1b2-4d30-acd8-601349e5e1a2.xml │ ├── 75a7170b-ad64-47ac-9b54-59ad50b6c47d.xml │ ├── 7db9a6b3-6f06-4205-b4de-4f906ec9fd94.xml │ └── abbcc652-0665-4f9d-9df5-c2c96aaf3c51.xml ├── binary │ └── README ├── hamlet.xml ├── i18n │ ├── collection_de.xml │ └── collection_es.xml ├── macbeth.xml ├── mondial.xml ├── r_and_j.xml └── shakes.xsl ├── error-page.html ├── examples ├── basic │ ├── ConvertItems.xsl │ ├── DemoValidation-Invalid.xml │ ├── DemoValidation-Valid.xml │ ├── DemoValidation.xsd │ ├── Items.xml │ ├── basics.html │ ├── fulltext.html │ ├── functions.html │ ├── groupby.html │ ├── hello.html │ ├── hof.html │ ├── htmlgenerate.html │ ├── maps.html │ ├── mondial.html │ ├── switch.html │ ├── trycatch.html │ ├── validation.html │ ├── xq3operators.html │ ├── xquery3.html │ └── xslt.html ├── contacts │ ├── contacts.xql │ ├── data │ │ └── e19316b0-af33-4c1c-88e3-9ddd5b03c239.xml │ ├── html │ │ ├── browseContacts.html │ │ ├── home.html │ │ ├── newContact.html │ │ └── updateContact.html │ └── js │ │ ├── angular-animate.min.js │ │ ├── angular-resource.min.js │ │ ├── angular-route.min.js │ │ ├── angular-spinner.min.js │ │ ├── angular.min.js │ │ ├── app.js │ │ ├── jquery-2.1.0.min.js │ │ └── spin.min.js ├── special │ ├── i18n-docs.html │ ├── i18n.html │ ├── index.html │ ├── json.html │ └── json.xql ├── templating │ ├── examples.xql │ ├── restxq-demo.xql │ ├── restxq-page.html │ └── templates.html ├── tests │ ├── shakespeare-tests.xql │ ├── shakespeare.xql │ └── test.html ├── urlrewriting │ ├── bad-page.html │ ├── index.html │ ├── login.html │ └── protected.html ├── web │ ├── guess-templates.xql │ ├── guess.html │ ├── guess.xql │ ├── index.html │ ├── shakespeare-ajax.html │ ├── shakespeare.html │ └── shakespeare.xql └── xforms │ ├── controller.xql │ ├── demo.html │ └── restxq-demo.xql ├── expath-pkg.xml.tmpl ├── icon.png ├── index.html ├── modules ├── cex-trigger.xql ├── cex.xql ├── config.xqm ├── demo.xql ├── i18n-templates.xql ├── i18n.xql └── view.xql ├── post-install.xql ├── pre-install.xql ├── repo.xml ├── resources ├── css │ └── demo.css ├── images │ ├── ajax-loader.gif │ ├── bold.gif │ ├── code.gif │ ├── delete-icon.png │ ├── eXide-screenshot.png │ ├── glyphicons-halflings.png │ ├── grey-box-bot.gif │ ├── grey-box-rpt.gif │ ├── grey-box-top.gif │ ├── italic.gif │ ├── nav-dropdown.gif │ ├── nav-dropdown.png │ ├── nav.gif │ ├── page-edit-icon.png │ ├── twitter-left.gif │ ├── twitter-right.gif │ └── twitter-rpt.gif └── scripts │ ├── bootstrap.min.js │ └── demo.js └── templates └── page.html /.existdb.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers": { 3 | "localhost": { 4 | "server": "http://localhost:8080/exist", 5 | "user": "admin", 6 | "password": "" 7 | } 8 | }, 9 | "sync": { 10 | "server": "localhost", 11 | "root": "/db/apps/demo", 12 | "active": true, 13 | "ignore": [ 14 | ".existdb.json", 15 | ".git/**" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | expath-pkg.xml 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | eXist XQuery Features Demo 2 | ========= 3 | 4 | "Seeing is believing." 5 | 6 | This application contains various small demos for particular eXist features: 7 | 8 | - Basic XQuery Examples 9 | - XQuery 3.0 Examples 10 | - Web Examples 11 | - URL Rewriting 12 | - Special Features 13 | - Templating 14 | - Content Extraction 15 | - Unit Testing 16 | - XForms and RestXQ 17 | - RestXQ and AngularJS 18 | 19 | Live demo on http://demo.exist-db.org/exist/apps/demo/ 20 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Don't directly modify this file. Instead, copy it to local.build.properties and 3 | # edit that. 4 | # 5 | 6 | project.name=demo 7 | project.version=0.4.4 8 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /cex-demo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Content Extraction and Binary Resource Indexing

4 |
5 |
6 |

The content extraction module does not appear to be available in your eXist installation. 7 | To enable it, stop eXist, edit $EXIST_HOME/extensions/build.properties and set the corresponding property to true:

8 |
 9 | # Binary Content and Metadata Extraction Module
10 | include.feature.contentextraction = true
11 |

Next, call build.sh/build.bat from eXist's top directory to build the module. You should see in the output how the various 12 | libraries required are downloaded and installed.

13 |
14 |
15 |

This page demonstrates how to query binary documents which have been indexed with Lucene after 16 | their text content has been extracted. The app defines a trigger on the "binary" collection below the "data" collection in the 17 | app root collection. To test the indexing, upload a pdf to the collection and its contents 18 | will be extracted and indexed automatically.

19 |
20 | 21 | 22 | 23 | 26 | 27 | 28 |
29 |
30 |
31 |
32 | 36 |
-------------------------------------------------------------------------------- /collection.xconf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /controller.xql: -------------------------------------------------------------------------------- 1 | xquery version "1.0"; 2 | 3 | import module namespace request="http://exist-db.org/xquery/request"; 4 | import module namespace xdb = "http://exist-db.org/xquery/xmldb"; 5 | import module namespace login="http://exist-db.org/xquery/login" at "resource:org/exist/xquery/modules/persistentlogin/login.xql"; 6 | 7 | declare variable $exist:path external; 8 | declare variable $exist:resource external; 9 | declare variable $exist:controller external; 10 | declare variable $exist:prefix external; 11 | 12 | if ($exist:path eq "") then 13 | 14 | 15 | 16 | 17 | else if ($exist:path eq "/") then 18 | 19 | 20 | 21 | 22 | (: Protected resource: user is required to log in with valid credentials. 23 | If the login fails or no credentials were provided, the request is redirected 24 | to the login.html page. :) 25 | else if ($exist:resource eq 'protected.html') then ( 26 | login:set-user("org.exist.demo.login", (), false()), 27 | if (request:get-attribute("org.exist.demo.login.user")) then 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | else 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ) 49 | 50 | (: Pass all requests to HTML files through view.xql, which handles HTML templating :) 51 | else if (ends-with($exist:resource, ".html")) then 52 | 53 | 54 | 55 | {login:set-user("org.exist.demo.login", (), false())} 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | else if (ends-with($exist:resource, ".xql")) then 68 | 69 | 70 | 71 | 72 | else if (contains($exist:path, "/$shared/")) then 73 | 74 | 75 | 76 | 77 | 78 | 79 | (: images, css are contained in the top /resources/ collection. :) 80 | (: Relative path requests from sub-collections are redirected there :) 81 | else if (contains($exist:path, "/resources/")) then 82 | 83 | 84 | 85 | 86 | 87 | 88 | else 89 | 90 | 91 | -------------------------------------------------------------------------------- /data.xconf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /data/addresses/0ff8612a-b998-4677-84a3-73e9ef84ba5f.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Biene Maja 4 | Wiesenweg 33 5 | Berlin 6 |
-------------------------------------------------------------------------------- /data/addresses/19791b37-f546-4dc0-9bb4-ba3c36f9bb35.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Elsa Elster 4 | Vogelstraße 22 5 | Mainz 6 |
-------------------------------------------------------------------------------- /data/addresses/2895645b-d16f-415e-a99a-a4504faaa6c2.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Berta Muh 4 | An der Viehtränke 13 5 | Wiesbaden 6 |
-------------------------------------------------------------------------------- /data/addresses/49ce9014-b1b2-4d30-acd8-601349e5e1a2.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Hans Hase 4 | Feldstraße 44 5 | Wiesbaden 6 |
-------------------------------------------------------------------------------- /data/addresses/75a7170b-ad64-47ac-9b54-59ad50b6c47d.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Linda Klaus 4 | Kopfstraße 5 5 | Heidelberg 6 |
-------------------------------------------------------------------------------- /data/addresses/7db9a6b3-6f06-4205-b4de-4f906ec9fd94.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Rudi Rüssel 4 | An der Viehtränke 24 5 | Frankfurt 6 |
-------------------------------------------------------------------------------- /data/addresses/abbcc652-0665-4f9d-9df5-c2c96aaf3c51.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | Lothar Lärche 4 | Vogelstraße 67 5 | Mainz 6 |
-------------------------------------------------------------------------------- /data/binary/README: -------------------------------------------------------------------------------- 1 | Drop a PDF into this collection to have its contents indexed. 2 | -------------------------------------------------------------------------------- /data/i18n/collection_de.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | i18n Demo Anwendung 4 | Willkommen {username} bei der i18n Demo Anwendung 5 | zu übersetzender Text 6 | Einfachen Text übersetzen 7 | Text mit einfachen Properties übersetzen 8 | Zu übersetzender Text mit {2} Parametern zum Ersetzen (in {1} Reihenfolge) 9 | Zu übersetzender Text mit {number} Parametern zum Ersetzen (nach {alphabetical} Schlüsseln) 10 | Zu übersetzender Text mit zu {1} 11 | Zu übersetzender Text mit zu {translatedParameter} 12 | übersetzenden Parametern 13 | Attribute übersetzen 14 | HTML DIV mit einer lokalisierten CSS Klasse und einem lokalisierten 'name' Attribut 15 | Schlüssel1 16 | Schlüssel2 17 | 18 | 19 | eXist i18n Dokumentation 20 | Einleitung 21 | -------------------------------------------------------------------------------- /data/i18n/collection_es.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | i18n Demo Aplicación 4 | Bienvenida {username} a la i18n Demo Aplicación 5 | Texto por traducir 6 | Traducir simple texto 7 | Traducir simple texto con parámetros 8 | Traducir simple texto con {2} parámetros (a '{1}' orden) 9 | Traducir simple texto con {number} parámetros (a '{alphabetical}' orden) 10 | Traducir texto con {1} 11 | Traducir texto con {translatedParameter} 12 | parámetros por traducir 13 | Traducir attributos 14 | Español Attribut 15 | llavae1 16 | llavae2 17 | -------------------------------------------------------------------------------- /data/shakes.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 | 6 |

7 |
8 | 9 |
10 | 11 | 12 | 13 |

14 | Table of Contents 15 |

16 | 34 | 35 | 36 |
37 |
38 | 39 |
40 | 41 |
42 |
43 | 44 |
45 |

46 | 47 | 48 | 49 | 50 | 51 | 52 |

53 | 54 | 55 |
56 |
57 | 58 |
59 |

60 | 61 | 62 | 63 | 64 | 65 | 66 |

67 | 68 |
69 | 70 |

71 | 72 | 73 | 74 | 75 | 76 | 77 |

78 | 79 |
80 | 81 | 82 | 83 | 88 | 94 | 95 |
84 |
85 | 86 |
87 |
89 | 90 | 91 | 92 | 93 |
96 |
97 | 98 | 99 |
100 |
101 | 102 | 103 |
104 |
105 | [ 106 | 107 | ] 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |

121 | 122 |

123 | 124 | 125 |
126 | 127 |

128 | 129 | 130 | 131 |

132 |
133 | 134 |
135 | 136 |
137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 |
152 | 153 | 154 | 155 | 156 | 157 |
158 | 159 | 160 | 161 | 162 |
163 |
164 |
-------------------------------------------------------------------------------- /error-page.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

An error has occurred

4 |

An error has been generated by the application.

5 |
6 |     
9 | 
-------------------------------------------------------------------------------- /examples/basic/ConvertItems.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Item overview

6 |
    7 | 8 |
  • 9 | : 10 |
  • 11 |
    12 |
13 | 14 |
15 |
-------------------------------------------------------------------------------- /examples/basic/DemoValidation-Invalid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Line 1 4 | Line 2 5 | Something extra that shouldn't be there! 6 | -------------------------------------------------------------------------------- /examples/basic/DemoValidation-Valid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Line 1 4 | Line 2 5 | -------------------------------------------------------------------------------- /examples/basic/DemoValidation.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Very simple schema to demonstrate eXist's validation capabilities 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/basic/Items.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a complete bogus item 4 | Ha, ha, very funny indeed! 5 | -------------------------------------------------------------------------------- /examples/basic/basics.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Basic XQuery Examples

4 |

This page contains a collection of simple XQuery examples which should give a first glimpse of what's possible 5 | with eXist and XQuery. To learn more about XQuery, we recommend to head over to the excellent 6 | XQuery Wikibook or buy one of the available books 7 | on XQuery.

8 |

Though the syntactic elements of XQuery can be learned quickly, it is a functional language and it may 9 | take some time to get a feel for it if you are coming from a procedural world.

10 |
    11 |
  1. 12 | Basic XQuery 13 |
  2. 14 |
  3. 15 | Analyze data 16 |
  4. 17 |
  5. Writing functions 18 |
  6. 19 |
  7. Generate HTML output 20 |
  8. 21 |
  9. Using the full text index 22 |
  10. 23 |
  11. Transforming XML with XSLT 24 |
  12. 25 |
  13. 26 | Validate a document programmatically
  14. 27 |
28 |
-------------------------------------------------------------------------------- /examples/basic/fulltext.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Simple expressions using the full-text index

4 |
5 |

Find out where Juliet talks about love

6 |

In the following, Jon Bosak's edition of the Shakespeare's Hamlet, Macbeth, and Romeo and Juilet are queried..

7 |
 8 |     //SPEECH[ft:query(., 'love')][SPEAKER = "JULIET"]
 9 |             
10 |
11 |
12 |

Search for a phrase

13 |
14 |     //SPEECH[ft:query(., '"fenny snake"')]
15 | 
16 |
17 |
18 |

Find speeches in which "love" and "father" occur closely together, using XML query syntax:

19 |
20 | let $query :=
21 |     <query>
22 |         <near slop="20"><term>love</term><near>father</near></near>
23 |     </query>
24 | return //SPEECH[ft:query(., $query)]
25 |             
26 |
27 |
28 |

Find speeches in which "boil" and "bubble" occur, ordering them by full-text match score

29 |
30 | for $m in //SPEECH[ft:query(., "boil bubble")]
31 | let $score := ft:score($m)
32 | order by $score descending
33 | return <m score="{$score}">{$m}</m>
34 | 
35 |
36 |
-------------------------------------------------------------------------------- /examples/basic/functions.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Functions and recursion

4 |
5 |

Simple function with two parameters

6 |
 7 | xquery version "3.0";
 8 | 
 9 | declare function local:greet($name as xs:string, $lang as xs:string?) as xs:string {
10 |     if ($lang = "de") then
11 |         "Hallo " || $name
12 |     else if ($lang = "es") then
13 |         "Hola " || $name
14 |     else
15 |         "Hello " || $name
16 | };
17 | 
18 | local:greet("Susi", "de"),
19 | local:greet("Susi", "es"),
20 | local:greet("Susi", "en"),
21 | local:greet("Susi", ())
22 |
23 |
24 |

Recursion: compute the factorial of a given integer

25 |
26 | xquery version "1.0";
27 | 
28 | declare function local:fact($n as xs:integer) {
29 |     if ($n eq 1) then
30 |         $n
31 |     else
32 |         $n * local:fact($n - 1)
33 | };
34 | 
35 | local:fact(6)
36 |         
37 |
38 |
-------------------------------------------------------------------------------- /examples/basic/groupby.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Group by

4 |
5 |

Output odd and even numbers

6 |
{$n}
13 |     else
14 |         {$n}]]>
15 |
16 |
17 |

Run full text search on Shakespeare and group results by speaker

18 |
xquery version "3.0";
19 | 
20 | let $query := "king"
21 | for $speechBySpeaker in //SPEECH[ft:query(., $query)]
22 | group by $speaker := $speechBySpeaker/SPEAKER
23 | order by $speaker
24 | return
25 |     <speaker name="{$speaker}">
26 |     { $speechBySpeaker }
27 |     </speaker>
28 |
29 |
30 |

Group results by speaker and scene

31 |
xquery version "3.0";
32 | 
33 | let $query := "poison"
34 | for $speechBySpeaker in //SPEECH[ft:query(., $query)]
35 | group by $speaker := $speechBySpeaker/SPEAKER
36 | order by $speaker
37 | return
38 |     <ul>
39 |         <li>
40 |             <h3>{$speaker/text()}</h3>
41 |             <ul>
42 |             {
43 |                 for $speech in $speechBySpeaker
44 |                 group by $scene := $speech/ancestor::SCENE/TITLE
45 |                 return
46 |                     <li>
47 |                         <h4>{$scene/text()}</h4>
48 |                         <ul>
49 |                         {
50 |                             for $line in util:expand($speech)/LINE[exist:match]
51 |                             return
52 |                                 <li>
53 |                                 {
54 |                                     for $node in $line/node()
55 |                                     return
56 |                                         typeswitch($node)
57 |                                             case element(exist:match) return
58 |                                                 <mark>{$node/text()}</mark>
59 |                                             default return
60 |                                                 $node
61 |                                 }
62 |                                 </li>
63 |                         }
64 |                         </ul>
65 |                     </li>
66 |             }
67 |             </ul>
68 |         </li>
69 |     </ul>
70 |
71 |
-------------------------------------------------------------------------------- /examples/basic/hello.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Basic XQuery

4 |
5 |

Basic Hello World

6 |

11 |      {$msg}
12 |   ]]>
13 |
14 |
15 |

Querying a Document

16 |
19 |
20 |
21 |

Querying a Collection

22 |
25 |
26 |
27 |

Find all speech elements in Shakespeare with a line containing "hurlyburly"

28 |
30 |
31 |
32 |

List all speakers appearing in scene 2 of the first act of Hamlet

33 |
35 |
36 |
-------------------------------------------------------------------------------- /examples/basic/hof.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Higher-order Functions

4 |
5 |

Passing an inline function as parameter

6 |
xquery version "3.0";
  7 | 
  8 | declare namespace ex="http://exist-db.org/xquery/ex";
  9 | 
 10 | declare function ex:apply($func, $list) {
 11 |     for $item in $list return $func($item)
 12 | };
 13 | 
 14 | (: Create an inline function and assign it to $f2 :)
 15 | let $f2 := function($a) { upper-case($a) }
 16 | return
 17 |        ex:apply($f2, ("Hello", "world!"))
 18 |             
19 |
20 |
21 |

Using a named function reference

22 |
xquery version "3.0";
 23 | 
 24 | declare namespace ex="http://exist-db.org/xquery/ex";
 25 | 
 26 | declare function ex:apply($func as function(item()) as item()*, $list) {
 27 |     for $item in $list return $func($item)
 28 | };
 29 | 
 30 | (: Use function reference literal to find function at compile time :)
 31 | let $fApply := ex:apply#2
 32 | return
 33 |        $fApply(function($a) { upper-case($a) }, ("Hello", "world!"))
 34 |             
35 |
36 |
37 |

Using a dynamic function lookup

38 |
 39 | xquery version "3.0";
 40 | 
 41 | declare namespace ex="http://exist-db.org/xquery/ex2";
 42 | 
 43 | declare function ex:fold-left(
 44 |         $f as function(item()*, item()) as item()*, 
 45 |         $zero as item()*, 
 46 |         $seq as item()*) as item()* {
 47 |     if (fn:empty($seq)) then $zero
 48 |     else ex:fold-left($f, $f($zero, $seq[1]), subsequence($seq, 2))
 49 | };
 50 | 
 51 | (: Function reference is resolved dynamically at runtime :)
 52 | let $foldLeft := function-lookup(xs:QName("ex:fold-left"), 3)
 53 | return
 54 |     $foldLeft(function($a, $b) { $a * $b}, 1, 1 to 5)
 55 |             
56 |
57 |
58 |

Basic higher-order functions

59 |

The default function library provides a number of basic functions which take function items as arguments:

60 |
    61 |
  • for-each
  • 62 |
  • filter
  • 63 |
  • fold-left
  • 64 |
  • fold-right
  • 65 |
  • for-each-pair
  • 66 |
67 |
68 |

fn:for-each

69 |
 70 | for-each(1 to 5, function($a) { $a * $a })
 71 |             
72 |
73 |
74 |

fn:filter

75 |
fn:filter(1 to 10, function($a) {$a mod 2 = 0})
76 |
77 |
78 |
79 |

Closures

80 |
81 |

Inline function using variable from local context

82 |
 83 | xquery version "3.0";
 84 | 
 85 | declare function local:apply($names as xs:string*, $f as function(xs:string) as xs:string) {
 86 |     for $name in $names
 87 |     return
 88 |         $f($name)
 89 | };
 90 | 
 91 | let $string := "Hello "
 92 | let $f := function($name as xs:string) {
 93 |     (: $string will be copied into the functions context :)
 94 |     $string || $name
 95 | }
 96 | return
 97 |     local:apply(("Hans", "Rudi"), $f)
 98 |             
99 |
100 |
101 |
102 |

Partial function application

103 |

When passing functions as arguments, it is often useful to be able to set certain fixed parameters when creating 104 | the function reference. XQuery 3.0 allows this using ? as an argument placeholder.

105 |
106 |

Multiply each item in a sequence with a base value

107 |
108 | xquery version "3.0";
109 |             
110 | declare namespace ex="http://exist-db.org/xquery/ex";
111 | 
112 | declare function ex:multiply($base, $number) {
113 |     $base * $number
114 | };
115 | 
116 | let $fMultiply := ex:multiply(10, ?)
117 | return
118 |     for-each(1 to 10, $fMultiply)
119 |             
120 |
121 |
122 |
-------------------------------------------------------------------------------- /examples/basic/htmlgenerate.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Generating HTML

4 |
5 |

Create a 10x10 table and color the cells

6 |
  7 | xquery version "1.0";
  8 | (: $Id: table.xq 6434 2007-08-28 18:59:23Z ellefj $ :)
  9 | (: An example found in Saxon: creates a table with 10x10 cells :)
 10 | 
 11 | declare namespace f="http://my-namespaces.org";
 12 | 
 13 | declare function f:background-color($x as xs:double, $y as xs:integer)
 14 | as xs:string {    
 15 |     if($x mod 2 + $y mod 2 <= 0) then "lightgreen"
 16 | 	else if($y mod 2 <= 0) then "yellow"
 17 | 	else if($x mod 2 <= 0) then "lightblue"
 18 | 	else "white"
 19 | };
 20 | 
 21 | <body>
 22 | 	<table>{
 23 | 	for $y in 1 to 10 return
 24 | 		<tr>
 25 | 		{
 26 | 			for $x in 1 to 10 return
 27 | 				let $bg := f:background-color($x, $y),
 28 | 					$prod := $x * $y
 29 | 				return
 30 | 					<td bgcolor="{$bg}">
 31 | 						{if ($y > 1 and $x > 1) then $prod else <b>{$prod}</b>}
 32 | 					</td>
 33 | 		}
 34 | 		</tr>
 35 | 	}</table>
 36 | </body>
 37 |             
38 |
39 |
40 |

Create a multiplication table

41 |
 42 | xquery version "1.0";
 43 | declare option exist:serialize "method=html5 media-type=text/html";
 44 | declare variable $max := 20;
 45 | 
 46 | <table border="1" width="100%">
 47 |     <th>1 x 1</th>
 48 |     {
 49 |         for $i in (1 to $max)
 50 |         return
 51 |             <th>{ $i}</th>
 52 |     }
 53 |       
 54 |     {
 55 |         for $a in (1 to $max)  
 56 |         return 
 57 |             <tr>
 58 |                 <th>{ $a,"*"}</th>
 59 |                 
 60 |                 {
 61 |                     for $b in (1 to $max)
 62 |                     return
 63 |                         if ($a = $b) then
 64 |                             <td bgcolor="#F46978">{$a * $b}</td>
 65 |                         else if ($a mod 2) then
 66 |                             <td bgcolor="#A46978">{$a * $b}</td> 
 67 |                         else
 68 |                             <td bgcolor="#A09224">{$a * $b}</td> 
 69 |                 }            
 70 |             </tr>
 71 |   
 72 |     }
 73 | </table>
74 |
75 |
76 |

Generate a list of the acts and scenes in Hamlet, with the roles appearing in each scene

77 |
 78 | declare option exist:serialize "method=html5 media-type=text/html";
 79 | 
 80 | <html>
 81 |     <body>{
 82 |         for $act in doc("/db/apps/demo/data/hamlet.xml")/PLAY/ACT
 83 |         return
 84 |             <ul>
 85 |                 <li>
 86 |                     <h2>{$act/TITLE/text()}</h2>
 87 |                     <ul>
 88 |                     {
 89 |                         for $scene in $act/SCENE return
 90 |                             <li>
 91 |                                 <h3>{$scene/TITLE/text()}</h3>
 92 |                                 <ul>
 93 |                                 {
 94 |                                     for $speaker in distinct-values($scene//SPEAKER)
 95 |                                     order by $speaker return
 96 |                                         <li>{$speaker}</li>
 97 |                                 }
 98 |                                 </ul>
 99 |                             </li>
100 |                     }
101 |                     </ul>
102 |                 </li>
103 |             </ul>
104 |     }</body>
105 | </html>
106 | 
107 |
108 |
-------------------------------------------------------------------------------- /examples/basic/maps.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Maps in XQuery 3.1

4 |

Please note that maps are part of the XQuery 3.1 specification, which is still subject to change. eXist is trying to preserve 5 | backwards compatibility as far as possible. You may thus find that some apps are still using the older notation "key:=value" 6 | instead of "key:value" for the map constructor.

7 |

See the function documentation 8 | for a list of all functions.

9 |
10 |

Day of week

11 |
let $week := map {0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
12 | return
13 |     $week(3)
14 |
15 |
16 |

Lookup operator

17 |
xquery version "3.0";
18 | 
19 | let $week := map 
20 |     {"sunday": "Sonntag", "monday": "Montag", "tuesday": "Dienstag", 
21 |     "wednesday": "Mittwoch", "thursday": "Donnerstag", 
22 |     "friday": "Freitag", "saturday": "Samstag"}
23 | return
24 |     $week?thursday
25 |
26 |
27 |

Map using date as key

28 |
<table class="table table-striped">
29 | {
30 |     let $birthdays := map {
31 |             xs:date("1975-03-19") : "Uschi",
32 |             xs:date("1980-01-22") : "Verona",
33 |             xs:date("1960-06-14") : "Heinz",
34 |             xs:date("1963-10-21") : "Roland"
35 |     }
36 |     for $key in map:keys($birthdays)
37 |     let $name := $birthdays($key)
38 |     order by $name ascending
39 |     return
40 |         <tr>
41 |             <td>{$name}</td>
42 |             <td>{format-date($key, "[MNn] [D00], [Y0000]")}</td>
43 |         </tr>
44 | }
45 | </table>
46 |
47 |
48 |

map:for-each-entry

49 |
<table class="table table-striped">
50 | {
51 |     let $birthdays := map {
52 |             xs:date("1975-03-19") : "Uschi",
53 |             xs:date("1980-01-22") : "Verona",
54 |             xs:date("1960-06-14") : "Heinz",
55 |             xs:date("1963-10-21") : "Roland"
56 |     }
57 |     return
58 |         map:for-each-entry($birthdays, function($date, $name) {
59 |             <tr>
60 |                 <td>{$name}</td>
61 |                 <td>{format-date($date, "[MNn] [D00], [Y0000]")}</td>
62 |             </tr>
63 |         })
64 | }
65 | </table>
66 |
67 |
-------------------------------------------------------------------------------- /examples/basic/mondial.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Analyze Data

4 |

The following queries use the Mondial 5 | database, a data set compiled by the Universität Göttingen.

6 |
7 |

For each country, list the 3 cities with the highest population

8 |
 9 | (:  This script accesses the mondial database, which can be
10 |     found at http://dbis.informatik.uni-goettingen.de/Mondial/ :)
11 | for $country in /mondial/country
12 | let $cities := 
13 |     (for $city in $country//city[population] 
14 |     order by xs:integer($city/population[1]) descending 
15 |     return $city)
16 | order by $country/name
17 | return
18 |     <country name="{$country/name}">
19 |     {
20 |         subsequence($cities, 1, 3)
21 |     }
22 |     </country>
23 |
24 |
25 |

Find all Spanish provinces and their cities

26 |
27 | xquery version "1.0";
28 | 
29 | let $country := /mondial/country[name = 'Spain']
30 | for $province in $country/province
31 | order by $province/name
32 | return
33 |     <province>
34 |         {$province/name}
35 | 		{
36 | 			for $city in $country//city[@province=$province/@id]
37 | 			order by $city/name
38 | 			return $city
39 | 		}
40 | 	</province>
41 |             
42 |
43 |
44 |

Find the countries with the largest Roman Catholic population

45 |
46 | for $country in /mondial/country
47 | where some $r in $country/religions satisfies $r = "Roman Catholic"
48 | order by $country/religions[. = "Roman Catholic"]/@percentage cast as xs:double descending
49 | return
50 |   <country name="{$country/name}">
51 |     {$country/religions}
52 |   </country>
53 | 
54 |
55 |
-------------------------------------------------------------------------------- /examples/basic/switch.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Switch statements

4 |
 5 | xquery version "3.0";
 6 | 
 7 | let $animal := "Duck"
 8 | return
 9 | switch ($animal)
10 |    case "Cow" return "Moo"
11 |    case "Cat" return "Meow"
12 |    case "Duck" return "Quack"
13 |    case "Dog" case "Pitbull" return "Wuff"
14 |    default return "What's that odd noise?"
15 |     
16 |
-------------------------------------------------------------------------------- /examples/basic/trycatch.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Try/Catch

4 |
5 |

Basic example catching any errors:

6 |
xquery version "3.0";
 7 | 
 8 |     let $x := "Hello"
 9 |     return
10 |     try {
11 |         $x cast as xs:integer
12 |     } catch * {
13 |         <error>Caught error {$err:code}: {$err:description}</error>
14 |         }
15 |
16 |
17 |

Generating your own errors:

18 |
xquery version "3.0";
19 |     
20 | declare namespace app="http://exist-db.org/myapp";
21 | 
22 | declare variable $app:ERROR := xs:QName("app:error");
23 | 
24 | try {
25 |     error($app:ERROR, "Ooops", "any data")
26 | } catch app:error {
27 |     <error>Caught error {$err:code}: {$err:description}. Data: {$err:value}.</error>
28 | }
29 |
30 |
-------------------------------------------------------------------------------- /examples/basic/validation.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Validation

4 |
5 |

Programmatically validate an XML document

6 |

13 |         
14 |         {
15 |             validation:validate-report($xml-valid, $schema)
16 |         }
17 |         
18 |         
19 |         {
20 |             validation:validate-report($xml-invalid, $schema)
21 |         }
22 |         
23 |     ]]>
24 |
25 |
-------------------------------------------------------------------------------- /examples/basic/xq3operators.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

String concatenation and bang operators

4 |
5 |

String concatenation

6 |
xquery version "3.0";
 7 | 
 8 | let $who := "world"
 9 | return
10 |     "Hello " || $who || "!"
11 |         
12 |
13 |
14 |

Bang operator

15 |

Can be used instead of simple for expressions. The expression to the right of the operator is evaluated once for 16 | each item in the left-hand sequence, setting the context item to the current item.

17 |
xquery version "3.0";
18 | 
19 | ("Hello", "world") ! upper-case(.)
20 |
21 |
-------------------------------------------------------------------------------- /examples/basic/xquery3.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

XQuery 3.0 (and 3.1) Features

4 |

XQuery 3.0 has been released as a working draft in December 2011. The new XQuery 3.0 specification 5 | standardizes many of the features which had been available as extension modules in eXist and other 6 | implementations for quite a while, for example: higher-order functions, try/catch or group by.

7 |

eXist also supports parts of the forthcoming XQuery 3.1, namely 8 | maps.

9 |

The following sections present usage examples for those new features. If you click on the 10 | edit link, the example snippet will be loaded into eXide so you can run, edit and play around 11 | with it.

12 |
    13 |
  1. 14 | String concatenation and bang operators 15 |
  2. 16 |
  3. 17 | Switch expression 18 |
  4. 19 |
  5. Catching errors with try/catch 20 |
  6. 21 |
  7. Using group by in FLWOR expressions
  8. 22 |
  9. 23 | Higher-order functions, closures and partial function applications
  10. 24 |
  11. 25 | XQuery 3.1 maps 26 |
  12. 27 |
28 |
-------------------------------------------------------------------------------- /examples/basic/xslt.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Calling XSLT transformation

4 |
5 |

Simple Transformation

6 |
 7 | xquery version "3.0";
 8 | 
 9 | let $input := doc("@@path/examples/basic/Items.xml")
10 | let $xsl := doc("@@path/examples/basic/ConvertItems.xsl")
11 | return
12 |     transform:transform($input, $xsl, ())
13 |

View source: Items.xml, 14 | ConvertItems.xsl 15 |

16 |
17 |
18 |

Transform Shakespeare's Hamlet to HTML

19 |
20 | xquery version "3.0";
21 | 
22 | let $input := doc("@@path/data/hamlet.xml")
23 | let $xsl := doc("@@path/data/shakes.xsl")
24 | return
25 |     transform:transform($input, $xsl, ())
26 |

View source: shakes.xsl, 27 | hamlet.xml 28 |

29 |
30 |
-------------------------------------------------------------------------------- /examples/contacts/data/e19316b0-af33-4c1c-88e3-9ddd5b03c239.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hans 4 | 0293829 5 | hans@web.de 6 | e19316b0-af33-4c1c-88e3-9ddd5b03c239 7 | -------------------------------------------------------------------------------- /examples/contacts/html/browseContacts.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Browse Contacts

4 | 5 |
6 |
7 | No data... 8 | 9 | 11 | 12 | 13 | 15 |
16 |
17 | 20 | 21 | 22 | 23 | 33 | 34 | 35 | 36 |
10 | NamePhoneEmail 14 |
18 | 19 | {{contact.name}}{{contact.phone}}{{contact.email}} 24 |
25 | 26 | Delete 27 | 28 | 29 | Update 30 | 31 |
32 |
37 |
38 |
39 | 40 | 41 | 42 |
-------------------------------------------------------------------------------- /examples/contacts/html/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"/> 6 | <meta data-template="config:app-meta"/> 7 | <script type="text/javascript" src="../js/angular.min.js"/> 8 | <script type="text/javascript" src="../js/angular-animate.min.js"/> 9 | <script type="text/javascript" src="../js/angular-route.min.js"/> 10 | <script type="text/javascript" src="../js/angular-resource.min.js"/> 11 | <script type="text/javascript" src="../js/jquery-2.1.0.min.js"/> 12 | <script type="text/javascript" src="../js/spin.min.js"/> 13 | <script type="text/javascript" src="../js/angular-spinner.min.js"/> 14 | <script type="text/javascript" src="../js/app.js"/> 15 | </head> 16 | <body> 17 | <div data-app-header="" data-media-screen=""> 18 | <h1>eXist-db Contacts RestXQ Demo</h1> 19 | </div> 20 | <div data-ng-view=""/> 21 | <span us-spinner="{radius:30, width:8, length: 16}" spinner-key="spinner-1"/> 22 | </body> 23 | </html> -------------------------------------------------------------------------------- /examples/contacts/html/newContact.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <form name="contact"> 3 | <div class="container"> 4 | <h2>Create New Contact</h2> 5 | <label for="name">Name : </label> 6 | <input id="name" value="" type="text" ng-model="contact.name" required=""/> 7 | <br/> 8 | <label for="phone">Phone : </label> 9 | <input id="phone" value="" type="text" ng-model="contact.phone" required=""/> 10 | <br/> 11 | <label for="email">Email : </label> 12 | <input id="email" value="" type="email" ng-model="contact.email" required=""/> 13 | <br/> 14 | <br/> 15 | <button id="create" ng-click="create(contact)">Create</button> 16 | <button id="cancel" ng-click="cancel()">Cancel</button> 17 | </div> 18 | </form> -------------------------------------------------------------------------------- /examples/contacts/html/updateContact.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <form name="contact2"> 3 | <div class="container"> 4 | <h2>Update Contact</h2> 5 | <img width="240" ng-src="{{getContactIconRel(contact)}}"/> 6 | <br/> 7 | <label for="name">Name : </label> 8 | <input id="name" type="text" value="{{contact.name}}" ng-model="contact.name" required=""/> 9 | <br/> 10 | <label for="phone">Phone : </label> 11 | <input id="phone" type="text" value="{{contact.phone}}" ng-model="contact.phone" required=""/> 12 | <br/> 13 | <label for="email">Email : </label> 14 | <input id="email" type="email" value="{{contact.email}}" ng-model="contact.email" required=""/> 15 | <br/> 16 | <label for="image">Image URL : </label> 17 | <input id="image" type="url" ng-model="contact.image"/> 18 | <br/> 19 | <br/> 20 | <button id="update" ng-click="update(contact)">Update</button> 21 | <button id="cancel" ng-click="cancel()">Cancel</button> 22 | </div> 23 | </form> -------------------------------------------------------------------------------- /examples/contacts/js/angular-animate.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.3.0-beta.3 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(F,g,P){'use strict';g.module("ngAnimate",["ng"]).factory("$$animateReflow",["$$rAF","$document",function(g,F){return function(e){return g(function(){e()})}}]).config(["$provide","$animateProvider",function(V,G){function e(e){for(var p=0;p<e.length;p++){var g=e[p];if(g.nodeType==ba)return g}}function u(p){return g.element(e(p))}var m=g.noop,p=g.forEach,ga=G.$$selectors,ba=1,h="$$ngAnimateState",J="ng-animate",r={running:!0};V.decorator("$animate",["$delegate","$injector","$sniffer","$rootElement", 7 | "$$asyncCallback","$rootScope","$document",function(x,F,aa,K,E,H,P){function Q(a){if(a){var b=[],c={};a=a.substr(1).split(".");(aa.transitions||aa.animations)&&a.push("");for(var d=0;d<a.length;d++){var f=a[d],e=ga[f];e&&!c[f]&&(b.push(F.get(e)),c[f]=!0)}return b}}function L(a,b,c){function d(a,b){var c=a[b],d=a["before"+b.charAt(0).toUpperCase()+b.substr(1)];if(c||d)return"leave"==b&&(d=c,c=null),y.push({event:b,fn:c}),l.push({event:b,fn:d}),!0}function f(b,d,e){var f=[];p(b,function(a){a.fn&&f.push(a)}); 8 | var n=0;p(f,function(b,p){var C=function(){a:{if(d){(d[p]||m)();if(++n<f.length)break a;d=null}e()}};switch(b.event){case "setClass":d.push(b.fn(a,q,z,C));break;case "addClass":d.push(b.fn(a,q||c,C));break;case "removeClass":d.push(b.fn(a,z||c,C));break;default:d.push(b.fn(a,C))}});d&&0===d.length&&e()}var e=a[0];if(e){var h="setClass"==b,r=h||"addClass"==b||"removeClass"==b,q,z;g.isArray(c)&&(q=c[0],z=c[1],c=q+" "+z);var s=a.attr("class")+" "+c;if(S(s)){var t=m,v=[],l=[],w=m,n=[],y=[],s=(" "+s).replace(/\s+/g, 9 | ".");p(Q(s),function(a){!d(a,b)&&h&&(d(a,"addClass"),d(a,"removeClass"))});return{node:e,event:b,className:c,isClassBased:r,isSetClassOperation:h,before:function(a){t=a;f(l,v,function(){t=m;a()})},after:function(a){w=a;f(y,n,function(){w=m;a()})},cancel:function(){v&&(p(v,function(a){(a||m)(!0)}),t(!0));n&&(p(n,function(a){(a||m)(!0)}),w(!0))}}}}}function A(a,b,c,d,f,e,r){function m(d){var e="$animate:"+d;w&&(w[e]&&0<w[e].length)&&E(function(){c.triggerHandler(e,{event:a,className:b})})}function q(){m("before")} 10 | function z(){m("after")}function s(){m("close");r&&E(function(){r()})}function t(){t.hasBeenRun||(t.hasBeenRun=!0,e())}function v(){if(!v.hasBeenRun){v.hasBeenRun=!0;var d=c.data(h);d&&(l&&l.isClassBased?B(c,b):(E(function(){var d=c.data(h)||{};A==d.index&&B(c,b,a)}),c.data(h,d)));s()}}var l=L(c,a,b);if(l){b=l.className;var w=g.element._data(l.node),w=w&&w.events;d||(d=f?f.parent():c.parent());var n=c.data(h)||{};f=n.active||{};var y=n.totalActive||0,C=n.last;if(l.isClassBased&&(n.disabled||C&&!C.isClassBased)|| 11 | N(c,d))t(),q(),z(),v();else{d=!1;if(0<y){n=[];if(l.isClassBased)"setClass"==C.event?(n.push(C),B(c,b)):f[b]&&(x=f[b],x.event==a?d=!0:(n.push(x),B(c,b)));else if("leave"==a&&f["ng-leave"])d=!0;else{for(var x in f)n.push(f[x]),B(c,x);f={};y=0}0<n.length&&p(n,function(a){a.cancel()})}!l.isClassBased||(l.isSetClassOperation||d)||(d="addClass"==a==c.hasClass(b));if(d)q(),z(),s();else{if("leave"==a)c.one("$destroy",function(a){a=g.element(this);var b=a.data(h);b&&(b=b.active["ng-leave"])&&(b.cancel(),B(a, 12 | "ng-leave"))});c.addClass(J);var A=O++;y++;f[b]=l;c.data(h,{last:l,active:f,index:A,totalActive:y});q();l.before(function(d){var e=c.data(h);d=d||!e||!e.active[b]||l.isClassBased&&e.active[b].event!=a;t();!0===d?v():(z(),l.after(v))})}}}else t(),q(),z(),v()}function T(a){if(a=e(a))a=g.isFunction(a.getElementsByClassName)?a.getElementsByClassName(J):a.querySelectorAll("."+J),p(a,function(a){a=g.element(a);(a=a.data(h))&&a.active&&p(a.active,function(a){a.cancel()})})}function B(a,b){if(e(a)==e(K))r.disabled|| 13 | (r.running=!1,r.structural=!1);else if(b){var c=a.data(h)||{},d=!0===b;!d&&(c.active&&c.active[b])&&(c.totalActive--,delete c.active[b]);if(d||!c.totalActive)a.removeClass(J),a.removeData(h)}}function N(a,b){if(r.disabled)return!0;if(e(a)==e(K))return r.disabled||r.running;do{if(0===b.length)break;var c=e(b)==e(K),d=c?r:b.data(h),d=d&&(!!d.disabled||d.running||0<d.totalActive);if(c||d)return d;if(c)break}while(b=b.parent());return!0}var O=0;K.data(h,r);H.$$postDigest(function(){H.$$postDigest(function(){r.running= 14 | !1})});var U=G.classNameFilter(),S=U?function(a){return U.test(a)}:function(){return!0};return{enter:function(a,b,c,d){this.enabled(!1,a);x.enter(a,b,c);H.$$postDigest(function(){a=u(a);A("enter","ng-enter",a,b,c,m,d)})},leave:function(a,b){T(a);this.enabled(!1,a);H.$$postDigest(function(){A("leave","ng-leave",u(a),null,null,function(){x.leave(a)},b)})},move:function(a,b,c,d){T(a);this.enabled(!1,a);x.move(a,b,c);H.$$postDigest(function(){a=u(a);A("move","ng-move",a,b,c,m,d)})},addClass:function(a, 15 | b,c){a=u(a);A("addClass",b,a,null,null,function(){x.addClass(a,b)},c)},removeClass:function(a,b,c){a=u(a);A("removeClass",b,a,null,null,function(){x.removeClass(a,b)},c)},setClass:function(a,b,c,d){a=u(a);A("setClass",[b,c],a,null,null,function(){x.setClass(a,b,c)},d)},enabled:function(a,b){switch(arguments.length){case 2:if(a)B(b);else{var c=b.data(h)||{};c.disabled=!0;b.data(h,c)}break;case 1:r.disabled=!a;break;default:a=!r.disabled}return!!a}}}]);G.register("",["$window","$sniffer","$timeout", 16 | "$$animateReflow",function(h,r,u,K){function E(a,k){R&&R();W.push(k);R=K(function(){p(W,function(a){a()});W=[];R=null;M={}})}function H(a,k){var b=e(a);a=g.element(b);Y.push(a);b=Date.now()+1E3*k;b<=fa||(u.cancel(ea),fa=b,ea=u(function(){J(Y);Y=[]},k,!1))}function J(a){p(a,function(a){(a=a.data(n))&&(a.closeAnimationFn||m)()})}function Q(a,k){var b=k?M[k]:null;if(!b){var c=0,d=0,e=0,f=0,n,Z,$,g;p(a,function(a){if(a.nodeType==ba){a=h.getComputedStyle(a)||{};$=a[I+s];c=Math.max(L($),c);g=a[I+t];n=a[I+ 17 | v];d=Math.max(L(n),d);Z=a[q+v];f=Math.max(L(Z),f);var k=L(a[q+s]);0<k&&(k*=parseInt(a[q+l],10)||1);e=Math.max(k,e)}});b={total:0,transitionPropertyStyle:g,transitionDurationStyle:$,transitionDelayStyle:n,transitionDelay:d,transitionDuration:c,animationDelayStyle:Z,animationDelay:f,animationDuration:e};k&&(M[k]=b)}return b}function L(a){var k=0;a=g.isString(a)?a.split(/\s*,\s*/):[];p(a,function(a){k=Math.max(parseFloat(a)||0,k)});return k}function A(a){var k=a.parent(),b=k.data(w);b||(k.data(w,++da), 18 | b=da);return b+"-"+e(a).className}function T(a,k,b,c){var d=A(k),f=d+" "+b,p=M[f]?++M[f].total:0,g={};if(0<p){var h=b+"-stagger",g=d+" "+h;(d=!M[g])&&k.addClass(h);g=Q(k,g);d&&k.removeClass(h)}c=c||function(a){return a()};k.addClass(b);var h=k.data(n)||{},l=c(function(){return Q(k,f)});c=l.transitionDuration;d=l.animationDuration;if(0===c&&0===d)return k.removeClass(b),!1;k.data(n,{running:h.running||0,itemIndex:p,stagger:g,timings:l,closeAnimationFn:m});a=0<h.running||"setClass"==a;0<c&&B(k,b,a); 19 | 0<d&&(0<g.animationDelay&&0===g.animationDuration)&&(e(k).style[q]="none 0s");return!0}function B(a,b,c){"ng-enter"!=b&&("ng-move"!=b&&"ng-leave"!=b)&&c?a.addClass(y):e(a).style[I+t]="none"}function N(a,b){var c=I+t,d=e(a);d.style[c]&&0<d.style[c].length&&(d.style[c]="");a.removeClass(y)}function O(a){var b=q;a=e(a);a.style[b]&&0<a.style[b].length&&(a.style[b]="")}function U(a,b,c,f){function g(a){b.off(y,h);b.removeClass(r);d(b,c);a=e(b);for(var X in u)a.style.removeProperty(u[X])}function h(a){a.stopPropagation(); 20 | var b=a.originalEvent||a;a=b.$manualTimeStamp||b.timeStamp||Date.now();b=parseFloat(b.elapsedTime.toFixed(C));Math.max(a-A,0)>=x&&b>=v&&f()}var l=e(b);a=b.data(n);if(-1!=l.className.indexOf(c)&&a){var r="";p(c.split(" "),function(a,b){r+=(0<b?" ":"")+a+"-active"});var q=a.stagger,m=a.timings,t=a.itemIndex,v=Math.max(m.transitionDuration,m.animationDuration),w=Math.max(m.transitionDelay,m.animationDelay),x=w*ca,A=Date.now(),y=z+" "+G,s="",u=[];if(0<m.transitionDuration){var B=m.transitionPropertyStyle; 21 | -1==B.indexOf("all")&&(s+=D+"transition-property: "+B+";",s+=D+"transition-duration: "+m.transitionDurationStyle+";",u.push(D+"transition-property"),u.push(D+"transition-duration"))}0<t&&(0<q.transitionDelay&&0===q.transitionDuration&&(s+=D+"transition-delay: "+S(m.transitionDelayStyle,q.transitionDelay,t)+"; ",u.push(D+"transition-delay")),0<q.animationDelay&&0===q.animationDuration&&(s+=D+"animation-delay: "+S(m.animationDelayStyle,q.animationDelay,t)+"; ",u.push(D+"animation-delay")));0<u.length&& 22 | (m=l.getAttribute("style")||"",l.setAttribute("style",m+" "+s));b.on(y,h);b.addClass(r);a.closeAnimationFn=function(){g();f()};l=(t*(Math.max(q.animationDelay,q.transitionDelay)||0)+(w+v)*V)*ca;a.running++;H(b,l);return g}f()}function S(a,b,c){var d="";p(a.split(","),function(a,X){d+=(0<X?",":"")+(c*b+parseInt(a,10))+"s"});return d}function a(a,b,c,e){if(T(a,b,c,e))return function(a){a&&d(b,c)}}function b(a,b,c,e){if(b.data(n))return U(a,b,c,e);d(b,c);e()}function c(c,d,e,f){var g=a(c,d,e);if(g){var h= 23 | g;E(d,function(){N(d,e);O(d);h=b(c,d,e,f)});return function(a){(h||m)(a)}}f()}function d(a,b){a.removeClass(b);var c=a.data(n);c&&(c.running&&c.running--,c.running&&0!==c.running||a.removeData(n))}function f(a,b){var c="";a=g.isArray(a)?a:a.split(/\s+/);p(a,function(a,d){a&&0<a.length&&(c+=(0<d?" ":"")+a+b)});return c}var D="",I,G,q,z;F.ontransitionend===P&&F.onwebkittransitionend!==P?(D="-webkit-",I="WebkitTransition",G="webkitTransitionEnd transitionend"):(I="transition",G="transitionend");F.onanimationend=== 24 | P&&F.onwebkitanimationend!==P?(D="-webkit-",q="WebkitAnimation",z="webkitAnimationEnd animationend"):(q="animation",z="animationend");var s="Duration",t="Property",v="Delay",l="IterationCount",w="$$ngAnimateKey",n="$$ngAnimateCSS3Data",y="ng-animate-block-transitions",C=3,V=1.5,ca=1E3,M={},da=0,W=[],R,ea=null,fa=0,Y=[];return{enter:function(a,b){return c("enter",a,"ng-enter",b)},leave:function(a,b){return c("leave",a,"ng-leave",b)},move:function(a,b){return c("move",a,"ng-move",b)},beforeSetClass:function(b, 25 | c,d,e){var g=f(d,"-remove")+" "+f(c,"-add"),h=a("setClass",b,g,function(a){var e=b.attr("class");b.removeClass(d);b.addClass(c);a=a();b.attr("class",e);return a});if(h)return E(b,function(){N(b,g);O(b);e()}),h;e()},beforeAddClass:function(b,c,d){var e=a("addClass",b,f(c,"-add"),function(a){b.addClass(c);a=a();b.removeClass(c);return a});if(e)return E(b,function(){N(b,c);O(b);d()}),e;d()},setClass:function(a,c,d,e){d=f(d,"-remove");c=f(c,"-add");return b("setClass",a,d+" "+c,e)},addClass:function(a, 26 | c,d){return b("addClass",a,f(c,"-add"),d)},beforeRemoveClass:function(b,c,d){var e=a("removeClass",b,f(c,"-remove"),function(a){var d=b.attr("class");b.removeClass(c);a=a();b.attr("class",d);return a});if(e)return E(b,function(){N(b,c);O(b);d()}),e;d()},removeClass:function(a,c,d){return b("removeClass",a,f(c,"-remove"),d)}}}])}])})(window,window.angular); 27 | //# sourceMappingURL=angular-animate.min.js.map -------------------------------------------------------------------------------- /examples/contacts/js/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.3.0-beta.3 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&& 7 | b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l= 8 | b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg", 9 | h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f} 10 | var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)? 11 | g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a, 12 | e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular); 13 | //# sourceMappingURL=angular-resource.min.js.map -------------------------------------------------------------------------------- /examples/contacts/js/angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.3.0-beta.3 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()} 7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){}, 8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b= 9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart", 10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl= 11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h<p;++h){var n=q[h-1],r="string"==typeof g[h]?decodeURIComponent(g[h]): 12 | g[h];n&&r&&(l[n.name]=r)}q=l}else q=null;else q=null;q=a=q}q&&(b=s(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&s(k[null],{params:{},pathParams:{}})}function t(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var u=!1,r={routes:k,reload:function(){u=!0;a.$evalAsync(l)}};a.$on("$locationChangeSuccess",l);return r}]});n.provider("$routeParams", 13 | function(){this.$get=function(){return{}}});n.directive("ngView",x);n.directive("ngView",z);x.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular); 14 | //# sourceMappingURL=angular-route.min.js.map -------------------------------------------------------------------------------- /examples/contacts/js/angular-spinner.min.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"use strict";b.module("angularSpinner",[]).factory("usSpinnerService",["$rootScope",function(a){var b={};return b.spin=function(b){a.$broadcast("us-spinner:spin",b)},b.stop=function(b){a.$broadcast("us-spinner:stop",b)},b}]).directive("usSpinner",["$window",function(a){return{scope:!0,controller:["$scope","$element","$attrs",function(a,c,d){a.spinner=null,a.key=b.isDefined(d.spinnerKey)?d.spinnerKey:!1,a.startActive=b.isDefined(d.spinnerStartActive)?d.spinnerStartActive:!a.key,a.spin=function(){a.spinner&&a.spinner.spin(c[0])},a.stop=function(){a.spinner&&a.spinner.stop()}}],link:function(b,c,d){b.$watch(d.usSpinner,function(d){b.stop(),b.spinner=new a.Spinner(d),(!b.key||b.startActive)&&b.spinner.spin(c[0])},!0),b.$on("us-spinner:spin",function(a,c){c===b.key&&b.spin()}),b.$on("us-spinner:stop",function(a,c){c===b.key&&b.stop()}),b.$on("$destroy",function(){b.stop(),b.spinner=null})}}}])}(window,window.angular); -------------------------------------------------------------------------------- /examples/contacts/js/app.js: -------------------------------------------------------------------------------- 1 | var contactsApp = angular.module('contactsApp', ['ngRoute','ngAnimate','angularSpinner']); 2 | 3 | 4 | var showAjaxError = function(headers) { 5 | if(headers('XQ-Exception') === null) 6 | { alert("Service Unavailable!"); } 7 | else 8 | { alert(headers('XQ-Exception')); } 9 | } 10 | 11 | var getLinkByRel = function(links, rel) { 12 | if(links.a instanceof Array) { // check if Array first 13 | return links.a.filter(function( link ) { 14 | return link.rel == rel; 15 | })[0]; // since links should be unique, we only care about the first one 16 | } else if(links.a instanceof Object && links.a.rel == rel) { 17 | return links.a; 18 | } else { 19 | return undefined; 20 | } 21 | } 22 | 23 | var makeArray = function(obj) { 24 | if(obj instanceof Array) { 25 | return obj; 26 | } else if(obj instanceof Object) { 27 | return [].concat(obj) 28 | } else { 29 | return undefined; 30 | } 31 | } 32 | 33 | contactsApp.controller('newContact', 34 | function($scope, $http, $location, usSpinnerService) 35 | { 36 | $scope.cancel = function () 37 | { 38 | $location 39 | .search('uri',null) 40 | .path("/browseContacts"); 41 | } 42 | 43 | $scope.create = function (contact) 44 | { 45 | if(contact.$valid) 46 | { 47 | usSpinnerService.spin('spinner-1'); 48 | 49 | var onSuccess = function(result) { 50 | usSpinnerService.stop('spinner-1'); 51 | $scope.cancel(); 52 | } 53 | 54 | var onFailure = function(result) { 55 | usSpinnerService.stop('spinner-1'); 56 | showAjaxError(result.headers); 57 | } 58 | 59 | $http 60 | .defaults 61 | .headers 62 | .post['Content-Type'] = 'application/json'; 63 | 64 | $http 65 | .post('/exist/restxq/demo/contacts', 66 | { 67 | "contact" : 68 | { 69 | "name" : contact.name, 70 | "phone" : contact.phone, 71 | "email" : contact.email 72 | } 73 | }) 74 | .then(onSuccess, onFailure); 75 | } 76 | } 77 | }); 78 | 79 | 80 | contactsApp.controller('updateContact', 81 | function($scope, $http, $location, $q, usSpinnerService) 82 | { 83 | $scope.getContactIconRel = function(contact) 84 | { 85 | return ( contact === undefined || getLinkByRel(contact.links,'icon') === undefined ) ? 86 | 'http://placekitten.com/240/240' : 87 | getLinkByRel(contact.links,'icon').href; 88 | } 89 | 90 | $scope.$on('$routeChangeSuccess', function (event, currentRoute, previousRoute) 91 | { 92 | usSpinnerService.spin('spinner-1'); 93 | 94 | var onSuccess = function(result) { 95 | usSpinnerService.stop('spinner-1'); 96 | $scope.contact = result.data.contact; 97 | } 98 | 99 | var onFailure = function(result) { 100 | usSpinnerService.stop('spinner-1'); 101 | showAjaxError(result.headers); 102 | } 103 | 104 | $http 105 | .get($location.search().uri) 106 | .then(onSuccess, onFailure); 107 | }); 108 | 109 | $scope.cancel = function () 110 | { 111 | $location 112 | .search('uri',null) 113 | .path("/browseContacts"); 114 | } 115 | 116 | $scope.update = function (contact) 117 | { 118 | //if(contact.$valid) //TODO: not sure the difference between $scope.contact and contact at this point 119 | { 120 | usSpinnerService.spin('spinner-1'); 121 | 122 | var onSuccess = function(result) { 123 | usSpinnerService.stop('spinner-1'); 124 | $scope.cancel(); 125 | } 126 | 127 | var onFailure = function(result) { 128 | usSpinnerService.stop('spinner-1'); 129 | showAjaxError(result.headers); 130 | } 131 | 132 | $http 133 | .defaults 134 | .headers 135 | .put['Content-Type'] = 'application/exist+json'; //TODO: fix this non-standard content type 136 | 137 | $q 138 | .all([ 139 | $http 140 | .put($location.search().uri, 141 | { 142 | "contact" : 143 | { 144 | "name" : contact.name, 145 | "phone" : contact.phone, 146 | "email" : contact.email 147 | } 148 | }), 149 | (contact.image === undefined) ? 150 | function() {} : 151 | $http 152 | .put($location.search().uri + '?uri=' + contact.image) 153 | ]) 154 | .then(onSuccess, onFailure); 155 | } 156 | } 157 | }); 158 | 159 | contactsApp.controller('browseContacts', 160 | function($scope, $http, $location, usSpinnerService) 161 | { 162 | $scope.uri = function () { 163 | return ( $location.search().uri === undefined ) ? 164 | '/exist/restxq/demo/contacts?skip=0&take=5' : 165 | $location.search().uri; 166 | } 167 | 168 | $scope.getContactIconRel = function(contact) 169 | { 170 | return ( getLinkByRel(contact.links,'icon') === undefined ) ? 171 | 'http://placekitten.com/g/59/59' : 172 | getLinkByRel(contact.links,'icon').href; 173 | } 174 | 175 | $scope.$on('$routeChangeSuccess', function (event, currentRoute, previousRoute) 176 | { 177 | usSpinnerService.spin('spinner-1'); 178 | 179 | var onSuccess = function(result) { 180 | usSpinnerService.stop('spinner-1'); 181 | 182 | $scope.contacts = makeArray(result.data.contact); 183 | 184 | //console.log(result.data); 185 | //console.log($scope.contacts); 186 | 187 | $scope.previousPage = function() { 188 | $location.search('uri', getLinkByRel(result.data.links,'prev').href).path('/browseContacts'); 189 | } 190 | 191 | $scope.refreshPage = function() { 192 | $location.search('uri', getLinkByRel(result.data.links,'self').href).path('/browseContacts'); 193 | } 194 | 195 | $scope.nextPage = function() { 196 | $location.search('uri', getLinkByRel(result.data.links,'next').href).path('/browseContacts'); 197 | } 198 | } 199 | 200 | var onFailure = function(result) { 201 | usSpinnerService.stop('spinner-1'); 202 | showAjaxError(result.headers); 203 | } 204 | 205 | $http 206 | .get($scope.uri()) 207 | .then(onSuccess, onFailure); 208 | }); 209 | 210 | $scope.new = function() { 211 | $location 212 | .search('uri',null) 213 | .path("/newContact"); 214 | } 215 | 216 | $scope.delete = function(contact) { 217 | usSpinnerService.spin('spinner-1'); 218 | 219 | var onSuccess = function(result) { 220 | usSpinnerService.stop('spinner-1'); 221 | $scope.refreshPage(); 222 | } 223 | 224 | var onFailure = function(result) { 225 | usSpinnerService.stop('spinner-1'); 226 | showAjaxError(result.headers); 227 | } 228 | 229 | $http 230 | .delete(getLinkByRel(contact.links,'self').href) 231 | .then(onSuccess, onFailure); 232 | } 233 | 234 | $scope.update = function(contact) { 235 | $location 236 | .search('uri',getLinkByRel(contact.links,'self').href) 237 | .path("/updateContact"); 238 | } 239 | }); 240 | 241 | 242 | contactsApp.config(function ($routeProvider) { 243 | $routeProvider 244 | .when('/newContact', 245 | { 246 | controller: 'newContact', 247 | templateUrl: 'newContact.html' 248 | }) 249 | .when('/updateContact', 250 | { 251 | controller: 'updateContact', 252 | templateUrl: 'updateContact.html' 253 | }) 254 | .when('/browseContacts', 255 | { 256 | controller: 'browseContacts', 257 | templateUrl: 'browseContacts.html' 258 | }) 259 | .otherwise({ redirectTo: '/browseContacts'}); 260 | }); -------------------------------------------------------------------------------- /examples/contacts/js/spin.min.js: -------------------------------------------------------------------------------- 1 | //fgnass.github.com/spin.js#v2.0.0 2 | !function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(b&&(b.insertBefore(f,b.firstChild||null),e(f,{left:d.left,top:d.top})),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h}); -------------------------------------------------------------------------------- /examples/special/i18n-docs.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <div class="templates:surround?with=templates/page.html&at=content"> 3 | <h1>eXist i18n XQuery Module Documentation</h1> 4 | <!-- INTRODUCTION --> 5 | <h2 id="introduction">Introduction</h2> 6 | <p>The eXist i18n module provides an easy to use mechanism to internationalize (i18n) any kind of XML document.</p> 7 | 8 | <!-- BRIEF DESCRIPTION--> 9 | <h2 id="briefdescription">Brief description</h2> 10 | <p>Following features are supported by the eXist i18n module</p> 11 | <ul> 12 | <li>Text translation</li> 13 | <li>Parameter substitution within text translations</li> 14 | <li>Usage of internationalized parameters</li> 15 | <li>Attribute translation</li> 16 | </ul> 17 | <p>See the <a href="#reference">reference</a> and <a href="#configuration">configuration</a> sections to utilize the i18n extension within your application.</p> 18 | <h2 id="reference">Reference</h2> 19 | <p>All i18n tags or attributes use a key to retrieve localized text from the i18n catalogue. If no catalogue is available for a chosen language and there is no default catalogue configured then the 'defaultValue' is used. See the description 20 | of the i18n tags / attributes to see where to place the 'defaultValue'.</p> 21 | 22 | <!-- LANGUAGE CATALOGUES --> 23 | <h3 id="catalogues">Language catalogues</h3> 24 | <p>Catalogues are holding the language data and have the following (flat) structure:</p> 25 | <pre class="brush: xml"><catalogue xml:lang="de"> 26 | <msg key="Welcome">Willkommen</msg> 27 | <msg key="Cancel">Abbrechen</msg> 28 | </catalogue></pre> 29 | <p>The xml:lang attribute on the catalogue tag defines the language for the catalogue. The attribute value should correspond to ISO 639. The catalogue itself is made up of an flat list of msg tags. Each has an attribute 'key' with a unique value 30 | to identify the translated text. The translated text itself is placed as node value of the msg node.</p> 31 | 32 | <!-- TEXT TRANSLATION --> 33 | <h3 id="textTranslation">Text translation</h3> 34 | <pre class="brush: xml"><i18n:text key="uniqueID">Text in default language</i18n:text></pre> 35 | <p>The <i18n:text> tag is used to mark text to be translated. The attribute <i>@key</i> is used to find the respective translation 36 | from a specific catalogue. The text 37 | value of the <i18n:text> node can be used as default translation and is further displayed if no catalogue for a selected language exists (and no default language is configured).</p> 38 | 39 | <!-- PARAMETER SUBSTITUTION--> 40 | <h3>Parameter substitution for text</h3> 41 | <p><i18n:translate> provides parameter substitution for internationalized text. The substitution can either be archived by the numerical order of the i18n:param tags or by character keys. Be aware that numerical and character parameter 42 | substitution must not be mixed within one i18n:translate tag.</p> 43 | <h4>Numerical i18n:param substitution</h4> 44 | <p>Parameters are referenced with numbers in angle brackets. Be aware that the i18n:param count starts with 1.</p> 45 | <pre class="brush: xml"><i18n:translate> 46 | <i18n:text key="textWithParam">{2} is prerequisite for {1}.(E.W. Dijkstra)</i18n:text> 47 | <i18n:param>reliability</i18n:param> 48 | <i18n:param>Simplicity</i18n:param> 49 | </i18n:translate></pre> 50 | <p>The above example resolves to: 'Simplicity is prerequisite for reliability.(E.W. Dijkstra)</p> 51 | <h4>Character i18n:param substitution</h4> 52 | <p>Using character parameter substitution uses keys instead of the numerical order to substitute parameters. The order of the parameters in the i18n:text tag does not matter.</p> 53 | <pre class="brush: xml"><i18n:translate> 54 | <i18n:text key="textWithParam">{key1} is prerequisite for {key2}.(E.W. Dijkstra)</i18n:text> 55 | <i18n:param key="key1">Simplicity</i18n:param> 56 | <i18n:param key="key2">reliability</i18n:param> 57 | </i18n:translate></pre> 58 | <p>The above example resolves to: 'Simplicity is prerequisite for reliability.(E.W. Dijkstra)</p> 59 | <h3>Translation of parameters</h3> 60 | <p>i18n:params can be translated just like i18n:text tags.</p> 61 | <pre class="brush: xml"><i18n:translate> 62 | <i18n:text key="textWithParam">{key1} is prerequisite for reliability.(E.W. Dijkstra)</i18n:text> 63 | <i18n:param key="key1"> 64 | <i18n:text key="simplicity">Simplicity</i18n:text> 65 | </i18n:param> 66 | </i18n:translate></pre> 67 | <h3>Attribute translation</h3> 68 | <p>Use i18n(key,defaultValue) to translate attributes where the parameter 'defaultValue' is optional.</p> 69 | <pre class="brush: xml"><div attr1="i18n(key1)" attr2="i18n(key2,defaultValue1)"/></pre> 70 | 71 | <!-- CONFIGURATION --> 72 | <h2 id="configuration">Configuration</h2> 73 | <!-- connect i18n module --> 74 | <h3>Automatically process XML</h3> 75 | <p>The i18n xquery module is configured via the controller.xql in your application. A typical configuration to process any .html file 76 | in an application would look like this: </p> 77 | <pre class="brush: xquery">xquery version "1.0"; 78 | 79 | import module namespace request="http://exist-db.org/xquery/request"; 80 | import module namespace xdb = "http://exist-db.org/xquery/xmldb"; 81 | 82 | declare variable $exist:path external; 83 | declare variable $exist:resource external; 84 | 85 | if (ends-with($exist:resource, ".html")) then 86 | <dispatch xmlns="http://exist.sourceforge.net/NS/exist"> 87 | <view> 88 | <forward url="/db/i18n/modules/view.xql"/> 89 | </view> 90 | </dispatch> 91 | else 92 | <ignore xmlns="http://exist.sourceforge.net/NS/exist"> 93 | <cache-control cache="yes"/> 94 | </ignore></pre> 95 | <h3>Usage of i18n via XQuery calls</h3> 96 | <p>Another variant is to directly call the i18n:process function within the i18n module: </p> 97 | <pre class="brush: xquery">(:~ i18n.xql: 98 | : i18n processing on the given set of nodes. Call this function from 99 | : within other functions to enable recursive processing of i18n tags. 100 | : 101 | : @param $nodes - the nodes to process 102 | : @param $selectedLang - chosen language, controls which i18n catalogue to load 103 | : @param $pathToCatalogues - path that points to the available i18n catalogues within the eXist database 104 | : @param $defaultLang - language that is used if no i18n catalogue can be found for the chosen language 105 | :) 106 | declare function i18n:process($nodes as node()*, 107 | $selectedLang as xs:string, $pathToCatalogues as xs:string, 108 | $defaultLang as xs:string)</pre> 109 | <p>The following sample shows how this could be done: </p> 110 | <pre class="brush: xquery">xquery version "1.0";xquery version "1.0"; 111 | 112 | import module namespace i18n = "http://exist-db.org/xquery/i18n" at "/db/i18n/modules/i18n.xql"; 113 | 114 | declare option exist:serialize "method=xhtml media-type=text/html"; 115 | (: get some html containing i18n tags :) 116 | let $content := doc('index.html')/* 117 | 118 | return 119 | i18n:process($content,'de','/db/i18n/data','es')</pre> 120 | <h2 id="usage">Usage</h2> 121 | <h3>Select language</h3> 122 | <p>The language to use for internationalization can be chosen in various ways</p> 123 | <ul> 124 | <li>via http parameter 'lang', e.q http://exist/index.html?lang=de</li> 125 | <li>as xquery parameter $selectedLang if the i18n module is called directly</li> 126 | <li>xml:lang attribute on the root node of the markup to process</li> 127 | </ul> 128 | <h3>Path to i18n catalogues</h3> 129 | <p>The path to the catalogue files can be given as follows:</p> 130 | <ul> 131 | <li>via http parameter 'cataloguesPath'</li> 132 | <li>as xquery parameter $cataloguesPath if the i18n module is called directly</li> 133 | <li>using the attribute i18n:catalogues on the root node of the processed markup</li> 134 | </ul> 135 | <h3>Default Language</h3> 136 | <p>Chosing a default language (without placing it as inline markup within i18n tags) can be done with:</p> 137 | <ul> 138 | <li>via http parameter 'defaultLang'</li> 139 | <li>as parameter $defaultLang if the i18n module is called directly</li> 140 | <li>using the attribute i18n:default-lang on the root node of the processed markup</li> 141 | </ul> 142 | </div> 143 | -------------------------------------------------------------------------------- /examples/special/i18n.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <div xmlns:i18n="http://exist-db.org/xquery/i18n" data-template="templates:surround" data-template-with="templates/page.html" data-template-at="content"> 3 | <div data-template="i18n:translate" data-template-lang="es" data-template-catalogues="data/i18n"> 4 | <h1>i18n Module Examples</h1> 5 | <p>The i18n XQuery module is a general-purpose library to internationalize an XML document. 6 | For more information about the supported format read the <a href="i18n-docs.html">documentation</a>.</p> 7 | <p>This page uses HTML templating. It calls the i18n module through a template instruction as follows:</p> 8 | <pre class="brush: xml"><div data-template="i18n:translate" data-template-lang="es" data-template-catalogues="data/i18n">...</div></pre> 9 | <p>The following files are used:</p> 10 | <table> 11 | <tr> 12 | <td> 13 | <a class="templates:load-source" href="examples/special/i18n.html">i18n.html</a> 14 | </td> 15 | <td>This document.</td> 16 | </tr> 17 | <tr> 18 | <td> 19 | <a class="templates:load-source" href="modules/i18n.xql">i18n.xql</a> 20 | </td> 21 | <td>The i18n library module.</td> 22 | </tr> 23 | <tr> 24 | <td> 25 | <a class="templates:load-source" href="data/i18n/collection_es.xml">collection_es.xml</a> 26 | </td> 27 | <td>The catalogue file for the Spanish translation.</td> 28 | </tr> 29 | <tr> 30 | <td> 31 | <a class="templates:load-source" href="data/i18n/collection_de.xml">collection_de.xml</a> 32 | </td> 33 | <td>The catalogue file for the German translation.</td> 34 | </tr> 35 | </table> 36 | <h2>i18n:text</h2> 37 | <div class="section"> 38 | <p>Markup</p> 39 | <div class="markup"> 40 | <pre><i18n:text key="translateSimpleText">Translate simple text</i18n:text></pre> 41 | </div> 42 | <p>Result</p> 43 | <div class="example-output"> 44 | <i18n:text key="translateSimpleText">Translate simple text</i18n:text> 45 | </div> 46 | </div> 47 | <h2>i18n:translate (numerical)</h2> 48 | <div class="section"> 49 | <p>Markup</p> 50 | <div class="markup"> 51 | <pre><i18n:translate> 52 | <i18n:text key="translateTextWithNumericalPropertiesSample">Text to translate with {2} parameters to substitute (in {1} order)</i18n:text> 53 | <i18n:param>numerical</i18n:param> 54 | <i18n:param>2</i18n:param> 55 | </i18n:translate> 56 | </pre> 57 | </div> 58 | <p>Result</p> 59 | <div class="example-output"> 60 | <i18n:translate> 61 | <i18n:text key="translateTextWithNumericalPropertiesSample">Text to translate with {2} parameters to substitute (in {1} order)</i18n:text> 62 | <i18n:param>numerical</i18n:param> 63 | <i18n:param>2</i18n:param> 64 | </i18n:translate> 65 | </div> 66 | </div> 67 | <h2>i18n:translate (alphabetical)</h2> 68 | <div class="section"> 69 | <p>Markup</p> 70 | <div class="markup"> 71 | <pre><i18n:translate> 72 | <i18n:text key="translateTextWithAlphabeticalPropertiesSample">Text to translate with {number} parameters to substitute (in {alphabetical} order)</i18n:text> 73 | <i18n:param key="alphabetical">alphabetical</i18n:param> 74 | <i18n:param key="number">2</i18n:param> 75 | </i18n:translate></pre> 76 | </div> 77 | <p>Result</p> 78 | <div class="example-output"> 79 | <i18n:translate> 80 | <i18n:text key="translateTextWithAlphabeticalPropertiesSample">Text to translate with {number} parameters to substitute (in {alphabetical} order)</i18n:text> 81 | <i18n:param key="alphabetical">alphabetical</i18n:param> 82 | <i18n:param key="number">2</i18n:param> 83 | </i18n:translate> 84 | </div> 85 | </div> 86 | <h2>i18n:translate (with translated parameter in numerical order)</h2> 87 | <div class="section"> 88 | <p>Markup </p> 89 | <div class="markup"> 90 | <pre><i18n:translate> 91 | <i18n:text key="translateTextWithTranslatedNumericalPropertiesSample">Text to translate with {1} to substitute</i18n:text> 92 | <i18n:param> 93 | <i18n:text key="translatedParameterValue">translated Parameter</i18n:text> 94 | </i18n:param> 95 | </i18n:translate> 96 | </pre> 97 | </div> 98 | <p>Result</p> 99 | <div class="example-output"> 100 | <i18n:translate> 101 | <i18n:text key="translateTextWithTranslatedNumericalPropertiesSample">Text to translate with {1} to substitute</i18n:text> 102 | <i18n:param> 103 | <i18n:text key="translatedParameterValue">translated Parameter</i18n:text> 104 | </i18n:param> 105 | </i18n:translate> 106 | </div> 107 | </div> 108 | <h2>i18n:translate (with translated parameter in alphabetical order)</h2> 109 | <div class="section"> 110 | <p>Markup </p> 111 | <div class="markup"> 112 | <pre><i18n:translate> 113 | <i18n:text key="translateTextWithTranslatedAlphabeticalPropertiesSample">Text to translate with{translatedParameter} to substitute</i18n:text> 114 | <i18n:param key="translatedParameter"> 115 | <i18n:text key="translatedParameterValue">translated Parameter</i18n:text> 116 | </i18n:param> 117 | </i18n:translate></pre> 118 | </div> 119 | <p>Result</p> 120 | <div class="example-output"> 121 | <i18n:translate> 122 | <i18n:text key="translateTextWithTranslatedAlphabeticalPropertiesSample">Text to translate with{translatedParameter} to substitute</i18n:text> 123 | <i18n:param key="translatedParameter"> 124 | <i18n:text key="translatedParameterValue">translated Parameter</i18n:text> 125 | </i18n:param> 126 | </i18n:translate> 127 | </div> 128 | </div> 129 | <h2>Attribute translation</h2> 130 | <div class="section"> 131 | <p>Markup </p> 132 | <div class="markup"> 133 | <pre><div id="testLocalizedAttributes" name="i18n(key1)" title="i18n(key2,defaultValue1)" class="i18n(nonExistingKey,value_for_not_existing_key)"/></pre> 134 | </div> 135 | <p>Result (take a look at the markup to verify the result)</p> 136 | <div class="example-output"> 137 | <div id="testLocalizedAttributes" name="i18n(key1)" title="i18n(key2,defaultValue1)" class="i18n(nonExistingKey,value_for_not_existing_key)">translated attributes</div> 138 | </div> 139 | </div> 140 | </div> 141 | </div> 142 | -------------------------------------------------------------------------------- /examples/special/index.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <div class="templates:surround?with=templates/page.html&at=content"> 3 | <h1>Advanced Features</h1> 4 | <p>Demos for various advanced features of eXist:</p> 5 | <dl> 6 | <dt> 7 | <a href="json.html">JSON Serializer</a> 8 | </dt> 9 | <dd>Demonstrates serialization of XQuery results as JSON.</dd> 10 | <dt> 11 | <a href="i18n.html">i18n Internationalization Module</a> 12 | </dt> 13 | <dd>The i18n module helps with translating labels on a website.</dd> 14 | </dl> 15 | <div class="source-links"> 16 | <p>View source: <a href="examples/special/index.html" class="templates:load-source">this page</a>.</p> 17 | </div> 18 | </div> -------------------------------------------------------------------------------- /examples/special/json.html: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <html xmlns="http://www.w3.org/1999/xhtml"> 3 | <head> 4 | <title>Demo App 5 | 6 | 7 | 8 | 27 | 28 | 29 |
30 |

JSON Serialization Demo

31 |

eXist supports various serializers for writing out the results of an XQuery script. One of the 32 | most useful is the JSON serializer, which transforms the XML output of an XQuery into JSON.

33 |

This example embeds the jQuery dynatree widget to display the current database collection hierarchy 34 | as a tree. The tree is loaded via an AJAX call to the XQuery json.xql, which returns 35 | data in the JSON format as expected by the dynatree widget.

36 |
37 | 41 |
42 | 43 | -------------------------------------------------------------------------------- /examples/special/json.xql: -------------------------------------------------------------------------------- 1 | xquery version "1.0"; 2 | 3 | declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; 4 | declare namespace json="http://www.json.org"; 5 | 6 | (: Switch to JSON serialization :) 7 | declare option output:method "json"; 8 | declare option output:media-type "text/javascript"; 9 | 10 | (:~ 11 | : Travers the sub collections of the specified root collection. 12 | : 13 | : @param $root the path of the root collection to process 14 | :) 15 | declare function local:sub-collections($root as xs:string) { 16 | let $children := xmldb:get-child-collections($root) 17 | for $child in $children 18 | return 19 | 20 | { local:collections(concat($root, '/', $child), $child) } 21 | 22 | }; 23 | 24 | (:~ 25 | : Generate metadata for a collection. Recursively process sub collections. 26 | : 27 | : @param $root the path to the collection to process 28 | : @param $label the label (name) to display for this collection 29 | :) 30 | declare function local:collections($root as xs:string, $label as xs:string) { 31 | ( 32 | {$label}, 33 | true, 34 | {$root}, 35 | if (sm:has-access($root, "rx")) then 36 | local:sub-collections($root) 37 | else 38 | () 39 | ) 40 | }; 41 | 42 | let $collection := request:get-parameter("root", "/db/apps") 43 | return 44 | 45 | {local:collections($collection, replace($collection, "^.*/([^/]+$)", "$1"))} 46 | -------------------------------------------------------------------------------- /examples/templating/examples.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | module namespace ex="http://exist-db.org/apps/demo/templating/examples"; 4 | 5 | import module namespace config="http://exist-db.org/xquery/apps/config" at "../../modules/config.xqm"; 6 | 7 | declare namespace templates="http://exist-db.org/xquery/templates"; 8 | 9 | (:~ 10 | : Simple templating function. A templating function needs to take two parameters at least. 11 | : It may return any sequence, which will be inserted into the output instead of $node. 12 | : 13 | : @param $node the HTML node which contained the class attribute which triggered this call. 14 | : @param $model an arbitrary sequence of items. Use this to pass required information between 15 | : tempate functions. 16 | :) 17 | declare function ex:hello($node as node()*, $model as map(*)) as element(span) { 18 | Hello World! 19 | }; 20 | 21 | (:~ 22 | : A templating function taking two additional parameters. The templating framework inspects 23 | : the function signature and tries to fill in additional parameters automatically. The value 24 | : to use is determined as follows: 25 | : 26 | :
    27 | :
  1. if there's a (non-empty) request parameter with the same name as the variable, use it
  2. 28 | :
  3. else if there's a (non-empty) session attribute with the same name as the variable, use it
  4. 29 | :
  5. test if there's an annotation %templates:default(name, value) whose first parameter matches 30 | : the name of the parameter variable. Use the second parameter as value if it does.
  6. 31 | :
32 | :) 33 | declare function ex:multiply($node as node()*, $model as map(*), $n1 as xs:int, $n2 as xs:int) { 34 | $n1 * $n2 35 | }; 36 | 37 | declare 38 | %templates:wrap %templates:default("language", "en") 39 | function ex:hello-world($node as node(), $model as map(*), $language as xs:string, $user as xs:string) as xs:string { 40 | switch($language) 41 | case "de" return 42 | "Hallo " || $user 43 | case "it" return 44 | "Ciao " || $user 45 | default return 46 | "Hello " || $user 47 | }; 48 | 49 | declare 50 | %templates:wrap 51 | function ex:addresses($node as node(), $model as map(*)) as map(*) { 52 | map { "addresses": collection($config:app-root || "/data/addresses")/address } 53 | }; 54 | 55 | declare 56 | %templates:wrap 57 | function ex:print-name($node as node(), $model as map(*)) { 58 | $model("address")/name/string() 59 | }; 60 | 61 | declare 62 | %templates:wrap 63 | function ex:print-city($node as node(), $model as map(*)) { 64 | $model("address")/city/string() 65 | }; 66 | 67 | declare 68 | %templates:wrap 69 | function ex:print-street($node as node(), $model as map(*)) { 70 | $model("address")/street/string() 71 | }; -------------------------------------------------------------------------------- /examples/templating/restxq-demo.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | module namespace demo="http://exist-db.org/apps/restxq/demo"; 4 | 5 | import module namespace ex="http://exist-db.org/apps/demo/templating/examples" at "examples.xql"; 6 | import module namespace templates="http://exist-db.org/xquery/templates"; 7 | import module namespace req="http://exquery.org/ns/request"; 8 | 9 | declare namespace rest="http://exquery.org/ns/restxq"; 10 | declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization"; 11 | 12 | (:~ 13 | : Demonstrates how to call HTML templating from within a RestXQ function. 14 | :) 15 | declare 16 | %rest:GET 17 | %rest:path("/page") 18 | %output:media-type("text/html") 19 | %output:method("html5") 20 | function demo:page() { 21 | let $content := doc("restxq-page.html") 22 | let $config := map { 23 | (: The following function will be called to look up template parameters :) 24 | $templates:CONFIG_PARAM_RESOLVER : function($param as xs:string) as xs:string* { 25 | req:parameter($param) 26 | } 27 | } 28 | let $lookup := function($functionName as xs:string, $arity as xs:int) { 29 | try { 30 | function-lookup(xs:QName($functionName), $arity) 31 | } catch * { 32 | () 33 | } 34 | } 35 | return 36 | templates:apply($content, $lookup, (), $config) 37 | }; -------------------------------------------------------------------------------- /examples/templating/restxq-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HTML Templating with RestXQ 5 | 6 | 7 | 8 | 64 |
-------------------------------------------------------------------------------- /examples/web/shakespeare.xql: -------------------------------------------------------------------------------- 1 | module namespace shakes="http://exist-db.org/apps/demo/shakespeare"; 2 | 3 | import module namespace config="http://exist-db.org/xquery/apps/config" at "../../modules/config.xqm"; 4 | import module namespace templates="http://exist-db.org/xquery/templates" at "../../modules/templates.xql"; 5 | import module namespace kwic="http://exist-db.org/xquery/kwic" 6 | at "resource:org/exist/xquery/lib/kwic.xql"; 7 | 8 | declare variable $shakes:SESSION := "shakespeare:results"; 9 | 10 | (:~ 11 | : Execute a query and pass the result to nested template functions. This function returns 12 | : a map, not a node. The templating module recognizes this and will merge the map into 13 | : the current model, then continue processing any children of $node. 14 | : 15 | : The annotation %templates:wrap indicates that the current element (in $node) should be preserved. 16 | : The templating module copies the current element and its attributes, before processing 17 | : its children. 18 | :) 19 | declare 20 | %templates:wrap 21 | function shakes:query($node as node()*, $model as map(*), $query as xs:string?, $mode as xs:string?) { 22 | session:create(), 23 | let $hits := shakes:do-query($query, $mode) 24 | let $store := session:set-attribute($shakes:SESSION, $hits) 25 | return 26 | map:entry("hits", $hits) 27 | }; 28 | 29 | declare function shakes:do-query($queryStr as xs:string?, $mode as xs:string?) { 30 | let $query := shakes:create-query($queryStr, $mode) 31 | for $hit in collection($config:app-root)//SCENE[ft:query(., $query)] 32 | order by ft:score($hit) descending 33 | return $hit 34 | }; 35 | 36 | (:~ 37 | Read the last query result from the HTTP session and pass it to nested templates 38 | in the $model parameter. 39 | :) 40 | declare 41 | %templates:wrap 42 | function shakes:from-session($node as node()*, $model as map(*)) { 43 | map:entry("hits", session:get-attribute($shakes:SESSION)) 44 | }; 45 | 46 | (:~ 47 | : Create a span with the number of items in the current search result. 48 | : The annotation %templates:output("wrap") tells the templating module 49 | : to create a new element with the same name and attributes as $node, 50 | : using the return value of the function as its content. 51 | :) 52 | declare 53 | %templates:wrap 54 | function shakes:hit-count($node as node()*, $model as map(*)) { 55 | count($model("hits")) 56 | }; 57 | 58 | (:~ 59 | : Output the actual search result as a div, using the kwic module to summarize full text matches. 60 | :) 61 | declare 62 | %templates:default("start", 1) 63 | function shakes:show-hits($node as node()*, $model as map(*), $start as xs:int) { 64 | for $hit at $p in subsequence($model("hits"), $start, 10) 65 | let $kwic := kwic:summarize($hit, , shakes:filter#2) 66 | return 67 |
68 |

{$hit/ancestor::PLAY/TITLE/text()}

69 |

{$hit/TITLE/text()}

70 | {$start + $p - 1} 71 | { $kwic }
72 |
73 | }; 74 | 75 | (:~ 76 | Callback function called from the kwic module. 77 | :) 78 | declare %private function shakes:filter($node as node(), $mode as xs:string?) as text()? { 79 | if ($node/parent::SPEAKER or $node/parent::STAGEDIR) then 80 | () 81 | else if ($mode eq 'before') then 82 | text { concat($node, ' ') } 83 | else 84 | text { concat(' ', $node) } 85 | }; 86 | 87 | (:~ 88 | Helper function: create a lucene query from the user input 89 | :) 90 | declare function shakes:create-query($queryStr as xs:string?, $mode as xs:string?) { 91 | 92 | { 93 | if ($mode eq 'any') then 94 | for $term in tokenize($queryStr, '\s') 95 | return 96 | {$term} 97 | else if ($mode eq 'all') then 98 | for $term in tokenize($queryStr, '\s') 99 | return 100 | {$term} 101 | else if ($mode eq 'phrase') then 102 | {$queryStr} 103 | else 104 | {$queryStr} 105 | } 106 | 107 | }; 108 | -------------------------------------------------------------------------------- /examples/xforms/controller.xql: -------------------------------------------------------------------------------- 1 | xquery version "1.0"; 2 | 3 | (: 4 | : Main controller. 5 | :) 6 | import module namespace demo="http://exist-db.org/apps/restxq/demo" at "restxq-demo.xql"; 7 | 8 | declare variable $exist:path external; 9 | declare variable $exist:resource external; 10 | declare variable $exist:controller external; 11 | 12 | (:~ 13 | : Redirect requests for / to demo.html. 14 | :) 15 | if ($exist:path = "/") then 16 | 17 | 18 | 19 | 20 | else if (ends-with($exist:resource, ".html")) then 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | else if (contains($exist:path, "/$shared/")) then 32 | 33 | 34 | 35 | 36 | 37 | 38 | else if (starts-with($exist:path, "/resources")) then 39 | (: images, css are contained in the top /resources/ collection. :) 40 | (: Relative path requests from sub-collections are redirected there :) 41 | 42 | 43 | 44 | 45 | else 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/xforms/demo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | name 18 | 19 | 20 | 26 | 27 | 28 | Address list loaded. 29 | 30 | 31 | Address saved. 32 | An error occurred. 33 | 34 | 35 | Address deleted. 36 | An error occurred. 37 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |
45 | 48 |

Manage Addresses

49 | 50 | 51 | 68 | 76 | 84 | 85 |
52 | 53 | 54 | 55 | Name 56 | name 57 | 58 | 59 | Street 60 | street 61 | 62 | 63 | City 64 | city 65 | 66 | 67 | 69 | 70 | 71 | Filter displayed addresses by entering a few characters contained 72 | in a name, street or city. 73 | 74 | 75 | 77 | 78 | Clear 79 | 80 | 81 | 82 | 83 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 97 | 100 | 103 | 104 | 105 |
NameStreetCity
95 | 96 | 98 | 99 | 101 | 102 |
106 | 107 | 108 | Delete 109 | 110 | 111 | New 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Name: 120 | 121 | 122 | Street: 123 | 124 | 125 | City: 126 | 127 | 128 | 129 | Save 130 | 131 |
132 |
133 |
134 |

A simple XForms application which talks to a RESTXQ service defining the following endpoints:

135 |
    136 |
  • GET /address
  • 137 |
  • GET /address/{$id}
  • 138 |
  • PUT /address
  • 139 |
  • DELETE /address/{$id}
  • 140 |
  • GET /search?query=&field=
  • 141 |
142 |

It uses a number of XForms submissions to retrieve data, search, save or delete entries.

143 |

The XForms code is in demo.html. The RestXQ endpoints 144 | are defined in restxq-demo.xql. 145 |

146 |
147 |
148 |
149 |
-------------------------------------------------------------------------------- /examples/xforms/restxq-demo.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | (: 4 | : Defines all the RestXQ endpoints used by the XForms. 5 | :) 6 | module namespace demo="http://exist-db.org/apps/restxq/demo"; 7 | 8 | import module namespace config="http://exist-db.org/xquery/apps/config" at "../../modules/config.xqm"; 9 | 10 | declare namespace rest="http://exquery.org/ns/restxq"; 11 | declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization"; 12 | 13 | declare variable $demo:data := $config:app-root || "/data/addresses"; 14 | 15 | (:~ 16 | : List all addresses and return them as XML. 17 | :) 18 | declare 19 | %rest:GET 20 | %rest:path("/address") 21 | %rest:produces("application/xml", "text/xml") 22 | function demo:addresses() { 23 | 24 | { 25 | for $address in collection($config:app-root || "/data/addresses")/address 26 | return 27 | $address 28 | } 29 | 30 | }; 31 | 32 | (:~ 33 | : Test: list all addresses in JSON format. For this function to be chosen, 34 | : the client should send an Accept header containing application/json. 35 | :) 36 | (:declare:) 37 | (: %rest:GET:) 38 | (: %rest:path("/address"):) 39 | (: %rest:produces("application/json"):) 40 | (: %output:media-type("application/json"):) 41 | (: %output:method("json"):) 42 | (:function demo:addresses-json() {:) 43 | (: demo:addresses():) 44 | (:};:) 45 | 46 | (:~ 47 | : Retrieve an address identified by uuid. 48 | :) 49 | declare 50 | %rest:GET 51 | %rest:path("/address/{$id}") 52 | function demo:get-address($id as xs:string*) { 53 | collection($demo:data)/address[@id = $id] 54 | }; 55 | 56 | (:~ 57 | : Search addresses using a given field and a (lucene) query string. 58 | :) 59 | declare 60 | %rest:GET 61 | %rest:path("/search") 62 | %rest:form-param("query", "{$query}", "") 63 | %rest:form-param("field", "{$field}", "name") 64 | function demo:search-addresses($query as xs:string*, $field as xs:string*) { 65 | 66 | { 67 | if ($query != "") then 68 | switch ($field) 69 | case "name" return 70 | collection($demo:data)/address[ngram:contains(name, $query)] 71 | case "street" return 72 | collection($demo:data)/address[ngram:contains(street, $query)] 73 | case "city" return 74 | collection($demo:data)/address[ngram:contains(city, $query)] 75 | default return 76 | collection($demo:data)/address[ngram:contains(., $query)] 77 | else 78 | collection($demo:data)/address 79 | } 80 | 81 | }; 82 | 83 | (:~ 84 | : Update an existing address or store a new one. The address XML is read 85 | : from the request body. 86 | :) 87 | declare 88 | %rest:PUT("{$content}") 89 | %rest:path("/address") 90 | function demo:create-or-edit-address($content as node()*) { 91 | let $id := ($content/address/@id, util:uuid())[1] 92 | let $data := 93 |
94 | { $content/address/* } 95 |
96 | let $log := util:log("DEBUG", "Storing data into " || $demo:data) 97 | let $stored := xmldb:store($demo:data, $id || ".xml", $data) 98 | return 99 | demo:addresses() 100 | }; 101 | 102 | (:~ 103 | : Delete an address identified by its uuid. 104 | :) 105 | declare 106 | %rest:DELETE 107 | %rest:path("/address/{$id}") 108 | function demo:delete-address($id as xs:string*) { 109 | xmldb:remove($demo:data, $id || ".xml"), 110 | demo:addresses() 111 | }; -------------------------------------------------------------------------------- /expath-pkg.xml.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | eXist-db Demo Apps 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

eXist XQuery Features Demo

4 |

This application contains various small demos for particular eXist-db features:

5 | 37 |

External Demos

38 |

Our showcases server hosts or links to a number of applications 39 | whose code is available on github or elsewhere and can be studied. All applications share a similar technology stack and setup, so they 40 | are a good source for inspiration and show what can be done with eXistdb.

41 | 44 |
-------------------------------------------------------------------------------- /modules/cex-trigger.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | module namespace trigger="http://exist-db.org/xquery/trigger"; 4 | 5 | declare namespace xhtml="http://www.w3.org/1999/xhtml"; 6 | 7 | import module namespace content="http://exist-db.org/xquery/contentextraction" 8 | at "java:org.exist.contentextraction.xquery.ContentExtractionModule"; 9 | 10 | declare function trigger:do-index($fieldName as xs:string, $value as xs:string?, $path as xs:anyURI) { 11 | let $index := 12 | 13 | {$value} 14 | 15 | let $null := ft:index($path, $index, false()) 16 | return 17 | () 18 | }; 19 | 20 | declare function trigger:index-callback($root as element(), $path as xs:anyURI, $page as xs:integer?) { 21 | typeswitch ($root) 22 | case element(xhtml:meta) return 23 | ( trigger:do-index($root/@name, $root/@content/string(), $path), $page ) 24 | case element(xhtml:title) return 25 | ( trigger:do-index("Title", $root/text(), $path), $page) 26 | default return 27 | if ($root/@class eq 'page') then 28 | let $page := if (empty($page)) then 1 else $page + 1 29 | return 30 | ( trigger:do-index("page", concat("[[", $page, "]]", string-join($root//xhtml:p/string(), " ")), $path), $page ) 31 | else 32 | $page 33 | }; 34 | 35 | declare function trigger:index($uri as xs:anyURI) { 36 | if (util:is-binary-doc($uri)) then 37 | let $doc := util:binary-doc($uri) 38 | return 39 | if (ends-with($uri, ".pdf")) then 40 | let $callback := trigger:index-callback#3 41 | let $namespaces := 42 | 43 | let $index := 44 | content:stream-content($doc, ("//xhtml:meta", "//xhtml:title", "//xhtml:div"), $callback, $namespaces, $uri) 45 | return 46 | ft:close() 47 | else 48 | let $content := content:get-metadata-and-content($doc) 49 | let $idxDoc := 50 | 51 | {string-join($content//xhtml:body//text(), " ")} 52 | 53 | return 54 | ft:index($uri, $idxDoc, true()) 55 | else 56 | () 57 | }; 58 | 59 | declare function trigger:after-create-document($uri as xs:anyURI) { 60 | trigger:index($uri) 61 | }; 62 | 63 | declare function trigger:after-update-document($uri as xs:anyURI) { 64 | trigger:index($uri) 65 | }; -------------------------------------------------------------------------------- /modules/cex.xql: -------------------------------------------------------------------------------- 1 | module namespace cex="http://exist-db.org/apps/demo/cex"; 2 | 3 | import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; 4 | import module namespace kwic="http://exist-db.org/xquery/kwic" 5 | at "resource:org/exist/xquery/lib/kwic.xql"; 6 | 7 | declare function cex:query($node as node()*, $model as map(*), $query as xs:string?) { 8 |
9 | { 10 | for $result in ft:search("/db/", concat('page:', $query))/search 11 | let $fields := $result/field 12 | (: Retrieve title from title field if available :) 13 | let $titleField := ft:get-field($result/@uri, "Title") 14 | let $title := if ($titleField) then $titleField else replace($result/@uri, "^.*/([^/]+)$", "$1") 15 | let $contentType := ft:get-field($result/@uri, "Content-Type") 16 | return 17 |
18 |

{$title} - Score: {$result/@score/string()}

19 |

Type: { $contentType }

20 |

Found matches in {count($fields[.//exist:match])} of the {count($fields)} page{if (count($fields) gt 1) then 's' else ''} of the document. {if (count($fields[.//exist:match]) gt 10) then 'Only matches from the first 10 pages with matches are shown.' else ''}

21 | { 22 | let $groupsRegex := "\[\[([0-9]+)" 23 | for $field in subsequence($fields[.//exist:match], 1, 10) 24 | let $page := analyze-string($field, $groupsRegex)//fn:group/string() 25 | return 26 |

27 | { concat("page ", $page) } 28 | {kwic:summarize($field, )} 29 |

30 | } 31 |
32 | } 33 |
34 | }; 35 | -------------------------------------------------------------------------------- /modules/config.xqm: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | (:~ 4 | : A set of helper functions to access the application context from 5 | : within a module. 6 | :) 7 | module namespace config="http://exist-db.org/xquery/apps/config"; 8 | 9 | import module namespace templates="http://exist-db.org/xquery/templates"; 10 | 11 | declare namespace repo="http://exist-db.org/xquery/repo"; 12 | declare namespace expath="http://expath.org/ns/pkg"; 13 | 14 | (: 15 | Determine the application root collection from the current module load path. 16 | :) 17 | declare variable $config:app-root := 18 | let $rawPath := system:get-module-load-path() 19 | let $modulePath := 20 | (: strip the xmldb: part :) 21 | if (starts-with($rawPath, "xmldb:exist://")) then 22 | if (starts-with($rawPath, "xmldb:exist://embedded-eXist-server")) then 23 | substring($rawPath, 36) 24 | else 25 | substring($rawPath, 15) 26 | else 27 | $rawPath 28 | return 29 | substring-before($modulePath, "/modules") 30 | ; 31 | 32 | declare variable $config:repo-descriptor := doc(concat($config:app-root, "/repo.xml"))/repo:meta; 33 | 34 | declare variable $config:expath-descriptor := doc(concat($config:app-root, "/expath-pkg.xml"))/expath:package; 35 | 36 | (:~ 37 | : Resolve the given path using the current application context. 38 | : If the app resides in the file system, 39 | :) 40 | declare function config:resolve($relPath as xs:string) { 41 | if (starts-with($config:app-root, "/db")) then 42 | doc(concat($config:app-root, "/", $relPath)) 43 | else 44 | doc(concat("file://", $config:app-root, "/", $relPath)) 45 | }; 46 | 47 | (:~ 48 | : Returns the repo.xml descriptor for the current application. 49 | :) 50 | declare function config:repo-descriptor() as element(repo:meta) { 51 | $config:repo-descriptor 52 | }; 53 | 54 | (:~ 55 | : Returns the expath-pkg.xml descriptor for the current application. 56 | :) 57 | declare function config:expath-descriptor() as element(expath:package) { 58 | $config:expath-descriptor 59 | }; 60 | 61 | declare %templates:wrap function config:app-title($node as node(), $model as map(*)) as text() { 62 | $config:expath-descriptor/expath:title/text() 63 | }; 64 | 65 | declare function config:app-meta($node as node(), $model as map(*)) as element()* { 66 | , 67 | for $author in $config:repo-descriptor/repo:author 68 | return 69 | 70 | }; 71 | 72 | (:~ 73 | : For debugging: generates a table showing all properties defined 74 | : in the application descriptors. 75 | :) 76 | declare function config:app-info($node as node(), $model as map(*)) { 77 | let $expath := config:expath-descriptor() 78 | let $repo := config:repo-descriptor() 79 | return 80 | 81 | 82 | 83 | 84 | 85 | { 86 | for $attr in ($expath/@*, $expath/*, $repo/*) 87 | return 88 | 89 | 90 | 91 | 92 | } 93 | 94 | 95 | 96 | 97 |
app collection:{$config:app-root}
{node-name($attr)}:{$attr/string()}
Controller:{ request:get-attribute("$exist:controller") }
98 | }; -------------------------------------------------------------------------------- /modules/demo.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.1"; 2 | 3 | module namespace demo="http://exist-db.org/apps/demo"; 4 | 5 | import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; 6 | import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; 7 | 8 | import module namespace templates="http://exist-db.org/xquery/templates"; 9 | 10 | declare function demo:error-handler-test($node as node(), $model as map(*), $number as xs:string?) { 11 | if (exists($number)) then 12 | xs:int($number) 13 | else 14 | () 15 | }; 16 | 17 | declare function demo:link-to-home($node as node(), $model as map(*)) { 18 | { 19 | $node/@* except $node/@href, 20 | $node/node() 21 | } 22 | }; 23 | 24 | declare function demo:run-tests($node as node(), $model as map(*)) { 25 | let $results := test:suite(inspect:module-functions(xs:anyURI("../examples/tests/shakespeare-tests.xql"))) 26 | return 27 | test:to-html($results) 28 | }; 29 | 30 | declare function demo:display-source($node as node(), $model as map(*), $lang as xs:string?, $type as xs:string?) { 31 | let $source := $node/string() => replace('^\s+','') => replace('\s+$','') 32 | let $expanded := replace($source, "@@path", $config:app-root) 33 | let $eXideLink := templates:link-to-app("http://exist-db.org/apps/eXide", "index.html?snip=" || encode-for-uri($expanded)) 34 | return 35 |
36 |
{ $expanded }
37 |
38 |
39 | 40 | Run 41 | 44 | Edit 45 |
46 | 47 |
48 |
49 |
50 | }; -------------------------------------------------------------------------------- /modules/i18n-templates.xql: -------------------------------------------------------------------------------- 1 | module namespace intl="http://exist-db.org/xquery/i18n/templates"; 2 | 3 | (:~ 4 | : i18n template functions. Integrates the i18n library module. Called from the templating framework. 5 | :) 6 | import module namespace i18n="http://exist-db.org/xquery/i18n" at "../modules/i18n.xql"; 7 | import module namespace templates="http://exist-db.org/xquery/templates"; 8 | import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; 9 | 10 | (:~ 11 | : Template function: calls i18n:process on the child nodes of $node. 12 | : Template parameters: 13 | : lang=de Language selection 14 | : catalogues=relative path Path to the i18n catalogue XML files inside database 15 | :) 16 | declare function intl:translate($node as node(), $model as map(*), $lang as xs:string?, $catalogues as xs:string?) { 17 | let $cpath := 18 | (: if path to catalogues is relative, resolve it relative to the app root :) 19 | if (starts-with($catalogues, "/")) then 20 | $catalogues 21 | else 22 | concat($config:app-root, "/", $catalogues) 23 | let $translated := 24 | i18n:process($node/*, $lang, $cpath, ()) 25 | return 26 | element { node-name($node) } { 27 | $node/@*, 28 | templates:process($translated, $model) 29 | } 30 | }; -------------------------------------------------------------------------------- /modules/i18n.xql: -------------------------------------------------------------------------------- 1 | module namespace i18n = 'http://exist-db.org/xquery/i18n'; 2 | (:~ 3 | : I18N Internationalization Module 4 | 5 | : @author Lars Windauer 6 | : @author Tobias Krebs 7 | :) 8 | 9 | (:~ 10 | : Start processing the provided content using the modules defined by $modules. $modules should 11 | : be an XML fragment following the scheme: 12 | : 13 | : 14 | : 15 | : 16 | : 17 | : @param $content the sequence of nodes which will be processed 18 | : @param $modules modules to import 19 | : @param $model a sequence of items which will be passed to all called template functions. Use this to pass 20 | : information between templating instructions. 21 | :) 22 | declare function i18n:apply($content as node()+, $modules as element(modules), $model as item()*) { 23 | let $null := ( 24 | request:set-attribute("$i18n:modules", $modules) 25 | ) 26 | for $root in $content 27 | return 28 | i18n:process($root, (),(),()) 29 | }; 30 | 31 | (:~ 32 | : Continue template processing on the given set of nodes. Call this function from 33 | : within other template functions to enable recursive processing of templates. 34 | : 35 | : @param $nodes the nodes to process 36 | : @param $model a sequence of items which will be passed to all called template functions. Use this to pass 37 | : information between templating instructions. 38 | :) 39 | declare function i18n:process($nodes as node()*, $selectedLang as xs:string,$pathToCatalogues as xs:string, $defaultLang as xs:string?) { 40 | for $node in $nodes 41 | let $selectedCatalogue := i18n:getLanguageCollection($nodes,$selectedLang, $pathToCatalogues,$defaultLang) 42 | return 43 | i18n:process($node, $selectedCatalogue) 44 | }; 45 | 46 | (:~ 47 | : recursive function to traverse through the document and to process all i18n prefixed nodes 48 | : 49 | : @param $node node to analyse if is an i18n:* node 50 | : @param $model a sequence of items which will be passed to all called template functions. Use this to pass 51 | : information between templating instructions. 52 | :) 53 | declare function i18n:process($node as node(), $selectedCatalogue as node()) { 54 | typeswitch ($node) 55 | case document-node() return 56 | for $child in $node/node() return i18n:process($child, $selectedCatalogue) 57 | 58 | case element(i18n:translate) return 59 | let $text := i18n:process($node/i18n:text,$selectedCatalogue) 60 | return 61 | i18n:translate($node, $text,$selectedCatalogue) 62 | 63 | case element(i18n:text) return 64 | i18n:getLocalizedText($node,$selectedCatalogue) 65 | 66 | case element() return 67 | element { node-name($node) } { 68 | i18n:translateAttributes($node,$selectedCatalogue), 69 | for $child in $node/node() return i18n:process($child,$selectedCatalogue) 70 | } 71 | 72 | default return 73 | $node 74 | }; 75 | 76 | declare function i18n:translateAttributes($node as node(), $selectedCatalogue as node()){ 77 | for $attribute in $node/@* 78 | return i18n:translateAttribute($attribute, $node, $selectedCatalogue) 79 | }; 80 | 81 | declare function i18n:translateAttribute($attribute as attribute(), $node as node(),$selectedCatalogue as node()){ 82 | if(starts-with($attribute, 'i18n(')) then 83 | let $key := 84 | if(contains($attribute, ",")) then 85 | substring-before(substring-after($attribute,"i18n("),",") 86 | else 87 | substring-before(substring-after($attribute,"i18n("),")") 88 | let $i18nValue := 89 | if(exists($selectedCatalogue//msg[@key eq $key])) then 90 | $selectedCatalogue//msg[@key eq $key]/text() 91 | else 92 | substring-before(substring-after(substring-after($attribute,"i18n("),","),")") 93 | return 94 | attribute {name($attribute)} {$i18nValue} 95 | else 96 | $attribute 97 | 98 | 99 | }; 100 | 101 | 102 | (: 103 | : Get the localized value for a given key from the given catalogue 104 | : if no localized value is available, the default value is used 105 | :) 106 | declare function i18n:getLocalizedText($textNode as node(), $selectedCatalogue as node()){ 107 | if(exists($selectedCatalogue//msg[@key eq $textNode/@key])) then 108 | $selectedCatalogue//msg[@key eq $textNode/@key]/text() 109 | else 110 | $textNode/text() 111 | 112 | }; 113 | 114 | (:~ 115 | : function implementing i18n:translate to enable localization of strings containing alphabetical or numerical parameters 116 | : 117 | : @param $node i18n:translate node enclosing i18n:text and parameters to substitute 118 | : @param $text the processed(!) content of i18n:text 119 | :) 120 | declare function i18n:translate($node as node(),$text as xs:string,$selectedCatalogue as node()) { 121 | if(contains($text,'{')) then 122 | (: text contains parameters to substitute :) 123 | let $params := $node//i18n:param 124 | let $paramKey := substring-before(substring-after($text, '{'),'}') 125 | return 126 | if(number($paramKey) and exists($params[position() eq number($paramKey)])) then 127 | (: numerical parameters to substituce :) 128 | let $selectedParam := $node/i18n:param[number($paramKey)] 129 | return 130 | i18n:replaceParam($node, $selectedParam,$paramKey, $text,$selectedCatalogue) 131 | else if(exists($params[@key eq $paramKey])) then 132 | (: alphabetical parameters to substituce :) 133 | let $selectedParam := $params[@key eq $paramKey] 134 | return 135 | i18n:replaceParam($node, $selectedParam,$paramKey, $text,$selectedCatalogue) 136 | 137 | else 138 | (: ERROR while processing parmaters to substitute:) 139 | concat("ERROR: Parameter ", $paramKey, " could not be substituted") 140 | else 141 | $text 142 | }; 143 | 144 | (:~ 145 | : function replacing the parameter with its (localized) value 146 | : 147 | : @param $node i18n:translate node enclosing i18n:text and parameters to substitute 148 | : @param $param currently processed i18n:param as node() 149 | : @param $paramKey currently processed parameterKey (numerical or alphabetical) 150 | : @param $text the processed(!) content of i18n:text 151 | :) 152 | declare function i18n:replaceParam($node as node(), $param as node(),$paramKey as xs:string, $text as xs:string,$selectedCatalogue as node()) { 153 | if(exists($param/i18n:text)) then 154 | (: the parameter has to be translated as well :) 155 | let $translatedParam := i18n:getLocalizedText($param/i18n:text, $selectedCatalogue) 156 | let $result := replace($text, concat("\{", $paramKey, "\}"), $translatedParam) 157 | return i18n:translate($node,$result,$selectedCatalogue) 158 | else 159 | (: simply substitute {paramKey} with it's param value' :) 160 | let $result := replace($text, concat("\{", $paramKey, "\}"), $param) 161 | return 162 | i18n:translate($node, $result,$selectedCatalogue) 163 | }; 164 | 165 | declare function i18n:getLanguageCollection($node as node()*,$selectedLang as xs:string,$pathToCatalogues as xs:string, $defaultLang as xs:string?) { 166 | let $tmpNode := typeswitch ($node) 167 | case document-node() return $node/node() 168 | default return $node 169 | 170 | let $lang := i18n:getSelectedLanguage($tmpNode,$selectedLang) 171 | let $cataloguePath := i18n:getPathToCatalogues($tmpNode,$pathToCatalogues) 172 | return 173 | if(exists(collection($cataloguePath)//catalogue[@xml:lang eq $lang])) then 174 | collection($cataloguePath)//catalogue[@xml:lang eq $lang] 175 | else if(string-length(request:get-parameter("defaultLang", "")) gt 0) then 176 | collection($cataloguePath)//catalogue[@xml:lang eq request:get-parameter("cataloguesPath", "")] 177 | else if(string-length($defaultLang) gt 0) then 178 | collection($cataloguePath)//catalogue[@xml:lang eq $defaultLang] 179 | else if(exists($tmpNode/@i18n:default-lang)) then 180 | collection($cataloguePath)//catalogue[@xml:lang eq $tmpNode/@i18n:default-lang] 181 | else () 182 | 183 | }; 184 | 185 | declare function i18n:getPathToCatalogues($node as node()*,$pathToCatalogues as xs:string){ 186 | if(string-length($pathToCatalogues) gt 0) then 187 | $pathToCatalogues 188 | else if(string-length(request:get-parameter("cataloguesPath", "")) gt 0) then 189 | request:get-parameter("cataloguesPath", "") 190 | else if (exists($node/@i18n:catalogues)) then 191 | $node/@i18n:catalogues 192 | else 'ERROR: no path to language catalogues given' 193 | }; 194 | 195 | declare function i18n:getSelectedLanguage($node as node()*,$selectedLang as xs:string) { 196 | if(string-length(request:get-parameter("lang", "")) gt 0) then 197 | (: use http parameter lang as selected language :) 198 | request:get-parameter("lang", "") 199 | else if(exists($node/@xml:lang)) then 200 | (: use xml:lang attribute on given node as selected language :) 201 | $node/@xml:lang 202 | else if(string-length($selectedLang) gt 0) then 203 | (: use given xquery parameter as selected language :) 204 | $selectedLang 205 | else 206 | 'en' 207 | }; 208 | -------------------------------------------------------------------------------- /modules/view.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | import module namespace templates="http://exist-db.org/xquery/templates"; 4 | 5 | (: The following modules provide functions which will be called by the templating :) 6 | import module namespace shakespeare="http://exist-db.org/apps/demo/shakespeare" at "../examples/web/shakespeare.xql"; 7 | import module namespace i18n="http://exist-db.org/xquery/i18n/templates" at "i18n-templates.xql"; 8 | import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; 9 | import module namespace site="http://exist-db.org/apps/site-utils"; 10 | 11 | import module namespace demo="http://exist-db.org/apps/demo" at "demo.xql"; 12 | import module namespace guess="http://exist-db.org/apps/demo/guess" at "../examples/web/guess-templates.xql"; 13 | import module namespace cex="http://exist-db.org/apps/demo/cex" at "cex.xql"; 14 | import module namespace ex="http://exist-db.org/apps/demo/templating/examples" at "../examples/templating/examples.xql"; 15 | 16 | 17 | declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; 18 | 19 | declare option output:method "xhtml"; 20 | declare option output:media-type "text/html"; 21 | 22 | let $config := map { 23 | $templates:CONFIG_APP_ROOT : $config:app-root 24 | } 25 | let $lookup := function($functionName as xs:string, $arity as xs:int) { 26 | try { 27 | function-lookup(xs:QName($functionName), $arity) 28 | } catch * { 29 | () 30 | } 31 | } 32 | let $content := request:get-data() 33 | return 34 | templates:apply($content, $lookup, (), $config) 35 | -------------------------------------------------------------------------------- /post-install.xql: -------------------------------------------------------------------------------- 1 | xquery version "3.0"; 2 | 3 | import module namespace xdb="http://exist-db.org/xquery/xmldb"; 4 | 5 | import module namespace xrest="http://exquery.org/ns/restxq/exist" at "java:org.exist.extensions.exquery.restxq.impl.xquery.exist.ExistRestXqModule"; 6 | 7 | (: The following external variables are set by the repo:deploy function :) 8 | 9 | (: the target collection into which the app is deployed :) 10 | declare variable $target external; 11 | 12 | (: Create 'contacts/data' collection and then make writable :) 13 | xmldb:create-collection($target || "/examples/contacts", "data"), 14 | sm:chmod(xs:anyURI($target || "/examples/contacts/data"), "rwxrwxrwx"), 15 | (: Allow uploads to binary collection :) 16 | sm:chmod(xs:anyURI($target || "/data/binary"), "rwxrwxrwx"), 17 | (: Allow changes to addresses collection :) 18 | sm:chmod(xs:anyURI($target || "/data/addresses"), "rwxrwxrwx"), 19 | for $resource in xmldb:get-child-resources($target || "/data/addresses") 20 | return 21 | sm:chmod(xs:anyURI($target || "/data/addresses/" || $resource), "rwxrwxrwx"), 22 | 23 | (: Register restxq modules. Should be done automatically, but there seems to be an occasional bug :) 24 | xrest:register-module(xs:anyURI($target || "/examples/templating/restxq-demo.xql")), 25 | xrest:register-module(xs:anyURI($target || "/examples/contacts/contacts.xql")), 26 | xrest:register-module(xs:anyURI($target || "/examples/xforms/restxq-demo.xql")) -------------------------------------------------------------------------------- /pre-install.xql: -------------------------------------------------------------------------------- 1 | xquery version "1.0"; 2 | 3 | import module namespace xdb="http://exist-db.org/xquery/xmldb"; 4 | 5 | (: The following external variables are set by the repo:deploy function :) 6 | 7 | (: file path pointing to the exist installation directory :) 8 | declare variable $home external; 9 | (: path to the directory containing the unpacked .xar package :) 10 | declare variable $dir external; 11 | (: the target collection into which the app is deployed :) 12 | declare variable $target external; 13 | 14 | declare function local:mkcol-recursive($collection, $components) { 15 | if (exists($components)) then 16 | let $newColl := concat($collection, "/", $components[1]) 17 | return ( 18 | xdb:create-collection($collection, $components[1]), 19 | local:mkcol-recursive($newColl, subsequence($components, 2)) 20 | ) 21 | else 22 | () 23 | }; 24 | 25 | (: Helper function to recursively create a collection hierarchy. :) 26 | declare function local:mkcol($collection, $path) { 27 | local:mkcol-recursive($collection, tokenize($path, "/")) 28 | }; 29 | 30 | (: store the collection configuration :) 31 | local:mkcol("/db/system/config", $target), 32 | local:mkcol(concat("/system/config", $target), "data"), 33 | xdb:store-files-from-pattern(concat("/system/config", $target, "/data"), $dir, "collection.xconf"), 34 | local:mkcol(concat("/system/config", $target, "/data"), "binary"), 35 | xdb:store-files-from-pattern(concat("/system/config", $target, "/data/binary"), $dir, "data.xconf") 36 | -------------------------------------------------------------------------------- /repo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Various small demo applications. 4 | Wolfgang Meier 5 | https://github.com/eXist-db/demo-apps 6 | beta 7 | GNU-LGPL 8 | true 9 | application 10 | demo 11 | pre-install.xql 12 | post-install.xql 13 | 14 | 15 | 16 |
    17 |
  • Improved the display of search results in the content extraction demo.
  • 18 |
  • Fixed RESTXQ and AngularJS demo.
  • 19 |
  • Removed dependency on JSONXQ library, replaced with XQuery 3.1 JSON facility.
  • 20 |
21 |
22 | 23 |
    24 |
  • Adopt correct syntax for empty-sequence node test, supported from eXist-db 4.0.0
  • 25 |
26 |
27 | 28 |
    29 |
  • Updated regular expressionto make app work again.
  • 30 |
31 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /resources/css/demo.css: -------------------------------------------------------------------------------- 1 | @import url('$shared/resources/css/exist-2.2.css'); 2 | 3 | #formWrapper form { 4 | margin: 0; 5 | } 6 | 7 | dl { 8 | margin: 10px 20px; 9 | } 10 | 11 | dl dd { 12 | margin: 4px 20px; 13 | } 14 | 15 | .itemhead { background: #E0E0E0; padding-left: 8px; } 16 | 17 | .scene { 18 | margin-bottom: 1em; 19 | } 20 | 21 | .scene .number { 22 | float: right; 23 | } 24 | 25 | .scene h3, .scene h4 { 26 | border: 0; 27 | margin: 0; 28 | padding: 0; 29 | } 30 | 31 | .scene h4 { 32 | margin-left: 1em; 33 | } 34 | 35 | table .previous { 36 | text-align: right; 37 | padding-right: 1em; 38 | } 39 | 40 | table .following { 41 | padding-left: 1em; 42 | } 43 | 44 | #collection-tree ul li, #collection-tree ul li ul li { 45 | list-style-type: none; 46 | } 47 | 48 | .source .toolbar, .example-output { 49 | padding-left: 18px; 50 | border-left: 4px solid #C7C7C7; 51 | } 52 | 53 | .output { 54 | margin: 8px 0; 55 | max-height: 500px; 56 | overflow: auto; 57 | } 58 | 59 | .output .code { 60 | max-height: 200px; 61 | overflow: auto; 62 | background: #ffffff; 63 | padding: 0 8px; 64 | } 65 | 66 | .testresult td { 67 | margin: 2px 4px; 68 | padding: 8px 10px; 69 | } 70 | 71 | .testresult .fail { 72 | background-color: #D7394C; 73 | color: white; 74 | } 75 | 76 | .testresult .pass { 77 | background-color: #69EB7F; 78 | } 79 | 80 | .addresses { 81 | width: 100%; 82 | margin: 10px 0; 83 | border-top: 1px solid #777; 84 | border-bottom: 1px solid #777; 85 | padding: 10px 0; 86 | } 87 | 88 | .addresses th { 89 | font-weight: bold; 90 | } 91 | 92 | .addresses td:nth-child(1) { 93 | width: 30%; 94 | } 95 | .addresses td:nth-child(2) { 96 | width: 40%; 97 | } 98 | .addresses td:nth-child(3) { 99 | width: 30%; 100 | } 101 | 102 | .search { 103 | margin-bottom: 4px; 104 | } 105 | 106 | .switch-endpoints td { 107 | padding-right: 1em; 108 | } 109 | 110 | .load-indicator { 111 | margin-left: 30px; 112 | display: none; 113 | } -------------------------------------------------------------------------------- /resources/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/ajax-loader.gif -------------------------------------------------------------------------------- /resources/images/bold.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/bold.gif -------------------------------------------------------------------------------- /resources/images/code.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/code.gif -------------------------------------------------------------------------------- /resources/images/delete-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/delete-icon.png -------------------------------------------------------------------------------- /resources/images/eXide-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/eXide-screenshot.png -------------------------------------------------------------------------------- /resources/images/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/glyphicons-halflings.png -------------------------------------------------------------------------------- /resources/images/grey-box-bot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/grey-box-bot.gif -------------------------------------------------------------------------------- /resources/images/grey-box-rpt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/grey-box-rpt.gif -------------------------------------------------------------------------------- /resources/images/grey-box-top.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/grey-box-top.gif -------------------------------------------------------------------------------- /resources/images/italic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/italic.gif -------------------------------------------------------------------------------- /resources/images/nav-dropdown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/nav-dropdown.gif -------------------------------------------------------------------------------- /resources/images/nav-dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/nav-dropdown.png -------------------------------------------------------------------------------- /resources/images/nav.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/nav.gif -------------------------------------------------------------------------------- /resources/images/page-edit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/page-edit-icon.png -------------------------------------------------------------------------------- /resources/images/twitter-left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/twitter-left.gif -------------------------------------------------------------------------------- /resources/images/twitter-right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/twitter-right.gif -------------------------------------------------------------------------------- /resources/images/twitter-rpt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eXist-db/demo-apps/631933e874027d2a11bdfa07c9598b08fb95c556/resources/images/twitter-rpt.gif -------------------------------------------------------------------------------- /resources/scripts/demo.js: -------------------------------------------------------------------------------- 1 | 2 | $(document).ready(function() { 3 | // Enable code highlighting 4 | $(".code").highlight(); 5 | 6 | // Enable "Run" buttons 7 | $(".run").click(function(ev) { 8 | ev.preventDefault(); 9 | var type = $(this).data("type") || "xml"; 10 | var text = $(this).parent().parent().parent().find(".code").highlight("getText"); 11 | var output = $(this).parent().parent().find(".output"); 12 | var indicator = $(this).parent().parent().find(".load-indicator"); 13 | var query = 14 | "\n" + 16 | " \n" + 17 | ""; 18 | 19 | function run() { 20 | indicator.show(); 21 | output.hide(); 22 | $.ajax({ 23 | url: "/exist/rest/db/", 24 | type: "POST", 25 | contentType: "application/xml", 26 | data: query, 27 | dataType: "json", 28 | success: function(result) { 29 | indicator.hide(); 30 | var data; 31 | if (Array.isArray(result.data)) 32 | data = result.data.join("\n"); 33 | else 34 | data = result.data; 35 | if (type === "xml") { 36 | var pre = document.createElement("div"); 37 | pre.className = "code"; 38 | pre.appendChild(document.createTextNode(data)); 39 | output.html(pre); 40 | $(pre).data("language", "xml"); 41 | $(pre).highlight({ theme: "dawn" }); 42 | } else 43 | output.html(data); 44 | output.slideDown(600); 45 | } 46 | }); 47 | } 48 | 49 | if (output.is(":empty")) { 50 | run(); 51 | } else { 52 | output.slideUp(800, function() { 53 | output.empty(); 54 | run(); 55 | }); 56 | } 57 | }); 58 | }); -------------------------------------------------------------------------------- /templates/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | App Title 5 | 6 | 7 | 8 | 9 |