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";

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 )
            let $since := /xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:since
            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:extract-title(string-join(/xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:description, ''))
                                }</div>
                 			    <br/>
                 			    <div>
                 			    {
                 			        if ($since eq "trunk") then 
                 			            "Can only be used with current svn trunk from sourceforge at https://exist.svn.sourceforge.net/svnroot/exist/trunk/" 
                 		            else if (string-length($since) > 0) then
                 		                concat("Available from release: ", /xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:since/text())
                 	                else
                 	                  ()
                 	            }
                 	            </div>
                 		    </td>
                            <td class="f-module-heading-hideshow">{ $hideIndicator }</td>
                        </tr>
                    </table>
                    <div class="f-module-heading-section">
                        <p>{/xqdoc:xqdoc/xqdoc:module[ xqdoc:uri = $modURI ]/xqdoc:comment/xqdoc:description}</p>
                        <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:extract-title($text as xs:string?) as xs:string {
    if (string-length($text) gt 60) then
        let $paragraphs := tokenize($text, "[.:?!]")
        return
            if (string-length($paragraphs[1]) gt 60) then
                concat(substring($paragraphs[1], 1, 60), '...')
            else
                $paragraphs[1]
    else
        $text
};

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, "^\s*(\$[^ ]+) (.*)$")
                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
                    <para>The function documentation needs to be generated one 
                    time at least. Please change to the 
                    <a href="{request:get-context-path()}/admin/admin.xql?panel=fundocs">documentation 
                    setup page</a>
                    in the admin web application.</para>
                    
                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="{request:get-context-path()}/admin/admin.xql?panel=fundocs">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 := empty(//xqdoc:module)
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)