Retour à la documentation
/**
* @class spw.widgets.SpwCSWViewer
*/
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/dom-construct',
'dojo/on',
'dojo/mouse',
'dojo/dom-geometry',
'dojo/dom-style',
'dojo/store/Memory',
'dijit/Tooltip',
'dijit/Dialog',
'dijit/form/TextBox',
'dijit/form/ComboBox',
'dijit/form/NumberSpinner',
'dojo/text!./templates/SpwCSWViewer.html',
'spw/api/SpwBaseTemplatedWidget',
'spw/api/MessageManager',
'spw/api/SpwCSWCatalog',
'spw/api/SpwCSWMetawal',
'dijit/form/Button',
'dijit/layout/BorderContainer',
'dijit/layout/ContentPane'
],
function(declare, lang, array, domConstruct, on, mouse, domGeom, domStyle, Memory, Tooltip, Dialog, TextBox,
ComboBox, NumberSpinner, template, SpwBaseTemplatedWidget, MessageManager, SpwCSWCatalog, SpwCSWMetawal) {
var SpwCSWViewer = declare('spw.widgets.SpwCSWViewer', [SpwBaseTemplatedWidget], {
templateString: template,
// url du service csw
cswUrl: null,
// le catalogue utilisé (SpwCSWCatalog ou Metawal)
catalog: null,
// pour la pagination
curPage: null,
totalPage: null,
recordsByPage: 20,
// les options du filtrage (construction formulaire)
filterOptions: null,
// contient les infos sur les filtres du formulaire
filters: null,
// la combo de tri
sortSelect: null,
// le spinner pour le nombre de résultats par page
recordsByPageBox: null,
// les filtres à appliquer par défaut
defaultFilter: null,
defaultSort: null,
// propriété correspondant à la description d'un record
descriptionProperty: 'description',
useCors: true,
constructor: function() {
},
resize: function() {
this.inherited(arguments);
this.firstBorderNode.resize();
},
postCreate: function() {
this.inherited(arguments);
// pour delay le changement de page (le temps que l'utilisateur arrêter de tapper au clavier)
var delayChangePage = (function(){
var timer = 0;
var oldValue = 1;
return lang.hitch(this, function(callback, page, ms) {
if (isNaN(page)) {
return;
}
page = +page;
if (oldValue === page) {
return;
}
clearTimeout (timer);
oldValue = page;
timer = setTimeout(callback, ms, page);
});
})();
this.own(
on(this.prevPageButton, 'click', lang.hitch(this, function() {
this.showCatalog(this.curPage - 1);
})),
on(this.firstPageButton, 'click', lang.hitch(this, function() {
if (this.curPage === 1) {
return;
}
this.showCatalog(1);
})),
on(this.nextPageButton, 'click', lang.hitch(this, function() {
this.showCatalog(this.curPage + 1);
})),
on(this.lastPageButton, 'click', lang.hitch(this, function() {
if (this.curPage === this.totalPage) {
return;
}
this.showCatalog(null);
})),
// lorsque l'utilisateur modifie la page par la textbox
on(this.pageNumberNode, 'keyup', lang.hitch(this, function() {
delayChangePage(lang.hitch(this, this.showCatalog),
this.pageNumberNode.get('value'), 1000);
}))
);
},
onActivate: function() {
this.inherited(arguments);
// si le catalog n'est pas instancié
if (this.catalog == null) {
// on le fait en se basant sur l'URL pour savoir s'il faut utiliser metawal ou non
if (this.cswUrl.indexOf('metawal') >= 0) {
this.catalog = new SpwCSWMetawal({
url: this.cswUrl,
defaultFilter: this.defaultFilter,
defaultSort: this.defaultSort,
useCors: this.useCors
});
}
else {
this.catalog = new SpwCSWCatalog({
url: this.cswUrl,
defaultFilter: this.defaultFilter,
defaultSort: this.defaultSort,
useCors: this.useCors
});
}
// on construit le formulaire de filtrage
this.drawFilter();
// et on affiche la première page
this.showCatalog(1);
}
},
/**
* Construit le formulaire de filtrage
*/
drawFilter: function() {
this.filters = [];
// pour ne pas ajouter plusieurs fois la même id
var ids = [];
array.forEach(this.filterOptions, lang.hitch(this, function(f) {
if (ids.indexOf(f.field) >= 0) { // id déjà présente ?
return;
}
// on récupère les infos pour le champs (type, label...)
var infos = this.catalog.getFilterInfo(f.field);
if (infos == null) {
console.error(f.field + ' is an unknown field')
return;
}
// on construit la textbox et le label
var li = domConstruct.create('li', {
style: 'margin: 5px 0 5px 0;'
}, this.filterNode, 'last');
domConstruct.create('label', {
'for': this.widgetId + 'sort' + f.field,
innerHTML: infos.label + ' : '
}, li);
// TODO: créer en fonction du type (date, numérique...)
var tmp = new TextBox({
id: this.widgetId + 'filter' + f.field,
style: 'width: 100%;'
}, domConstruct.create('input', null, li, 'last'));
tmp.filterField = f.field;
this.filters.push(tmp);
}));
// création de la combo pour le tri
var sortItems = [];
// ajout des paramètres de tri
array.forEach(this.sortOptions, lang.hitch(this, function(s) {
var infos = this.catalog.getFilterInfo(s);
if (infos == null) {
return;
}
sortItems.push({
field: s,
label: infos.label
});
}));
if (sortItems.length > 0) {
var liSort = domConstruct.create('li', {
style: 'margin: 20px 0 20px 0;'
}, this.filterNode, 'last');
domConstruct.create('label', {
'for': this.widgetId + 'sortSelect',
innerHTML: 'Trier par : '
}, liSort);
this.sortSelect = new ComboBox({
id: this.widgetId + 'sortSelect',
store: new Memory({data: sortItems}),
searchAttr: 'label',
style: 'width: 100%;',
required: false
}, domConstruct.create('input', null, liSort));
this.sortSelect.startup();
}
// nombre de records par page
var liNb = domConstruct.create('li', {
style: 'margin: 20px 0 20px 0;'
}, this.filterNode, 'last');
domConstruct.create('label', {
'for': this.widgetId + 'recordsByPage',
innerHTML: 'Nombre de résultats par page : '
}, liNb);
this.recordsByPageBox = new NumberSpinner({
id: this.widgetId + 'recordsByPage',
value: this.recordsByPage,
smallDelta: 10,
constraints: {
min: 1,
max: 1000,
places: 0
},
required: true,
style: 'width: 100%;'
}, domConstruct.create('input', null, liNb));
this.recordsByPageBox.startup();
// rafaîchissement
this.own(
on(this.formFilterNode, 'submit', lang.hitch(this, function(evt) {
evt.preventDefault();
this.showCatalog(1);
}))
);
},
/**
* Permet de récupérer le filtre à envoyer au catalogue sur base du formulaire
* @return {Array} du type [ { field: 'dc:type', like: '%service%' } ]
*/
getFilter: function() {
var tmp = [];
// on parcourt le formulaire
array.forEach(this.filters, lang.hitch(this, function(f) {
// si valeur entrée
if (f.get('value') == null || f.get('value') === '') {
return;
}
// on push le filtre
// TODO: eq/neq/gt/gteq/lt/lteq/between
tmp.push({
field: f.filterField,
like: f.get('value')
});
}));
// on s'assure qu'on retourne null si aucun filtre
if (tmp.length > 0) {
return tmp;
}
return null;
},
/**
* Permet de récupérer le paramètre sort à envoyer
*/
getSort: function() {
if (this.sortSelect == null) {
return null;
}
var item = this.sortSelect.get('item');
if (item == null || item === '') {
return;
}
return [{
field: item.field
}];
},
/**
* Affiche une page du catalogue
* @param {Integer} page numéro de la page (null si dernière)
*/
showCatalog: function(page) {
if (page == null) {
// on récupère la dernière page si elle existe, sinon, on retourne à la première
if (this.totalPage) {
page = this.totalPage;
}
else {
page = 1;
}
}
else if (page < 1) {
return;
}
else {
// on vérifie que la page ne dépasse pas le nombre total
if (this.totalPage) {
if (this.totalPage < page) {
return;
}
}
}
// on construit les options à passer au GetRecords
var opts = {
filter: this.getFilter(),
sort: this.getSort()
};
// loader + retour au-dessus de la page (sinon le load ne s'affiche pas bien)
this.centerNode.domNode.scrollTop = 0;
this.pageNumberNode.set('disabled', true);
this.showLoading(this.centerNode.domNode);
// on calcule le numéro du record de début de page
this.recordsByPage = this.recordsByPageBox.get('value');
var start = ((page - 1) * this.recordsByPage) + 1;
this.catalog.GetRecords(start, this.recordsByPage, opts).then(
lang.hitch(this, function(data) {
// on calcule le nombre total de pages
this.totalPage = Math.ceil(data.total / this.recordsByPage);
// on met à jour la pagination
this.updatePagination(data, page);
// on vide la page
domConstruct.empty(this.listNode);
// et on ajoute les nouveaux éléments à la page
array.forEach(data.records, lang.hitch(this, function(r, idx) {
var item = new ItemNode({
controller: this,
record: r
}, domConstruct.create('li', null, this.listNode));
item.startup();
}));
this.pageNumberNode.set('disabled', false);
this.hideLoading();
}),
lang.hitch(this, function(err){
MessageManager.getInstance().notifyError(err);
})
);
},
/**
* Met à jour le visuel de la pagination
*/
updatePagination: function(result, page) {
// le disabled ne fonctionne pas
if (this.totalPage === page || result.nextRecord === 0) {
domStyle.set(this.nextPageButton, 'disabled', 'true');
domStyle.set(this.lastPageButton, 'disabled', 'true');
}
else {
domStyle.set(this.nextPageButton, 'disabled', '');
domStyle.set(this.lastPageButton, 'disabled', '');
}
if (page === 1) {
domStyle.set(this.prevPageButton, 'disabled', 'true');
domStyle.set(this.firstPageButton, 'disabled', 'true');
}
else {
domStyle.set(this.prevPageButton, 'disabled', '');
domStyle.set(this.firstPageButton, 'disabled', '');
}
this.curPage = page;
this.pageNumberNode.set('value', this.curPage);
this.paginationTextNode.innerHTML = 'sur ' + this.totalPage;
}
});
/**
* Représente un record du catalogue
*/
var ItemNode = declare('spw.widgets.SpwCSWViewerItem', [SpwBaseTemplatedWidget], {
templateString: '<li></li>',
// controller = SpwCSWViewer
controller: null,
// le record
record: null,
// paragraphe de description pour qu'il soit coupé si trop long
clipped: null,
parClipped: null,
// le tooltip affichant la description complète
tooltip: null,
postCreate: function() {
this.inherited(arguments);
if (this.record == null) {
return;
}
this.buildView();
},
_getDescription: function() {
return this.record[this.controller.descriptionProperty] ?
this.record[this.controller.descriptionProperty] : 'Aucune description';
},
/**
* Construction de la vue
*/
buildView: function() {
// on parcourt les uri du record pour récupérer une éventuelle miniature
var found = array.some(this.record.uri, lang.hitch(this, function(u) {
if (u.link.match(/\.(jpg|jpeg|png|gif)$/)) {
domConstruct.create('img', {
src: u.link,
'class': 'iconCsw'
}, this.domNode, 'first');
return true;
}
return false;
}));
// si aucune miniature trouvée -> nopreview
if (!found) {
domConstruct.create('img', {
src: this.imagesPath + 'nopreview.gif',
'class': 'iconCsw'
}, this.domNode, 'first');
}
// construction du titre, de la description et des boutons éventuels
domConstruct.create('h3', {
style: 'margin-bottom: 0;',
innerHTML: this.record.title
}, this.domNode, 'last');
this.clipped = domConstruct.create('div', {
'class': 'clipped'
}, this.domNode, 'last');
this.parClipped = domConstruct.create('p', {
innerHTML: this._getDescription()
}, this.clipped);
// si le record a un id, on peut en afficher les détails
if (this.record.id) {
var details = domConstruct.create('span', {
'class': 'details'
}, this.domNode, 'last');
this.own(on(details, 'click', lang.hitch(this, function() {
var url = this.controller.detailsUrl || '{id}';
url = lang.replace(url, {id: this.record.id});
if (this.controller.detailsPopup) {
var width = this.controller.detailsPopup.width != null ? this.controller.detailsPopup.width : "750px";
var height = this.controller.detailsPopup.height != null ? this.controller.detailsPopup.height : "800px";
new Dialog({
title: '',
content: "<iframe width=" + width + " height=" + height + " src=" + url + "></iframe>"
}).show();
}
else {
window.open(url, '_blank');
}
})));
}
// si le record est un mapservice, on peut l'ajouter à la carte
if (this.controller.catalog.isMapService(this.record)) {
var add = domConstruct.create('span', {
'class': 'add'
}, this.domNode, 'last');
this.own(on(add, 'click', lang.hitch(this, function() {
this.controller.catalog.addServiceFromURI(this.record);
})));
}
},
startup: function() {
this.inherited(arguments);
// on calcule la taille du div contenant le paragraphe de description
// et la taille du paragraphe pour savoir s'il dépasse.
// Si c'est le cas, on réduit le texte affiché pour qu'il rentre et on
// ajoute un tooltip pour afficher la description complète
var divh = domGeom.position(this.clipped).h;
var addHover = false;
while (domGeom.position(this.parClipped).h > divh) {
addHover = true;
this.parClipped.innerHTML = this.parClipped.innerHTML.replace(/\W*\s(\S)*$/, '...');
}
if (addHover) {
this.tooltip = new Tooltip({
connectId: [this.clipped],
label: '<div style="max-width: 500px;">' +
this._getDescription() + '</div>',
position: ['after', 'above'],
showDelay: 1000,
style: 'width: 500px;'
});
this.tooltip.startup();
}
}
});
return SpwCSWViewer;
});