Commit 2eb86963 authored by Jerome Chauveau's avatar Jerome Chauveau
Browse files

premières ébauches de filtres sur les index (recherche) & pagination +...

premières ébauches de filtres sur les index (recherche) & pagination + externalisation de la configuration au niveau de la config de l'édition
parent b02f16ea
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
<?xml version="1.0"?>

<search>
    <tags>
        <tag name="corpname" label="corpname"/>
        <tag name="famname" label="famname"/>
        <tag name="function" label="Fonction"/>
        <tag name="genreform" label="genreform"/>
        <tag name="geogname" label="geogname"/>
        <tag name="occupation" label="Occupation"/>
        <tag name="name" label="Nom"/>
        <tag name="persname" label="Nom de personne"/>
        <tag name="subject" label="Sujet"/>
        <tag name="title" label="Titre"/>
    </tags>
    <dates format="YYYY"></dates>
</search>
 No newline at end of file
+21 −0
Original line number Diff line number Diff line
@@ -44,3 +44,24 @@
#ead-search-results {
    border-top: 1px solid #888;
}

.ead-search-popup-wrap{
    display: inline;
    position: relative;
}

.ead-search-popup{
    display: none;
    position: absolute;
    top:0;
    left: 10px;
    border:1px solid #999;
    min-width:400px;
    background-color: white;
    z-index:10;
    font-size:0.8rem;
}

.ead-search-popup-alphabet{
    text-align :center;
}
 No newline at end of file
+98 −33
Original line number Diff line number Diff line
@@ -5,40 +5,103 @@ import {Plugin} from '../../core/ui/js/Plugin.js';
class EadSearchPlugin extends Plugin{
  constructor(name) {
     super(name);
     this.withDatesFilter = document.getElementById('ead-search-date-cb').checked;
     this.filters = {}
     if(document.getElementById('ead-search-section'))
        this.fetchIndexLists();
     if(document.getElementById('ead-search-section')){
        document.getElementById('ead-search-date-cb').addEventListener('click', (evt) => {
            this.withDatesFilter = evt.target.checked;
            if(!this.withDatesFilter){
                document.getElementById('ead-search-date-from').setAttribute('disabled', true);
                document.getElementById('ead-search-date-to').setAttribute('disabled', true);
            }
            else{
                document.getElementById('ead-search-date-from').removeAttribute('disabled');
                document.getElementById('ead-search-date-to').removeAttribute('disabled')
            }

        })
        this.bindIndexAutocompletes();
     }
//        this.fetchIndexLists();

  }

  fetchIndexLists(){
    let indexList = document.querySelectorAll('.ead-search-input')
  bindIndexAutocompletes(){
    let indexList = document.querySelectorAll('.ead-search-input');

    indexList.forEach((e) => {
        e.addEventListener('input', (evt) => {

            let indexName = e.dataset.index;
        fetch(baseURI + projectId + '/search-index/'+indexName+'.json').then((res) => res.json()).then( (json) => {
            let q = e.value;
            if(q.trim() !==''){
                let url = baseURI + projectId + '/search-index/'+indexName+'.json?q='+ q ;
                let datalist = document.getElementById(indexName);
                fetch(baseURI + projectId + '/search-index/'+indexName+'.json').then((res) => res.json()).then( (json) => {
                    datalist.innerHTML = '';
                    let entries = json.entries
                    entries.forEach((entry) => {
                        let option = document.createElement('option');
                        option.value = decodeURIComponent(entry.normal);
                        datalist.appendChild(option);

                    })

                    document.getElementById(indexName+'-input').addEventListener('input', (event) => {
                        //alert(event.target.value)
                            if(event.inputType === 'insertReplacementText'){
                                this.addIndexFilter(indexName, event.target.value)
                            }

                    });
                })
            }
        })
    })

  }

  popupIndex(tagName){
    let popupElt = document.getElementById('ead-search-popup-'+tagName);
    let popupContent = document.getElementById('ead-search-popup-'+tagName+"-contents");
    popupContent.innerHTML = '';
    let url = baseURI + projectId + '/search-index/'+tagName+'.json';
    let list = document.createElement('ol');
    fetch(baseURI + projectId + '/search-index/'+tagName+'.json').then((res) => res.json()).then( (json) => {
        let entries = json.entries
        entries.forEach((entry) => {
                let li = document.createElement('li');
                li.innerHTML = decodeURIComponent(entry.normal);
                list.appendChild(li);
        })
    })
    popupContent.appendChild(list);
    popupElt.style.display='block';
  }
//
//  fetchIndexLists(){
//    let indexList = document.querySelectorAll('.ead-search-input')
//
//    indexList.forEach((e) => {
//        let indexName = e.dataset.index;
//        fetch(baseURI + projectId + '/search-index/'+indexName+'.json').then((res) => res.json()).then( (json) => {
//                let datalist = document.getElementById(indexName);
//                let entries = json.entries
//                entries.forEach((entry) => {
//                    let option = document.createElement('option');
//                    option.value = decodeURIComponent(entry.normal);
//                    datalist.appendChild(option);
//
//                })
//
//                document.getElementById(indexName+'-input').addEventListener('input', (event) => {
//                        //alert(event.target.value)
//                        if(event.inputType === 'insertReplacementText'){
//                            this.addIndexFilter(indexName, event.target.value)
//                        }
//
//                });
//            })
//
//
//    })
//  }

  addIndexFilter(filterType, filterValue){
    if(filterValue.trim() === '')
@@ -78,6 +141,7 @@ class EadSearchPlugin extends Plugin{

       query = baseURI + projectId + '/' +query;

        if(this.withDatesFilter){
            //date
            let dateMode = document.querySelector('input[name=ead-search-radio-date]:checked').value
            if(dateMode === 'interval'){
@@ -90,6 +154,7 @@ class EadSearchPlugin extends Plugin{
                let dateIn = document.getElementById('ead-search-date-in').value;
                query+=(!filtered ? "?" : "&") + "in="+dateIn
            }
        }

       fetch(query).then(res => res.text()).then(text => {
        document.getElementById('ead-search-results').innerHTML = text
+101 −71
Original line number Diff line number Diff line
@@ -3,35 +3,14 @@ xquery version "3.0";
module namespace max.plugin.ead_search = 'pddn/max/plugin/ead_search';
import module namespace max.config = 'pddn/max/config' at '../../rxq/config.xqm';
import module namespace max.html = 'pddn/max/html' at '../../rxq/html.xqm';
import module namespace max.cons = 'pddn/max/cons' at '../../rxq/cons.xqm';
import module namespace max = 'pddn/max' at '../../max.xq';
import module namespace max.util = 'pddn/max/util' at '../../rxq/util.xqm';
import module namespace max.i18n = 'pddn/max/i18n' at '../../rxq/i18n.xqm';

(:declare variable $max.plugin.search:PLUGIN_ID := "search";:)
(:declare variable $max.plugin.search:ALL_TXT := "all_txt";:)
(:declare variable $max.plugin.search:SELECTION := "selection";:)

(:Plugin parameters  - should be defined in MAX CONFIGURATION FILE:)
(:declare variable $max.plugin.search:TAG_PARAMETER := "tag";:)
(:declare variable $max.plugin.search:BACK_TO_TEXT_ID_PARAMETER := "backToTextID";:)


declare variable $max.plugin.ead_search:INDEX_TAGS :=
    <search>
        <tags>
            <tag name="corpname" attribute="role" value="scriptorium"/>
            <tag name="famname"/>
            <tag name="function"/>
            <tag name="genreform"/>
            <tag name="geogname"/>
            <tag name="occupation"/>
            <tag name="name"/>
            <tag name="persname"/>
            <tag name="subject"/>
            <tag name="title" attribute="type" value="subscriptio"/>
        </tags>
        <dates format="YYYY"></dates>
    </search>;


declare %private function max.plugin.ead_search:getSearchConfiguration($project){
    let $p:=max.config:getPluginParameterValue($project, 'ead_search', 'searchForm')
    return if($p) then $p else doc(max.util:maxHome()||'/plugins/ead_search/default_config.xml')
};

declare
%rest:GET
@@ -41,14 +20,23 @@ function max.plugin.ead_search:searchPage($project){
    let $dbPath := max.config:getProjectDBPath($project)
    let $datalists := <section id="ead-search-section" class="ead-search">
        {
        for $indexTag in $max.plugin.ead_search:INDEX_TAGS//tag
        for $indexTag in max.plugin.ead_search:getSearchConfiguration($project)//tag
        let $tagName := string($indexTag/@name)
        return
            if(count(collection($dbPath)//*[fn:local-name()=$tagName and @normal]) > 0)
            then
            <div>
                <label>{$tagName}s</label>
                <label>{string($indexTag/@label)}</label>
                <input type="text" class="ead-search-input" data-index="{$tagName}" id="{$tagName}-input" list="{$tagName}" multiple="multiple"></input>
                <div class="ead-search-popup-wrap">
                    <button onclick="window.eadSearch.popupIndex('{$tagName}')">&#x1F4D6;</button>
                    <div class="ead-search-popup" id="ead-search-popup-{$tagName}">
                            <div id="ead-search-popup-{$tagName}-alphabet" class="ead-search-popup-alphabet">
                                {for $l in 1 to 26 return <a>{codepoints-to-string(($l+64))}</a>}
                            </div>
                            <div id="ead-search-popup-{$tagName}-contents"></div>
                    </div>
                </div>
                <ul id="{$tagName}-ul" class="ead-search-ul">
                </ul>
                <datalist id="{$tagName}" class="ead-index-list"></datalist>
@@ -56,6 +44,7 @@ function max.plugin.ead_search:searchPage($project){
            else ()
        }
            <div id="ead-search-date-wrap">
                <input type="checkbox" checked="checked" id="ead-search-date-cb"/>
                <label>Année de production</label>
                <!--<div>
                    <input type="radio" name="ead-search-radio-date" checked="checked" value="in"/>
@@ -95,7 +84,9 @@ function max.plugin.ead_search:runSearch($project as xs:string, $indexes as xs:s
    let $subqueries := for $index at $i in $indexes
        let $p := request:parameter($index||'[]')
        return
            let $or := string-join(for $n in $p return '@normal="'||$n||'" or contains(./text(),"'||$n||'")',' or ' )
            (: chercher aussi ds les noeuds text() ? - commenté pour le moment:)
(:            let $or := string-join(for $n in $p return '@normal="'||$n||'" or contains(./text(),"'||$n||'")',' or ' ):)
            let $or := string-join(for $n in $p return '@normal="'||$n||'"',' or ' )
            return
            if($i = 1) then ' where count($c//*[local-name(.)!="c"]//*:'||$index||'['||$or||'])>0 '
            else ' and count($c//*[local-name(.)!="c"]//*:'||$index||'['||$or||'])>0 '
@@ -110,14 +101,15 @@ function max.plugin.ead_search:runSearch($project as xs:string, $indexes as xs:s

(:    fn:string-join($subqueries,'') || ' ' || max.plugin.ead_search:buildDateQuery($project, $from, $to, $in)||' return $c':)
(:    return $fullQuery:)
    return try{
    let $matches := max.plugin.ead_search:dateFilter(
            $from, $to, $in, xquery:eval($fullQuery, map { '': db:open($dbPath) }))
            $project,$from, $to, $in, xquery:eval($fullQuery, map { '': db:open($dbPath) }))



    let $html:= <ul>{
        for $c in $matches
        return <li>{$c/*:did/*:unitid/text()}</li>
        return <li>{$c/*:did/*:unitid/text()} | <em>{string($c/*:did/*:unitdate[1]/@normal)}</em></li>
    }
    </ul>

@@ -126,25 +118,50 @@ function max.plugin.ead_search:runSearch($project as xs:string, $indexes as xs:s
            <h4>XQuery = {$fullQuery} - (db = {$dbPath})</h4>
            {$html}
        </section>
    }
    catch * {
        max:max-error("Erreur code " || $err:code, $err:description ||'('||$fullQuery||')',$err:module, $err:line-number)
    }
};

declare %private function max.plugin.ead_search:parseDateParameter($strDate as xs:string, $format as xs:string){
    try {
         switch ($format)
            case "YYYY"
                return xs:date($strDate||'-01-01')
            case "YYYY-MM"
                return xs:date($strDate||'-01')
            default
                return xs:date($strDate)
    }
    catch * {
        admin:write-log("Wrong date entry :" || $strDate || ' format = '|| $format),
        xs:date('0001-01-01')
    }

};

declare %private function max.plugin.ead_search:dateFilter(
        $project as xs:string,
        $from as xs:string?,
        $to as xs:string?,
        $in as xs:string?,
        $matches){

    let $dateFormat :=string(max.plugin.ead_search:getSearchConfiguration($project)//dates/@format)
    return
    if($from and $to)
    then max.plugin.ead_search:dateIntervalFilter($from, $to, $matches)
    else if($in) then () (:todo:)
        then max.plugin.ead_search:dateIntervalFilter($from, $to, $dateFormat, $matches)
    else
        if($in) then () (:todo:)
        else $matches

};

declare %private function max.plugin.ead_search:dateIntervalFilter($from as xs:string, $to as xs:string, $matches as item()+){
    let $fromDateTime := max.plugin.ead_search:parseDateParameter($from)
    let $toDateTime := max.plugin.ead_search:parseDateParameter($to)
declare %private function max.plugin.ead_search:dateIntervalFilter($from as xs:string, $to as xs:string, $dateFormat as xs:string, $matches as item()+){

    let $fromDateTime := max.plugin.ead_search:parseDateParameter($from,$dateFormat)
    let $toDateTime := max.plugin.ead_search:parseDateParameter($to,$dateFormat)

    return
    for $m in $matches
@@ -153,14 +170,14 @@ declare %private function max.plugin.ead_search:dateIntervalFilter($from as xs:s
        return if(contains($unitDate,'/'))
            then
            let $dates := tokenize($unitDate,'/')
            let $unitFrom :=  max.plugin.ead_search:parseDateParameter($dates[1])
            let $unitTo:=  max.plugin.ead_search:parseDateParameter($dates[2])
            let $unitFrom :=  max.plugin.ead_search:parseDateParameter($dates[1], $dateFormat)
            let $unitTo:=  max.plugin.ead_search:parseDateParameter($dates[2], $dateFormat)
            return
               if($fromDateTime <= $unitFrom and $toDateTime >= $unitTo)
               then $m
               else()
            else
                let $unitFrom :=  max.plugin.ead_search:parseDateParameter($unitDate)
                let $unitFrom :=  max.plugin.ead_search:parseDateParameter($unitDate, $dateFormat)
                return
                    if($fromDateTime <= $unitFrom) then $m else ()

@@ -176,49 +193,62 @@ declare function max.plugin.ead_search:buildSimpleDateQuery($project as xs:strin
declare
%rest:GET
%output:method("json")
%rest:query-param("q", "{$query}")
%rest:query-param("page", "{$page}",1)
%rest:path("/{$project}/search-index/{$tag}.json")
function max.plugin.ead_search:searchIndexesList($project, $tag){
function max.plugin.ead_search:searchIndexesListAsJSON($project, $tag, $page as xs:integer, $query as xs:string?){
    let $entries := max.plugin.ead_search:searchIndexesList($project, $tag, $page, $query)
    let $jsonStr :=
            for $entry in $entries/*
            order by $entry/@normal
            where fn:string-length($entry/@normal) > 0
            return '{"normal":"' || encode-for-uri($entry/@normal) || '", "tag":"' || $tag || '", "role" :"'||$entry/@role||'"}'
    return json:parse('{"entries" :[' || string-join($jsonStr,',') ||']}')
};




declare %private function max.plugin.ead_search:searchIndexesList($project, $tag, $page as xs:integer, $query as xs:string?){
    let $dbPath := max.config:getProjectDBPath($project)
    let $tagParameters := $max.plugin.ead_search:INDEX_TAGS//tag[@name=$tag]
    let $tagParameters := max.plugin.ead_search:getSearchConfiguration($project)//tag[@name=$tag]
    (:select all nodes with required tag and attributes :)
    let $allEntries := for $elt in collection($dbPath)//*[fn:local-name()=$tag and @normal]
        where
    let $allEntries :=
        for $elt in collection($dbPath)//*[fn:local-name()=$tag and @normal]
        where(
            if($tagParameters/@attribute) then
                $elt/@*[local-name(.)=string($tagParameters/@attribute) and string(.)=string($tagParameters/@value)]
            else true()
        )
        and (
            if($query)
            then  $elt/@normal[contains(., $query)]
            else true()
        )
        return $elt

    (:get their normal forms:)
    let $allNormals := for $e in $allEntries return string($e/@normal)
    let $allNormals :=
        for $e in $allEntries
        return string($e/@normal)

    (:positions computing according to page number:)
    let $start := $page * 10 - 9
    let $end := $start + 10

    (:filter : avoid doublons:)
    let $entries := for $normal in distinct-values($allNormals)
    return <entries>{
        for $normal at $pos in distinct-values($allNormals)
        order by $normal
        where $pos >= $start
        and $pos < $end
        return $allEntries[@normal=$normal][1]
    }</entries>


    let $jsonStr :=
            for $entry in $entries
            order by $entry/@normal
            where fn:string-length($entry/@normal) > 0
            return '{"normal":"' || encode-for-uri($entry/@normal) || '", "tag":"' || $tag || '", "role" :"'||$entry/@role||'"}'
    return json:parse('{"entries" :[' || string-join($jsonStr,',') ||']}')
};


declare %private function max.plugin.ead_search:parseDateParameter($strDate as xs:string){
    let $format := string($max.plugin.ead_search:INDEX_TAGS/dates/@format)
    return try {
     switch ($format)
        case "YYYY"
            return xs:date($strDate||'-01-01')
        case "YYYY-MM"
            return xs:date($strDate||'-01')
        default return xs:date($strDate)
        }
    catch * {
         xs:date('0001-01-01')
        }

};


(:test index:)