m

/functions.xql

(:~
    Search the built-in function library
:)
xquery version "1.0";
(: $Id: functions.xq 8359 2008-12-03 20:31:47Z wolfgang_m $ :)

declare namespace xqdoc="http://www.xqdoc.org/1.0";

import module namespace util="http://exist-db.org/xquery/util";
import module namespace request="http://exist-db.org/xquery/request";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace ngram="http://exist-db.org/xquery/ngram" at
    "java:org.exist.xquery.modules.ngram.NGramModule";

import module namespace setup="http://exist-db.org/xquery/docs/setup" at "docsetup.xql";

declare option exist:serialize "media-type=text/xml";
(:~
    Execute a query or list all functions in a given module.
:)
declare function xqdoc:do-query($action as xs:string, $module as xs:string?, $type as xs:string?, 
$qs as xs:string?, $print as xs:boolean) as element()* {
    if ($qs != '' or $module != '') then
        let $matches :=
            if ($action eq "Browse") then
                if( $module eq "All" ) then
                    /xqdoc:xqdoc//xqdoc:function
                else
                    /xqdoc:xqdoc[xqdoc:module/xqdoc:uri = $module]//xqdoc:function
            else if( $qs != '' ) then
                if ($type eq "name") then
                    //xqdoc:function[ngram:contains(xqdoc:name, $qs)]
                else
                    //xqdoc:function[ngram:contains(xqdoc:comment/xqdoc:description, $qs)]
            else ()
    
        let $hideIndicator   := if( $print ) then "" else "-"
    
        let $hideshowButtons := if( $print ) then () 
                                else 
                                    <div>
                                        <table class="f-hideshow-buttons">
                                            <tr>
                                                <td class="f-show-buttons">
                                                    Modules:  <a id="showAllModules" href="#">Show All</a> | <a id="hideAllModules" href="#">Hide All</a>
                                                </td>
                                                <td class="f-hide-buttons">
                                                    Function Descriptions: <a id="showAllDescriptions" href="#">Show All</a> | <a id="hideAllDescriptions" href="#">Hide All</a>
                                                </td>
                                            </tr>
                                        </table>
                                        <br/>
                                    </div>
            
    
        let $return := 
            for $modURI in distinct-values( $matches/ancestor::xqdoc:xqdoc/xqdoc:module/xqdoc:uri )
            order by $modURI
            return 
                <div class="f-module-heading">
                    <br/>
                    <table class="f-module-heading-table">
                        <tr>
                            <td class="f-module-heading-namespace">{ $modURI }</td>
                            <td class="f-module-heading-description"><div>{  /xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:description/text() }</div>
			    <br/>
			    <div>{if (/xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:release-version/text() eq "trunk") then "Can only be used with current svn trunk from sourceforge at https://exist.svn.sourceforge.net/svnroot/exist/trunk/" else concat("Available from release: ", /xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:release-version/text())}</div>
			    </td>
                            <td class="f-module-heading-hideshow">{ $hideIndicator }</td>
                        </tr>
                    </table>
                    <div class="f-module-heading-section">
                        <br/>
                        {
                            for $match in $matches[ ancestor::xqdoc:xqdoc/xqdoc:module/xqdoc:uri = $modURI ]
                            let $modName := $match/ancestor::xqdoc:xqdoc/xqdoc:module/xqdoc:name
                            let $modUri := $match/ancestor::xqdoc:xqdoc/xqdoc:module/xqdoc:uri
                            order by $match/xqdoc:name
                            return
                                <div class="f-function">
                                    <div class="f-module">
                                        {$match/ancestor::xqdoc:xqdoc/xqdoc:module/xqdoc:uri/text()}
                                    </div>
                                    <h3>{$match/xqdoc:name/text()}</h3>
                                    <div class="f-signature">
                                        <a href="../functions/{replace($modUri, '^.*/([^/]+)$', '$1')}/{$match/xqdoc:name}"
                                            class="f-link" target="_new"
                                            title="Open docs in new windows">
                                            Link
                                        </a>
                                        {$match/xqdoc:signature/text()}
                                    </div>
                                    <div class="f-description">
                                    	{ xqdoc:print-description($match/xqdoc:comment) }
                                        { xqdoc:print-parameters($match/xqdoc:comment) }
                                        { xqdoc:print-return($match/xqdoc:comment) }
                                    </div>{
			                       if (string-length($match/xqdoc:comment/xqdoc:deprecated/text()) > 0)
			                       then
			                           <div class="f-deprecated"><div>Deprecated: {$match/xqdoc:comment/xqdoc:deprecated/text()}</div></div>
			                       else ()
                                }</div>
                        } 
                    </div>
                </div>
    
        return <div class="query-result">{ $hideshowButtons, $return }</div>
    else
        ()
};

declare function xqdoc:print-description($comment as element(xqdoc:comment)) {
    for $desc in tokenize($comment/xqdoc:description, "\n")
    return
    	<div class="f-description-para">{$desc}</div>
};

declare function xqdoc:print-parameters($comment as element(xqdoc:comment)) {
    let $params := $comment/xqdoc:param
    return
        if ($params[1] != '$a') then
            <table class="f-params">
            {
                for $param in $comment/xqdoc:param
                let $split := text:groups($param, "^(\$[^ ]+) (.*)$")
                return
                    <tr>
                        <td>{$split[2]}</td>
                        <td>{$split[3]}</td>
                    </tr>
            }
            </table>
        else
            ()
};

declare function xqdoc:print-return($comment as element(xqdoc:comment)) {
    let $returning := $comment/xqdoc:return
    return
        if (string-length($returning/text())) then
            <div class="f-return">Returns {$returning/text()}</div>
        else
            ()
};

(:~
    Return the main XML page, which will be transformed into HTML by Cocoon.
    If Javascript is enabled on the client, this function will only be called
    once. All subsequent calls to this script will be made via AJAX and we don't
    need to return the entire page.
:)
declare function xqdoc:get-page($action as xs:string, $module as xs:string?, $type as xs:string?, 
$query as xs:string?, $askPass as xs:boolean) as element() {
    <book>
        <bookinfo>
            <graphic fileref="logo.jpg"/>
    
            <productname>Open Source Native XML Database</productname>
            <title>XQuery Function Documentation</title>
            <link rel="stylesheet" type="text/css" href="styles/fundocs.css"/>
            <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
			<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>
            <script type="text/javascript" src="../scripts/yui/utilities2.7.0.js"/>
            <script type="text/javascript" src="scripts/fundocs.js"/>
            <source>functions.xql/source</source>
        </bookinfo>
        
        <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sidebar.xml"/>
    
        <chapter>
            <title>XQuery Function Documentation</title>
            {
                if ($askPass) then
                    <form id="f-pass" name="f-pass" action="functions.xql" method="POST">
                        <para>The function documentation needs to be generated first,
                        which requires administrator rights. Please enter the
                        password for the admin user below:</para>
                        <input type="password" name="pass" value=""/>
                        <input type="hidden" name="generate" value="true"/>
                        <button type="submit">Generate</button>
                    </form>
                else (
                    <div id="f-search">
                        <form name="f-query" action="functions.xql" method="POST">
                            <table>
                                <tr>
                                    <td>
                                        <label for="q">Search:</label>
                                        <input name="q" type="text" value="{$query}"/>
                                        <label for="type">in</label>
                                        <select name="type">
                                            <option value="name">Function Name</option>
                                            <option value="desc">Description</option>
                                        </select>
                                    </td>
                                    <td class="f-btn">
                                        <input id="f-btn-search" type="submit" 
                                            name="action" value="Search"/>
                                    </td>
                                    <td>
                                        <input id="f-btn-print" type="submit" 
                                            name="action" value="Print"/>
                                    </td>
                                </tr>
                                <tr>
                                    <td>
                                        <label for="module">Or display <b>all</b> in:</label>
                                        <select name="module">
                                            <option value="All">All</option>
                                        {
                                            for $mod in collection("/db")//xqdoc:module
                                            let $uri := $mod/xqdoc:uri/text()
                                            order by $uri
                                            return
                                                <option value="{$uri}">
                                                { if ($uri eq $module) then attribute selected { "true" } else () }
                                                { $uri }
                                                </option>
                                        }
                                        </select>
                                    </td>
                                    <td class="f-btn">
                                        <input id="f-btn-browse" type="submit" name="action" value="Browse"/> 
                                    </td>
                                    <td><img id="f-loading" src="../resources/loading.gif"/></td>
                                </tr>
                            </table>
                            <input type="hidden" name="prev" value="{$action}"/>
                        </form>
                        <p class="f-reload"><a href="?action=reload">Reload documentation</a>
                            (click here if you enabled/disabled additional modules)</p>
                        <p class="f-info">(<b>eXist version: {util:system-property("product-version")}, 
                        build: {util:system-property("product-build")},
                        functions: {count(//xqdoc:function)}</b>). Modules have to be enabled 
                        in conf.xml to appear here.
                        </p>
                        <div id="f-result">
                            { if ($query or $module) then xqdoc:do-query($action, $module, $type, $query, false()) else () }
                        </div>
                    </div>
                )
            }
        </chapter>
    </book>
};

declare function xqdoc:print-page($module as xs:string?, $type as xs:string?,
$query as xs:string?) as element() {
    let $prevAction := request:get-parameter("prev", "Browse")
    return
        <html>
            <head>
                <title>XQuery Function Documentation</title>
                <link rel="stylesheet" type="text/css" href="styles/fundocs.css"/>
                <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
				<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>
            </head>
            <body class="f-print">
                <h1>XQuery Function Documentation</h1>
                {
                    if ($prevAction = "Search") then
                        <p>Query: "{$query}" in {$type}.</p>
                    else ()
                }
                { xqdoc:do-query($prevAction, $module, $type, $query, true() ) }
            </body>
        </html>
};

declare function xqdoc:debug-parameters() {
    for $param in request:get-parameter-names()
    return
        util:log("DEBUG", ($param , " = ", request:get-parameter($param, ())))
};

(:
    The mainline of the script. First checks if the documentation has
    already been extracted. If not, ask for the admin password and
    call xqdoc:setup() to generate the documentation. 
:)
let $action := request:get-parameter("action", "Search")
let $generate := request:get-parameter("generate", ())
let $askPass :=
    if (empty(//xqdoc:module) or $generate) then
        let $adminPass := request:get-parameter("pass", ())
        return
            if ($generate) then
                let $setup-result := util:catch("java.lang.Exception",
                                     let $result := setup:setup($adminPass) return false(),
                                     true())
                return $setup-result
            else
                true()
    else
        $action eq 'reload'
let $log := xqdoc:debug-parameters()
let $query := request:get-parameter("q", ())
let $type := request:get-parameter("type", "name")
let $mode := request:get-parameter("mode", ())
let $module := request:get-parameter("module", ())
return
    if ($mode = "ajax") then
        xqdoc:do-query($action, $module, $type, $query, false())
    else if ($action eq "Print") then
        xqdoc:print-page($module, $type, $query)
    else
        xqdoc:get-page($action, $module, $type, $query, $askPass)