Subversion Repositories eFlore/Applications.cel

Compare Revisions

No changes between revisions

Ignore whitespace Rev 3860 → Rev 3859

/branches/v3.01-serpe/widget/modules/photo/config.defaut.ini
New file
0,0 → 1,25
[photo]
; Chemin pour l'autoload à ajouter
autoload = "bibliotheque/;bibliotheque/xml_feed_parser/1.0.4/;bibliotheque/xml_feed_parser/1.0.4/parsers/"
; URL ou chemin du flux RSS contenant les liens vers les photos - ne pas oublier de changer motif_guid en même temps!
fluxRssUrl = "https://api.tela-botanica.org/service:cel:CelSyndicationImage/multicriteres/atom/M"
; Squelette d'url pour accéder à la fiche eFlore
efloreUrlTpl = "https://www.tela-botanica.org/%s-nn-%s"
; Nombre de vignette à afficher : nombre de vignettes par ligne et nombre de lignes séparés par une vigule (ex. : 4,3).
vignette = 4,3
; Afficher/Cacher l'affichage en grand de la dernière image ajoutée
extraActif = true
; url service widget image
celUrlImages = "https://api.tela-botanica.org/service:cel:CelWidgetImage/*"
; url profil utilisateur
tbProfilUrlTpl = "https://www.tela-botanica.org/profil-par-id/%s"
; afficher le champ de recherche
champRecherche = true
 
[photo.cache]
; Active/Désactive le cache
activation = true
; Dossier où stocker les fichiers de cache du widget
stockageDossier = "/tmp"
; Durée de vie du fichier de cache
dureeDeVie = 86400
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/Cache.php
New file
0,0 → 1,128
<?php
class Cache {
private $actif = null;
private $dossier_stockage = null;
private $duree_de_vie = null;
public function __construct($dossier_stockage = null, $duree_de_vie = null, $activation = true) {
$this->actif = ($activation) ? true : false;
if ($this->actif) {
$this->dossier_stockage = $dossier_stockage;
if (is_null($dossier_stockage)) {
$this->dossier_stockage = self::getDossierTmp();
}
$this->duree_de_vie = $duree_de_vie;
if (is_null($duree_de_vie)) {
$this->duree_de_vie = 3600*24;
}
}
}
public function charger($id) {
$contenu = false;
if ($this->actif) {
$chemin_fichier_cache = $this->dossier_stockage.DIRECTORY_SEPARATOR.$id.'.txt';
if (file_exists($chemin_fichier_cache ) && (time() - @filemtime($chemin_fichier_cache) < $this->duree_de_vie)) {
$contenu = file_get_contents($chemin_fichier_cache);
}
}
return $contenu;
}
public function sauver($id, $contenu) {
if ($this->actif) {
$chemin_fichier_cache = $this->dossier_stockage.DIRECTORY_SEPARATOR.$id.'.txt';
if (!file_exists($chemin_fichier_cache) || (time() - @filemtime($chemin_fichier_cache) > $this->duree_de_vie)) {
$fh = fopen($chemin_fichier_cache,'w+');
if ($fh) {
fputs($fh, $contenu);
fclose($fh);
}
}
}
}
/**
* Détermine le dossier système temporaire et détecte si nous y avons accès en lecture et écriture.
*
* Inspiré de Zend_File_Transfer_Adapter_Abstract & Zend_Cache
*
* @return string|false le chemine vers le dossier temporaire ou false en cas d'échec.
*/
private static function getDossierTmp() {
$dossier_tmp = false;
foreach (array($_ENV, $_SERVER) as $environnement) {
foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $cle) {
if (isset($environnement[$cle])) {
if (($cle == 'windir') or ($cle == 'SystemRoot')) {
$dossier = realpath($environnement[$cle] . '\\temp');
} else {
$dossier = realpath($environnement[$cle]);
}
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
break 2;
}
}
}
}
if ( ! $dossier_tmp) {
$dossier_televersement_tmp = ini_get('upload_tmp_dir');
if ($dossier_televersement_tmp) {
$dossier = realpath($dossier_televersement_tmp);
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp) {
if (function_exists('sys_get_temp_dir')) {
$dossier = sys_get_temp_dir();
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp) {
// Tentative de création d'un fichier temporaire
$fichier_tmp = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($fichier_tmp) {
$dossier = realpath(dirname($fichier_tmp));
unlink($fichier_tmp);
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp && self::etreAccessibleEnLectureEtEcriture('/tmp')) {
$dossier_tmp = '/tmp';
}
if ( ! $dossier_tmp && self::etreAccessibleEnLectureEtEcriture('\\temp')) {
$dossier_tmp = '\\temp';
}
return $dossier_tmp;
}
/**
* Vérifie si le fichier ou dossier est accessible en lecture et écriture.
*
* @param $ressource chemin vers le dossier ou fichier à tester
* @return boolean true si la ressource est accessible en lecture et écriture.
*/
protected static function etreAccessibleEnLectureEtEcriture($ressource){
$accessible = false;
if (is_readable($ressource) && is_writable($ressource)) {
$accessible = true;
}
return $accessible;
}
}
?>
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/schemas/atom.rng
New file
0,0 → 1,598
<?xml version="1.0" encoding="UTF-8"?>
<!--
-*- rnc -*-
RELAX NG Compact Syntax Grammar for the
Atom Format Specification Version 11
-->
<grammar ns="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:s="http://www.ascc.net/xml/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<choice>
<ref name="atomFeed"/>
<ref name="atomEntry"/>
</choice>
</start>
<!-- Common attributes -->
<define name="atomCommonAttributes">
<optional>
<attribute name="xml:base">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="xml:lang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<zeroOrMore>
<ref name="undefinedAttribute"/>
</zeroOrMore>
</define>
<!-- Text Constructs -->
<define name="atomPlainTextConstruct">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<choice>
<value>text</value>
<value>html</value>
</choice>
</attribute>
</optional>
<text/>
</define>
<define name="atomXHTMLTextConstruct">
<ref name="atomCommonAttributes"/>
<attribute name="type">
<value>xhtml</value>
</attribute>
<ref name="xhtmlDiv"/>
</define>
<define name="atomTextConstruct">
<choice>
<ref name="atomPlainTextConstruct"/>
<ref name="atomXHTMLTextConstruct"/>
</choice>
</define>
<!-- Person Construct -->
<define name="atomPersonConstruct">
<ref name="atomCommonAttributes"/>
<interleave>
<element name="atom:name">
<text/>
</element>
<optional>
<element name="atom:uri">
<ref name="atomUri"/>
</element>
</optional>
<optional>
<element name="atom:email">
<ref name="atomEmailAddress"/>
</element>
</optional>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</define>
<!-- Date Construct -->
<define name="atomDateConstruct">
<ref name="atomCommonAttributes"/>
<data type="dateTime"/>
</define>
<!-- atom:feed -->
<define name="atomFeed">
<element name="atom:feed">
<s:rule context="atom:feed">
<s:assert test="atom:author or not(atom:entry[not(atom:author)])">An atom:feed must have an atom:author unless all of its atom:entry children have an atom:author.</s:assert>
</s:rule>
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<optional>
<ref name="atomGenerator"/>
</optional>
<optional>
<ref name="atomIcon"/>
</optional>
<ref name="atomId"/>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomLogo"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSubtitle"/>
</optional>
<ref name="atomTitle"/>
<ref name="atomUpdated"/>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
<zeroOrMore>
<ref name="atomEntry"/>
</zeroOrMore>
</element>
</define>
<!-- atom:entry -->
<define name="atomEntry">
<element name="atom:entry">
<s:rule context="atom:entry">
<s:assert test="atom:link[@rel='alternate'] or atom:link[not(@rel)] or atom:content">An atom:entry must have at least one atom:link element with a rel attribute of 'alternate' or an atom:content.</s:assert>
</s:rule>
<s:rule context="atom:entry">
<s:assert test="atom:author or ../atom:author or atom:source/atom:author">An atom:entry must have an atom:author if its feed does not.</s:assert>
</s:rule>
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<optional>
<ref name="atomContent"/>
</optional>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<ref name="atomId"/>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomPublished"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSource"/>
</optional>
<optional>
<ref name="atomSummary"/>
</optional>
<ref name="atomTitle"/>
<ref name="atomUpdated"/>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</element>
</define>
<!-- atom:content -->
<define name="atomInlineTextContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<choice>
<value>text</value>
<value>html</value>
</choice>
</attribute>
</optional>
<zeroOrMore>
<text/>
</zeroOrMore>
</element>
</define>
<define name="atomInlineXHTMLContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<attribute name="type">
<value>xhtml</value>
</attribute>
<ref name="xhtmlDiv"/>
</element>
</define>
<define name="atomInlineOtherContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="atomOutOfLineContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<attribute name="src">
<ref name="atomUri"/>
</attribute>
<empty/>
</element>
</define>
<define name="atomContent">
<choice>
<ref name="atomInlineTextContent"/>
<ref name="atomInlineXHTMLContent"/>
<ref name="atomInlineOtherContent"/>
<ref name="atomOutOfLineContent"/>
</choice>
</define>
<!-- atom:author -->
<define name="atomAuthor">
<element name="atom:author">
<ref name="atomPersonConstruct"/>
</element>
</define>
<!-- atom:category -->
<define name="atomCategory">
<element name="atom:category">
<ref name="atomCommonAttributes"/>
<attribute name="term"/>
<optional>
<attribute name="scheme">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="label"/>
</optional>
<ref name="undefinedContent"/>
</element>
</define>
<!-- atom:contributor -->
<define name="atomContributor">
<element name="atom:contributor">
<ref name="atomPersonConstruct"/>
</element>
</define>
<!-- atom:generator -->
<define name="atomGenerator">
<element name="atom:generator">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="uri">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="version"/>
</optional>
<text/>
</element>
</define>
<!-- atom:icon -->
<define name="atomIcon">
<element name="atom:icon">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:id -->
<define name="atomId">
<element name="atom:id">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:logo -->
<define name="atomLogo">
<element name="atom:logo">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:link -->
<define name="atomLink">
<element name="atom:link">
<ref name="atomCommonAttributes"/>
<attribute name="href">
<ref name="atomUri"/>
</attribute>
<optional>
<attribute name="rel">
<choice>
<ref name="atomNCName"/>
<ref name="atomUri"/>
</choice>
</attribute>
</optional>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<optional>
<attribute name="hreflang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<optional>
<attribute name="title"/>
</optional>
<optional>
<attribute name="length"/>
</optional>
<ref name="undefinedContent"/>
</element>
</define>
<!-- atom:published -->
<define name="atomPublished">
<element name="atom:published">
<ref name="atomDateConstruct"/>
</element>
</define>
<!-- atom:rights -->
<define name="atomRights">
<element name="atom:rights">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:source -->
<define name="atomSource">
<element name="atom:source">
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<optional>
<ref name="atomGenerator"/>
</optional>
<optional>
<ref name="atomIcon"/>
</optional>
<optional>
<ref name="atomId"/>
</optional>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomLogo"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSubtitle"/>
</optional>
<optional>
<ref name="atomTitle"/>
</optional>
<optional>
<ref name="atomUpdated"/>
</optional>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</element>
</define>
<!-- atom:subtitle -->
<define name="atomSubtitle">
<element name="atom:subtitle">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:summary -->
<define name="atomSummary">
<element name="atom:summary">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:title -->
<define name="atomTitle">
<element name="atom:title">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:updated -->
<define name="atomUpdated">
<element name="atom:updated">
<ref name="atomDateConstruct"/>
</element>
</define>
<!-- Low-level simple types -->
<define name="atomNCName">
<data type="string">
<param name="minLength">1</param>
<param name="pattern">[^:]*</param>
</data>
</define>
<!-- Whatever a media type is, it contains at least one slash -->
<define name="atomMediaType">
<data type="string">
<param name="pattern">.+/.+</param>
</data>
</define>
<!-- As defined in RFC 3066 -->
<define name="atomLanguageTag">
<data type="string">
<param name="pattern">[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*</param>
</data>
</define>
<!--
Unconstrained; it's not entirely clear how IRI fit into
xsd:anyURI so let's not try to constrain it here
-->
<define name="atomUri">
<text/>
</define>
<!-- Whatever an email address is, it contains at least one @ -->
<define name="atomEmailAddress">
<data type="string">
<param name="pattern">.+@.+</param>
</data>
</define>
<!-- Simple Extension -->
<define name="simpleExtensionElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<text/>
</element>
</define>
<!-- Structured Extension -->
<define name="structuredExtensionElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<choice>
<group>
<oneOrMore>
<attribute>
<anyName/>
</attribute>
</oneOrMore>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</group>
<group>
<zeroOrMore>
<attribute>
<anyName/>
</attribute>
</zeroOrMore>
<group>
<optional>
<text/>
</optional>
<oneOrMore>
<ref name="anyElement"/>
</oneOrMore>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</group>
</group>
</choice>
</element>
</define>
<!-- Other Extensibility -->
<define name="extensionElement">
<choice>
<ref name="simpleExtensionElement"/>
<ref name="structuredExtensionElement"/>
</choice>
</define>
<define name="undefinedAttribute">
<attribute>
<anyName>
<except>
<name>xml:base</name>
<name>xml:lang</name>
<nsName ns=""/>
</except>
</anyName>
</attribute>
</define>
<define name="undefinedContent">
<zeroOrMore>
<choice>
<text/>
<ref name="anyForeignElement"/>
</choice>
</zeroOrMore>
</define>
<define name="anyElement">
<element>
<anyName/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="anyForeignElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<!-- XHTML -->
<define name="anyXHTML">
<element>
<nsName/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyXHTML"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="xhtmlDiv">
<element name="xhtml:div">
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyXHTML"/>
</choice>
</zeroOrMore>
</element>
</define>
</grammar>
<!-- EOF -->
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/schemas/README
New file
0,0 → 1,9
Most of these schemas are only available in RNC (RelaxNG, Compact) format.
 
libxml (and therefor PHP) only supports RelaxNG - the XML version.
 
To update these, you will need a conversion utility, like trang (http://www.thaiopensource.com/relaxng/trang.html).
 
 
 
clockwerx@clockwerx-desktop:~/trang$ java -jar trang.jar -I rnc -O rng http://atompub.org/2005/08/17/atom.rnc atom.rng
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/schemas/rss10.rng
New file
0,0 → 1,113
<?xml version='1.0' encoding='UTF-8'?>
<!-- http://www.xml.com/lpt/a/2002/01/23/relaxng.html -->
<!-- http://www.oasis-open.org/committees/relax-ng/tutorial-20011203.html -->
<!-- http://www.zvon.org/xxl/XMLSchemaTutorial/Output/ser_wildcards_st8.html -->
 
<grammar xmlns='http://relaxng.org/ns/structure/1.0'
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
ns='http://purl.org/rss/1.0/'
datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'>
 
<start>
<element name='RDF' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<ref name='RDFContent'/>
</element>
</start>
 
<define name='RDFContent' ns='http://purl.org/rss/1.0/'>
<interleave>
<element name='channel'>
<ref name='channelContent'/>
</element>
<optional>
<element name='image'><ref name='imageContent'/></element>
</optional>
<oneOrMore>
<element name='item'><ref name='itemContent'/></element>
</oneOrMore>
</interleave>
</define>
 
<define name='channelContent' combine="interleave">
<interleave>
<element name='title'><data type='string'/></element>
<element name='link'><data type='anyURI'/></element>
<element name='description'><data type='string'/></element>
<element name='image'>
<attribute name='resource' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<data type='anyURI'/>
</attribute>
</element>
<element name='items'>
<ref name='itemsContent'/>
</element>
<attribute name='about' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<data type='anyURI'/>
</attribute>
</interleave>
</define>
<define name="itemsContent">
<element name="Seq" ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<oneOrMore>
<element name="li" ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<choice>
<attribute name='resource'> <!-- Why doesn't RDF/RSS1.0 ns qualify this attribute? -->
<data type='anyURI'/>
</attribute>
<attribute name='resource' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<data type='anyURI'/>
</attribute>
</choice>
</element>
</oneOrMore>
</element>
</define>
<define name='imageContent'>
<interleave>
<element name='title'><data type='string'/></element>
<element name='link'><data type='anyURI'/></element>
<element name='url'><data type='anyURI'/></element>
<attribute name='about' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<data type='anyURI'/>
</attribute>
</interleave>
</define>
 
<define name='itemContent'>
<interleave>
<element name='title'><data type='string'/></element>
<element name='link'><data type='anyURI'/></element>
<optional><element name='description'><data type='string'/></element></optional>
<ref name="anyThing"/>
<attribute name='about' ns='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<data type='anyURI'/>
</attribute>
</interleave>
</define>
 
<define name='anyThing'>
<zeroOrMore>
<choice>
<text/>
<element>
<anyName>
<except>
<nsName/>
</except>
</anyName>
<ref name='anyThing'/>
<zeroOrMore>
<attribute>
<anyName/>
</attribute>
</zeroOrMore>
</element>
</choice>
</zeroOrMore>
</define>
</grammar>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/schemas/rss11.rng
New file
0,0 → 1,218
<?xml version="1.0" encoding="UTF-8"?>
<!--
RELAX NG Compact Schema for RSS 1.1
Sean B. Palmer, inamidst.com
Christopher Schmidt, crschmidt.net
License: This schema is in the public domain
-->
<grammar xmlns:rss="http://purl.org/net/rss1.1#" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns="http://purl.org/net/rss1.1#" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<ref name="Channel"/>
</start>
<define name="Channel">
<a:documentation>http://purl.org/net/rss1.1#Channel</a:documentation>
<element name="Channel">
<ref name="Channel.content"/>
 
</element>
</define>
<define name="Channel.content">
<optional>
<ref name="AttrXMLLang"/>
</optional>
<optional>
<ref name="AttrXMLBase"/>
</optional>
 
<ref name="AttrRDFAbout"/>
<interleave>
<ref name="title"/>
<ref name="link"/>
<ref name="description"/>
<optional>
<ref name="image"/>
</optional>
<zeroOrMore>
 
<ref name="Any"/>
</zeroOrMore>
<ref name="items"/>
</interleave>
</define>
<define name="title">
<a:documentation>http://purl.org/net/rss1.1#title</a:documentation>
<element name="title">
 
<ref name="title.content"/>
</element>
</define>
<define name="title.content">
<optional>
<ref name="AttrXMLLang"/>
</optional>
<text/>
</define>
 
<define name="link">
<a:documentation>http://purl.org/net/rss1.1#link</a:documentation>
<element name="link">
<ref name="link.content"/>
</element>
</define>
<define name="link.content">
<data type="anyURI"/>
 
</define>
<define name="description">
<a:documentation>http://purl.org/net/rss1.1#description</a:documentation>
<element name="description">
<ref name="description.content"/>
</element>
</define>
<define name="description.content">
 
<optional>
<ref name="AttrXMLLang"/>
</optional>
<text/>
</define>
<define name="image">
<a:documentation>http://purl.org/net/rss1.1#image</a:documentation>
<element name="image">
 
<ref name="image.content"/>
</element>
</define>
<define name="image.content">
<optional>
<ref name="AttrXMLLang"/>
</optional>
<ref name="AttrRDFResource"/>
<interleave>
 
<ref name="title"/>
<optional>
<ref name="link"/>
</optional>
<ref name="url"/>
<zeroOrMore>
<ref name="Any"/>
</zeroOrMore>
</interleave>
 
</define>
<define name="url">
<a:documentation>http://purl.org/net/rss1.1#url</a:documentation>
<element name="url">
<ref name="url.content"/>
</element>
</define>
<define name="url.content">
 
<data type="anyURI"/>
</define>
<define name="items">
<a:documentation>http://purl.org/net/rss1.1#items</a:documentation>
<element name="items">
<ref name="items.content"/>
</element>
</define>
 
<define name="items.content">
<optional>
<ref name="AttrXMLLang"/>
</optional>
<ref name="AttrRDFCollection"/>
<zeroOrMore>
<ref name="item"/>
</zeroOrMore>
</define>
 
<define name="item">
<a:documentation>http://purl.org/net/rss1.1#item</a:documentation>
<element name="item">
<ref name="item.content"/>
</element>
</define>
<define name="item.content">
<optional>
 
<ref name="AttrXMLLang"/>
</optional>
<ref name="AttrRDFAbout"/>
<interleave>
<ref name="title"/>
<ref name="link"/>
<optional>
<ref name="description"/>
</optional>
 
<optional>
<ref name="image"/>
</optional>
<zeroOrMore>
<ref name="Any"/>
</zeroOrMore>
</interleave>
</define>
<define name="Any">
 
<a:documentation>http://purl.org/net/rss1.1#Any</a:documentation>
<element>
<anyName>
<except>
<nsName/>
</except>
</anyName>
<ref name="Any.content"/>
 
</element>
</define>
<define name="Any.content">
<zeroOrMore>
<attribute>
<anyName>
<except>
<nsName/>
<nsName ns=""/>
 
</except>
</anyName>
</attribute>
</zeroOrMore>
<mixed>
<zeroOrMore>
<ref name="Any"/>
</zeroOrMore>
</mixed>
 
</define>
<define name="AttrXMLLang">
<attribute name="xml:lang">
<data type="language"/>
</attribute>
</define>
<define name="AttrXMLBase">
<attribute name="xml:base">
<data type="anyURI"/>
 
</attribute>
</define>
<define name="AttrRDFAbout">
<attribute name="rdf:about">
<data type="anyURI"/>
</attribute>
</define>
<define name="AttrRDFResource">
<attribute name="rdf:parseType">
 
<value>Resource</value>
</attribute>
</define>
<define name="AttrRDFCollection">
<attribute name="rdf:parseType">
<value>Collection</value>
</attribute>
</define>
 
</grammar>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/schemas/rss20.rng
New file
0,0 → 1,298
<?xml version="1.0" encoding="utf-8"?>
 
<!-- ======================================================================
* Author: Dino Morelli
* Began: 2004-Feb-18
* Build #: 0001
* Version: 0.1
* E-Mail: dino.morelli@snet.net
* URL: (none yet)
* License: (none yet)
*
* ========================================================================
*
* RSS v2.0 Relax NG schema
*
* ==================================================================== -->
 
 
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
 
<start>
<ref name="element-rss" />
</start>
 
<define name="element-title">
<element name="title">
 
<text />
</element>
</define>
 
<define name="element-description">
<element name="description">
<text />
</element>
</define>
 
<define name="element-link">
<element name="link">
<text />
</element>
</define>
 
<define name="element-category">
<element name="category">
<optional>
 
<attribute name="domain" />
</optional>
<text />
</element>
</define>
 
<define name="element-rss">
<element name="rss">
<attribute name="version">
 
<value>2.0</value>
</attribute>
<element name="channel">
<interleave>
<ref name="element-title" />
<ref name="element-link" />
<ref name="element-description" />
<optional>
 
<element name="language"><text /></element>
</optional>
<optional>
<element name="copyright"><text /></element>
</optional>
<optional>
<element name="lastBuildDate"><text /></element>
</optional>
<optional>
 
<element name="docs"><text /></element>
</optional>
<optional>
<element name="generator"><text /></element>
</optional>
<optional>
<ref name="element-category" />
</optional>
<optional>
 
<element name="managingEditor"><text /></element>
</optional>
<optional>
<element name="webMaster"><text /></element>
</optional>
<optional>
<element name="pubDate"><text /></element>
</optional>
<optional>
 
<element name="rating"><text /></element>
</optional>
<optional>
<element name="image">
<interleave>
<element name="url"><text /></element>
<ref name="element-title" />
<ref name="element-link" />
<optional>
 
<element name="width"><text /></element>
</optional>
<optional>
<element name="height"><text /></element>
</optional>
<optional>
<ref name="element-description" />
</optional>
</interleave>
 
</element>
</optional>
<optional>
<element name="cloud">
<attribute name="domain" />
<attribute name="port" />
<attribute name="path" />
<attribute name="registerProcedure" />
<attribute name="protocol" />
 
</element>
</optional>
<optional>
<element name="textInput">
<interleave>
<ref name="element-title" />
<ref name="element-description" />
<element name="name"><text /></element>
<ref name="element-link" />
 
</interleave>
</element>
</optional>
<optional>
<element name="skipHours">
<oneOrMore>
<element name="hour">
<choice>
<value>0</value>
 
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
<value>5</value>
<value>6</value>
 
<value>7</value>
<value>8</value>
<value>9</value>
<value>10</value>
<value>11</value>
<value>12</value>
 
<value>13</value>
<value>14</value>
<value>15</value>
<value>16</value>
<value>17</value>
<value>18</value>
 
<value>19</value>
<value>20</value>
<value>21</value>
<value>22</value>
<value>23</value>
</choice>
 
</element>
</oneOrMore>
</element>
</optional>
<optional>
<element name="skipDays">
<oneOrMore>
<element name="day">
<choice>
 
<value>0</value>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
<value>5</value>
 
<value>6</value>
<value>7</value>
<value>8</value>
<value>9</value>
<value>10</value>
<value>11</value>
 
<value>12</value>
<value>13</value>
<value>14</value>
<value>15</value>
<value>16</value>
<value>17</value>
 
<value>18</value>
<value>19</value>
<value>20</value>
<value>21</value>
<value>22</value>
<value>23</value>
 
<value>24</value>
<value>25</value>
<value>26</value>
<value>27</value>
<value>28</value>
<value>29</value>
 
<value>30</value>
<value>31</value>
</choice>
</element>
</oneOrMore>
</element>
</optional>
<optional>
 
<element name="ttl"><text /></element>
</optional>
<zeroOrMore>
<element name="item">
<interleave>
<choice>
<ref name="element-title" />
<ref name="element-description" />
<interleave>
 
<ref name="element-title" />
<ref name="element-description" />
</interleave>
</choice>
<optional>
<ref name="element-link" />
</optional>
<optional>
<element name="author"><text /></element>
 
</optional>
<optional>
<ref name="element-category" />
</optional>
<optional>
<element name="comments"><text /></element>
</optional>
<optional>
<element name="enclosure">
 
<attribute name="url" />
<attribute name="length" />
<attribute name="type" />
<text />
</element>
</optional>
<optional>
<element name="guid">
<optional>
 
<attribute name="isPermaLink">
<choice>
<value>true</value>
<value>false</value>
</choice>
</attribute>
</optional>
<text />
 
</element>
</optional>
<optional>
<element name="pubDate"><text /></element>
</optional>
<optional>
<element name="source">
<attribute name="url" />
<text />
 
</element>
</optional>
</interleave>
</element>
</zeroOrMore>
</interleave>
</element>
</element>
</define>
 
</grammar>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/XmlFeedParser.php
New file
0,0 → 1,304
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Key gateway class for XML_Feed_Parser package
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
* @version CVS: $Id: Parser.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This is the core of the XML_Feed_Parser package. It identifies feed types
* and abstracts access to them. It is an iterator, allowing for easy access
* to the entire feed.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParser implements Iterator {
/**
* This is where we hold the feed object
* @var Object
*/
private $feed;
 
/**
* To allow for extensions, we make a public reference to the feed model
* @var DOMDocument
*/
public $model;
/**
* A map between entry ID and offset
* @var array
*/
protected $idMappings = array();
 
/**
* A storage space for Namespace URIs.
* @var array
*/
private $feedNamespaces = array(
'rss2' => array(
'http://backend.userland.com/rss',
'http://backend.userland.com/rss2',
'http://blogs.law.harvard.edu/tech/rss'));
/**
* Detects feed types and instantiate appropriate objects.
*
* Our constructor takes care of detecting feed types and instantiating
* appropriate classes. For now we're going to treat Atom 0.3 as Atom 1.0
* but raise a warning. I do not intend to introduce full support for
* Atom 0.3 as it has been deprecated, but others are welcome to.
*
* @param string $feed XML serialization of the feed
* @param bool $strict Whether or not to validate the feed
* @param bool $suppressWarnings Trigger errors for deprecated feed types?
* @param bool $tidy Whether or not to try and use the tidy library on input
*/
function __construct($feed, $strict = false, $suppressWarnings = true, $tidy = true) {
$this->model = new DOMDocument;
if (! $this->model->loadXML($feed)) {
if (extension_loaded('tidy') && $tidy) {
$tidy = new tidy;
$tidy->parseString($feed, array('input-xml' => true, 'output-xml' => true));
$tidy->cleanRepair();
if (! $this->model->loadXML((string) $tidy)) {
throw new XmlFeedParserException("Entrée invalide : le flux n'est pas du XML valide");
}
} else {
throw new XmlFeedParserException("Entrée invalide : le flux n'est pas du XML valide");
}
}
 
/* detect feed type */
$doc_element = $this->model->documentElement;
$error = false;
 
switch (true) {
case ($doc_element->namespaceURI == 'http://www.w3.org/2005/Atom'):
$class = 'XmlFeedParserAtom';
break;
case ($doc_element->namespaceURI == 'http://purl.org/atom/ns#'):
$class = 'XmlFeedParserAtom';
$error = "Atom 0.3 est déprécié, le parseur en version 1.0 sera utilisé mais toutes les options ne seront pas disponibles.";
break;
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.0/'
|| ($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://purl.org/rss/1.0/')):
$class = 'XmlFeedParserRss1';
break;
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.1/'
|| ($doc_element->hasChildNodes()
&& $doc_element->childNodes->length > 1
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://purl.org/rss/1.1/')):
$class = 'XmlFeedParserRss11';
break;
case (($doc_element->hasChildNodes()
&& $doc_element->childNodes->length > 1
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/')
|| $doc_element->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/'):
$class = 'XmlFeedParserRss09';
break;
case ($doc_element->tagName == 'rss'
and $doc_element->hasAttribute('version')
&& $doc_element->getAttribute('version') == 0.91):
$error = 'RSS 0.91 has been superceded by RSS2.0. Using RSS2.0 parser.';
$class = 'XmlFeedParserRss2';
break;
case ($doc_element->tagName == 'rss'
and $doc_element->hasAttribute('version')
&& $doc_element->getAttribute('version') == 0.92):
$error = 'RSS 0.92 has been superceded by RSS2.0. Using RSS2.0 parser.';
$class = 'XmlFeedParserRss2';
break;
case (in_array($doc_element->namespaceURI, $this->feedNamespaces['rss2'])
|| $doc_element->tagName == 'rss'):
if (! $doc_element->hasAttribute('version') || $doc_element->getAttribute('version') != 2) {
$error = 'RSS version not specified. Parsing as RSS2.0';
}
$class = 'XmlFeedParserRss2';
break;
default:
throw new XmlFeedParserException('Type de flux de syndicaton inconnu');
break;
}
 
if (! $suppressWarnings && ! empty($error)) {
trigger_error($error, E_USER_WARNING);
}
 
/* Instantiate feed object */
$this->feed = new $class($this->model, $strict);
}
 
/**
* Proxy to allow feed element names to be used as method names
*
* For top-level feed elements we will provide access using methods or
* attributes. This function simply passes on a request to the appropriate
* feed type object.
*
* @param string $call - the method being called
* @param array $attributes
*/
function __call($call, $attributes) {
$attributes = array_pad($attributes, 5, false);
list($a, $b, $c, $d, $e) = $attributes;
return $this->feed->$call($a, $b, $c, $d, $e);
}
 
/**
* Proxy to allow feed element names to be used as attribute names
*
* To allow variable-like access to feed-level data we use this
* method. It simply passes along to __call() which in turn passes
* along to the relevant object.
*
* @param string $val - the name of the variable required
*/
function __get($val) {
return $this->feed->$val;
}
 
/**
* Provides iteration functionality.
*
* Of course we must be able to iterate... This function simply increases
* our internal counter.
*/
function next() {
if (isset($this->current_item) &&
$this->current_item <= $this->feed->numberEntries - 1) {
++$this->current_item;
} else if (! isset($this->current_item)) {
$this->current_item = 0;
} else {
return false;
}
}
 
/**
* Return XML_Feed_Type object for current element
*
* @return XML_Feed_Parser_Type Object
*/
function current() {
return $this->getEntryByOffset($this->current_item);
}
 
/**
* For iteration -- returns the key for the current stage in the array.
*
* @return int
*/
function key() {
return $this->current_item;
}
 
/**
* For iteration -- tells whether we have reached the
* end.
*
* @return bool
*/
function valid() {
return $this->current_item < $this->feed->numberEntries;
}
 
/**
* For iteration -- resets the internal counter to the beginning.
*/
function rewind() {
$this->current_item = 0;
}
 
/**
* Provides access to entries by ID if one is specified in the source feed.
*
* As well as allowing the items to be iterated over we want to allow
* users to be able to access a specific entry. This is one of two ways of
* doing that, the other being by offset. This method can be quite slow
* if dealing with a large feed that hasn't yet been processed as it
* instantiates objects for every entry until it finds the one needed.
*
* @param string $id Valid ID for the given feed format
* @return XML_Feed_Parser_Type|false
*/
function getEntryById($id) {
if (isset($this->idMappings[$id])) {
return $this->getEntryByOffset($this->idMappings[$id]);
}
 
/*
* Since we have not yet encountered that ID, let's go through all the
* remaining entries in order till we find it.
* This is a fairly slow implementation, but it should work.
*/
return $this->feed->getEntryById($id);
}
 
/**
* Retrieve entry by numeric offset, starting from zero.
*
* As well as allowing the items to be iterated over we want to allow
* users to be able to access a specific entry. This is one of two ways of
* doing that, the other being by ID.
*
* @param int $offset The position of the entry within the feed, starting from 0
* @return XML_Feed_Parser_Type|false
*/
function getEntryByOffset($offset) {
if ($offset < $this->feed->numberEntries) {
if (isset($this->feed->entries[$offset])) {
return $this->feed->entries[$offset];
} else {
try {
$this->feed->getEntryByOffset($offset);
} catch (Exception $e) {
return false;
}
$id = $this->feed->entries[$offset]->getID();
$this->idMappings[$id] = $offset;
return $this->feed->entries[$offset];
}
} else {
return false;
}
}
 
/**
* Retrieve version details from feed type class.
*
* @return void
* @author James Stewart
*/
function version() {
return $this->feed->version;
}
/**
* Returns a string representation of the feed.
*
* @return String
**/
function __toString() {
return $this->feed->__toString();
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserAtom.php
New file
0,0 → 1,358
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Atom feed class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: Atom.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This is the class that determines how we manage Atom 1.0 feeds
*
* How we deal with constructs:
* date - return as unix datetime for use with the 'date' function unless specified otherwise
* text - return as is. optional parameter will give access to attributes
* person - defaults to name, but parameter based access
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserAtom extends XmlFeedParserType {
/**
* The URI of the RelaxNG schema used to (optionally) validate the feed
* @var string
*/
protected $relax = 'atom.rng';
 
/**
* We're likely to use XPath, so let's keep it global
* @var DOMXPath
*/
public $xpath;
 
/**
* When performing XPath queries we will use this prefix
* @var string
*/
private $xpathPrefix = '//';
 
/**
* The feed type we are parsing
* @var string
*/
public $version = 'Atom 1.0';
 
/**
* The class used to represent individual items
* @var string
*/
protected $itemClass = 'XmlFeedParserAtomElement';
/**
* The element containing entries
* @var string
*/
protected $itemElement = 'entry';
 
/**
* Here we map those elements we're not going to handle individually
* to the constructs they are. The optional second parameter in the array
* tells the parser whether to 'fall back' (not apt. at the feed level) or
* fail if the element is missing. If the parameter is not set, the function
* will simply return false and leave it to the client to decide what to do.
* @var array
*/
protected $map = array(
'author' => array('Person'),
'contributor' => array('Person'),
'icon' => array('Text'),
'logo' => array('Text'),
'id' => array('Text', 'fail'),
'rights' => array('Text'),
'subtitle' => array('Text'),
'title' => array('Text', 'fail'),
'updated' => array('Date', 'fail'),
'link' => array('Link'),
'generator' => array('Text'),
'category' => array('Category'),
'content' => array('Text'));
 
/**
* Here we provide a few mappings for those very special circumstances in
* which it makes sense to map back to the RSS2 spec. Key is RSS2 version
* value is an array consisting of the equivalent in atom and any attributes
* needed to make the mapping.
* @var array
*/
protected $compatMap = array(
'guid' => array('id'),
'links' => array('link'),
'tags' => array('category'),
'contributors' => array('contributor'));
 
/**
* Our constructor does nothing more than its parent.
*
* @param DOMDocument $xml A DOM object representing the feed
* @param bool (optional) $string Whether or not to validate this feed
*/
function __construct(DOMDocument $model, $strict = false) {
$this->model = $model;
 
if ($strict) {
if (! $this->relaxNGValidate()) {
throw new XML_Feed_Parser_Exception('Failed required validation');
}
}
 
$this->xpath = new DOMXPath($this->model);
$this->xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
$this->numberEntries = $this->count('entry');
}
 
/**
* Implement retrieval of an entry based on its ID for atom feeds.
*
* This function uses XPath to get the entry based on its ID. If DOMXPath::evaluate
* is available, we also use that to store a reference to the entry in the array
* used by getEntryByOffset so that method does not have to seek out the entry
* if it's requested that way.
*
* @param string $id any valid Atom ID.
* @return XML_Feed_Parser_AtomElement
*/
function getEntryById($id) {
if (isset($this->idMappings[$id])) {
return $this->entries[$this->idMappings[$id]];
}
 
$entries = $this->xpath->query("//atom:entry[atom:id='$id']");
 
if ($entries->length > 0) {
$xmlBase = $entries->item(0)->baseURI;
$entry = new $this->itemClass($entries->item(0), $this, $xmlBase);
if (in_array('evaluate', get_class_methods($this->xpath))) {
$offset = $this->xpath->evaluate("count(preceding-sibling::atom:entry)", $entries->item(0));
$this->entries[$offset] = $entry;
}
 
$this->idMappings[$id] = $entry;
 
return $entry;
}
}
 
/**
* Retrieves data from a person construct.
*
* Get a person construct. We default to the 'name' element but allow
* access to any of the elements.
*
* @param string $method The name of the person construct we want
* @param array $arguments An array which we hope gives a 'param'
* @return string|false
*/
protected function getPerson($method, $arguments) {
$offset = empty($arguments[0]) ? 0 : $arguments[0];
$parameter = empty($arguments[1]['param']) ? 'name' : $arguments[1]['param'];
$section = $this->model->getElementsByTagName($method);
if ($parameter == 'url') {
$parameter = 'uri';
}
 
if ($section->length <= $offset) {
return false;
}
 
$param = $section->item($offset)->getElementsByTagName($parameter);
if ($param->length == 0) {
return false;
}
return $param->item(0)->nodeValue;
}
 
/**
* Retrieves an element's content where that content is a text construct.
*
* Get a text construct. When calling this method, the two arguments
* allowed are 'offset' and 'attribute', so $parser->subtitle() would
* return the content of the element, while $parser->subtitle(false, 'type')
* would return the value of the type attribute.
*
* @todo Clarify overlap with getContent()
* @param string $method The name of the text construct we want
* @param array $arguments An array which we hope gives a 'param'
* @return string
*/
protected function getText($method, $arguments = Array()) {
$offset = empty($arguments[0]) ? 0: $arguments[0];
$attribute = empty($arguments[1]) ? false : $arguments[1];
$tags = $this->model->getElementsByTagName($method);
 
if ($tags->length <= $offset) {
return false;
}
 
$content = $tags->item($offset);
 
if (! $content->hasAttribute('type')) {
$content->setAttribute('type', 'text');
}
$type = $content->getAttribute('type');
 
if (! empty($attribute) and
! ($method == 'generator' and $attribute == 'name')) {
if ($content->hasAttribute($attribute)) {
return $content->getAttribute($attribute);
} else if ($attribute == 'href' and $content->hasAttribute('uri')) {
return $content->getAttribute('uri');
}
return false;
}
 
return $this->parseTextConstruct($content);
}
/**
* Extract content appropriately from atom text constructs
*
* Because of different rules applied to the content element and other text
* constructs, they are deployed as separate functions, but they share quite
* a bit of processing. This method performs the core common process, which is
* to apply the rules for different mime types in order to extract the content.
*
* @param DOMNode $content the text construct node to be parsed
* @return String
* @author James Stewart
**/
protected function parseTextConstruct(DOMNode $content) {
if ($content->hasAttribute('type')) {
$type = $content->getAttribute('type');
} else {
$type = 'text';
}
 
if (strpos($type, 'text/') === 0) {
$type = 'text';
}
 
switch ($type) {
case 'text':
case 'html':
return $content->textContent;
break;
case 'xhtml':
$container = $content->getElementsByTagName('div');
if ($container->length == 0) {
return false;
}
$contents = $container->item(0);
if ($contents->hasChildNodes()) {
/* Iterate through, applying xml:base and store the result */
$result = '';
foreach ($contents->childNodes as $node) {
$result .= $this->traverseNode($node);
}
return $result;
}
break;
case preg_match('@^[a-zA-Z]+/[a-zA-Z+]*xml@i', $type) > 0:
return $content;
break;
case 'application/octet-stream':
default:
return base64_decode(trim($content->nodeValue));
break;
}
return false;
}
/**
* Get a category from the entry.
*
* A feed or entry can have any number of categories. A category can have the
* attributes term, scheme and label.
*
* @param string $method The name of the text construct we want
* @param array $arguments An array which we hope gives a 'param'
* @return string
*/
function getCategory($method, $arguments) {
$offset = empty($arguments[0]) ? 0: $arguments[0];
$attribute = empty($arguments[1]) ? 'term' : $arguments[1];
$categories = $this->model->getElementsByTagName('category');
if ($categories->length <= $offset) {
$category = $categories->item($offset);
if ($category->hasAttribute($attribute)) {
return $category->getAttribute($attribute);
}
}
return false;
}
 
/**
* This element must be present at least once with rel="feed". This element may be
* present any number of further times so long as there is no clash. If no 'rel' is
* present and we're asked for one, we follow the example of the Universal Feed
* Parser and presume 'alternate'.
*
* @param int $offset the position of the link within the container
* @param string $attribute the attribute name required
* @param array an array of attributes to search by
* @return string the value of the attribute
*/
function getLink($offset = 0, $attribute = 'href', $params = false) {
if (is_array($params) and !empty($params)) {
$terms = array();
$alt_predicate = '';
$other_predicate = '';
 
foreach ($params as $key => $value) {
if ($key == 'rel' && $value == 'alternate') {
$alt_predicate = '[not(@rel) or @rel="alternate"]';
} else {
$terms[] = "@$key='$value'";
}
}
if (!empty($terms)) {
$other_predicate = '[' . join(' and ', $terms) . ']';
}
$query = $this->xpathPrefix . 'atom:link' . $alt_predicate . $other_predicate;
$links = $this->xpath->query($query);
} else {
$links = $this->model->getElementsByTagName('link');
}
if ($links->length > $offset) {
if ($links->item($offset)->hasAttribute($attribute)) {
$value = $links->item($offset)->getAttribute($attribute);
if ($attribute == 'href') {
$value = $this->addBase($value, $links->item($offset));
}
return $value;
} else if ($attribute == 'rel') {
return 'alternate';
}
}
return false;
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss09.php
New file
0,0 → 1,215
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS0.9 class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS09.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class handles RSS0.9 feeds.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
* @todo Find a Relax NG URI we can use
*/
class XmlFeedParserRss09 extends XmlFeedParserType {
/**
* The URI of the RelaxNG schema used to (optionally) validate the feed
* @var string
*/
protected $relax = '';
 
/**
* We're likely to use XPath, so let's keep it global
* @var DOMXPath
*/
protected $xpath;
 
/**
* The feed type we are parsing
* @var string
*/
public $version = 'RSS 0.9';
 
/**
* The class used to represent individual items
* @var string
*/
protected $itemClass = 'XmlFeedParserRss09Element';
/**
* The element containing entries
* @var string
*/
protected $itemElement = 'item';
 
/**
* Here we map those elements we're not going to handle individually
* to the constructs they are. The optional second parameter in the array
* tells the parser whether to 'fall back' (not apt. at the feed level) or
* fail if the element is missing. If the parameter is not set, the function
* will simply return false and leave it to the client to decide what to do.
* @var array
*/
protected $map = array(
'title' => array('Text'),
'link' => array('Text'),
'description' => array('Text'),
'image' => array('Image'),
'textinput' => array('TextInput'));
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS2.
* @var array
*/
protected $compatMap = array(
'title' => array('title'),
'link' => array('link'),
'subtitle' => array('description'));
 
/**
* We will be working with multiple namespaces and it is useful to
* keep them together
* @var array
*/
protected $namespaces = array(
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
 
/**
* Our constructor does nothing more than its parent.
*
* @todo RelaxNG validation
* @param DOMDocument $xml A DOM object representing the feed
* @param bool (optional) $string Whether or not to validate this feed
*/
function __construct(DOMDocument $model, $strict = false) {
$this->model = $model;
 
$this->xpath = new DOMXPath($model);
foreach ($this->namespaces as $key => $value) {
$this->xpath->registerNamespace($key, $value);
}
$this->numberEntries = $this->count('item');
}
 
/**
* Included for compatibility -- will not work with RSS 0.9
*
* This is not something that will work with RSS0.9 as it does not have
* clear restrictions on the global uniqueness of IDs.
*
* @param string $id any valid ID.
* @return false
*/
function getEntryById($id) {
return false;
}
 
/**
* Get details of the image associated with the feed.
*
* @return array|false an array simply containing the child elements
*/
protected function getImage() {
$images = $this->model->getElementsByTagName('image');
if ($images->length > 0) {
$image = $images->item(0);
$details = array();
if ($image->hasChildNodes()) {
$details = array(
'title' => $image->getElementsByTagName('title')->item(0)->value,
'link' => $image->getElementsByTagName('link')->item(0)->value,
'url' => $image->getElementsByTagName('url')->item(0)->value);
} else {
$details = array('title' => false,
'link' => false,
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
}
$details = array_merge($details,
array('description' => false, 'height' => false, 'width' => false));
if (! empty($details)) {
return $details;
}
}
return false;
}
 
/**
* The textinput element is little used, but in the interests of
* completeness we will support it.
*
* @return array|false
*/
protected function getTextInput() {
$inputs = $this->model->getElementsByTagName('textinput');
if ($inputs->length > 0) {
$input = $inputs->item(0);
$results = array();
$results['title'] = isset(
$input->getElementsByTagName('title')->item(0)->value) ?
$input->getElementsByTagName('title')->item(0)->value : null;
$results['description'] = isset(
$input->getElementsByTagName('description')->item(0)->value) ?
$input->getElementsByTagName('description')->item(0)->value : null;
$results['name'] = isset(
$input->getElementsByTagName('name')->item(0)->value) ?
$input->getElementsByTagName('name')->item(0)->value : null;
$results['link'] = isset(
$input->getElementsByTagName('link')->item(0)->value) ?
$input->getElementsByTagName('link')->item(0)->value : null;
if (empty($results['link']) &&
$input->attributes->getNamedItem('resource')) {
$results['link'] = $input->attributes->getNamedItem('resource')->nodeValue;
}
if (! empty($results)) {
return $results;
}
}
return false;
}
/**
* Get details of a link from the feed.
*
* In RSS1 a link is a text element but in order to ensure that we resolve
* URLs properly we have a special function for them.
*
* @return string
*/
function getLink($offset = 0, $attribute = 'href', $params = false) {
$links = $this->model->getElementsByTagName('link');
if ($links->length <= $offset) {
return false;
}
$link = $links->item($offset);
return $this->addBase($link->nodeValue, $link);
}
 
/**
* Not implemented - no available validation.
*/
public function relaxNGValidate() {
return true;
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserType.php
New file
0,0 → 1,455
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Abstract class providing common methods for XML_Feed_Parser feeds.
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: Type.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This abstract class provides some general methods that are likely to be
* implemented exactly the same way for all feed types.
*
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
*/
abstract class XmlFeedParserType {
/**
* Where we store our DOM object for this feed
* @var DOMDocument
*/
public $model;
 
/**
* For iteration we'll want a count of the number of entries
* @var int
*/
public $numberEntries;
 
/**
* Where we store our entry objects once instantiated
* @var array
*/
public $entries = array();
 
/**
* Store mappings between entry IDs and their position in the feed
*/
public $idMappings = array();
 
/**
* Proxy to allow use of element names as method names
*
* We are not going to provide methods for every entry type so this
* function will allow for a lot of mapping. We rely pretty heavily
* on this to handle our mappings between other feed types and atom.
*
* @param string $call - the method attempted
* @param array $arguments - arguments to that method
* @return mixed
*/
function __call($call, $arguments = array()) {
if (! is_array($arguments)) {
$arguments = array();
}
 
if (isset($this->compatMap[$call])) {
$tempMap = $this->compatMap;
$tempcall = array_pop($tempMap[$call]);
if (! empty($tempMap)) {
$arguments = array_merge($arguments, $tempMap[$call]);
}
$call = $tempcall;
}
 
/* To be helpful, we allow a case-insensitive search for this method */
if (! isset($this->map[$call])) {
foreach (array_keys($this->map) as $key) {
if (strtoupper($key) == strtoupper($call)) {
$call = $key;
break;
}
}
}
 
if (empty($this->map[$call])) {
return false;
}
 
$method = 'get' . $this->map[$call][0];
if ($method == 'getLink') {
$offset = empty($arguments[0]) ? 0 : $arguments[0];
$attribute = empty($arguments[1]) ? 'href' : $arguments[1];
$params = isset($arguments[2]) ? $arguments[2] : array();
return $this->getLink($offset, $attribute, $params);
}
if (method_exists($this, $method)) {
return $this->$method($call, $arguments);
}
 
return false;
}
 
/**
* Proxy to allow use of element names as attribute names
*
* For many elements variable-style access will be desirable. This function
* provides for that.
*
* @param string $value - the variable required
* @return mixed
*/
function __get($value) {
return $this->__call($value, array());
}
 
/**
* Utility function to help us resolve xml:base values
*
* We have other methods which will traverse the DOM and work out the different
* xml:base declarations we need to be aware of. We then need to combine them.
* If a declaration starts with a protocol then we restart the string. If it
* starts with a / then we add on to the domain name. Otherwise we simply tag
* it on to the end.
*
* @param string $base - the base to add the link to
* @param string $link
*/
function combineBases($base, $link) {
if (preg_match('/^[A-Za-z]+:\/\//', $link)) {
return $link;
} else if (preg_match('/^\//', $link)) {
/* Extract domain and suffix link to that */
preg_match('/^([A-Za-z]+:\/\/.*)?\/*/', $base, $results);
$firstLayer = $results[0];
return $firstLayer . "/" . $link;
} else if (preg_match('/^\.\.\//', $base)) {
/* Step up link to find place to be */
preg_match('/^((\.\.\/)+)(.*)$/', $link, $bases);
$suffix = $bases[3];
$count = preg_match_all('/\.\.\//', $bases[1], $steps);
$url = explode("/", $base);
for ($i = 0; $i <= $count; $i++) {
array_pop($url);
}
return implode("/", $url) . "/" . $suffix;
} else if (preg_match('/^(?!\/$)/', $base)) {
$base = preg_replace('/(.*\/).*$/', '$1', $base) ;
return $base . $link;
} else {
/* Just stick it on the end */
return $base . $link;
}
}
 
/**
* Determine whether we need to apply our xml:base rules
*
* Gets us the xml:base data and then processes that with regard
* to our current link.
*
* @param string
* @param DOMElement
* @return string
*/
function addBase($link, $element) {
if (preg_match('/^[A-Za-z]+:\/\//', $link)) {
return $link;
}
 
return $this->combineBases($element->baseURI, $link);
}
 
/**
* Get an entry by its position in the feed, starting from zero
*
* As well as allowing the items to be iterated over we want to allow
* users to be able to access a specific entry. This is one of two ways of
* doing that, the other being by ID.
*
* @param int $offset
* @return XML_Feed_Parser_RSS1Element
*/
function getEntryByOffset($offset) {
if (! isset($this->entries[$offset])) {
$entries = $this->model->getElementsByTagName($this->itemElement);
if ($entries->length > $offset) {
$xmlBase = $entries->item($offset)->baseURI;
$this->entries[$offset] = new $this->itemClass(
$entries->item($offset), $this, $xmlBase);
if ($id = $this->entries[$offset]->id) {
$this->idMappings[$id] = $this->entries[$offset];
}
} else {
throw new XML_Feed_Parser_Exception('No entries found');
}
}
 
return $this->entries[$offset];
}
 
/**
* Return a date in seconds since epoch.
*
* Get a date construct. We use PHP's strtotime to return it as a unix datetime, which
* is the number of seconds since 1970-01-01 00:00:00.
*
* @link http://php.net/strtotime
* @param string $method The name of the date construct we want
* @param array $arguments Included for compatibility with our __call usage
* @return int|false datetime
*/
protected function getDate($method, $arguments) {
$time = $this->model->getElementsByTagName($method);
if ($time->length == 0 || empty($time->item(0)->nodeValue)) {
return false;
}
return strtotime($time->item(0)->nodeValue);
}
 
/**
* Get a text construct.
*
* @param string $method The name of the text construct we want
* @param array $arguments Included for compatibility with our __call usage
* @return string
*/
protected function getText($method, $arguments = array()) {
$tags = $this->model->getElementsByTagName($method);
if ($tags->length > 0) {
$value = $tags->item(0)->nodeValue;
return $value;
}
return false;
}
 
/**
* Apply various rules to retrieve category data.
*
* There is no single way of declaring a category in RSS1/1.1 as there is in RSS2
* and Atom. Instead the usual approach is to use the dublin core namespace to
* declare categories. For example delicious use both:
* <dc:subject>PEAR</dc:subject> and: <taxo:topics><rdf:Bag>
* <rdf:li resource="http://del.icio.us/tag/PEAR" /></rdf:Bag></taxo:topics>
* to declare a categorisation of 'PEAR'.
*
* We need to be sensitive to this where possible.
*
* @param string $call for compatibility with our overloading
* @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array
* @return string|array|false
*/
protected function getCategory($call, $arguments) {
$categories = $this->model->getElementsByTagName('subject');
$offset = empty($arguments[0]) ? 0 : $arguments[0];
$array = empty($arguments[1]) ? false : true;
if ($categories->length <= $offset) {
return false;
}
if ($array) {
$list = array();
foreach ($categories as $category) {
array_push($list, $category->nodeValue);
}
return $list;
}
return $categories->item($offset)->nodeValue;
}
 
/**
* Count occurrences of an element
*
* This function will tell us how many times the element $type
* appears at this level of the feed.
*
* @param string $type the element we want to get a count of
* @return int
*/
protected function count($type) {
if ($tags = $this->model->getElementsByTagName($type)) {
return $tags->length;
}
return 0;
}
 
/**
* Part of our xml:base processing code
*
* We need a couple of methods to access XHTML content stored in feeds.
* This is because we dereference all xml:base references before returning
* the element. This method handles the attributes.
*
* @param DOMElement $node The DOM node we are iterating over
* @return string
*/
function processXHTMLAttributes($node) {
$return = '';
foreach ($node->attributes as $attribute) {
if ($attribute->name == 'src' or $attribute->name == 'href') {
$attribute->value = $this->addBase(htmlentities($attribute->value, NULL, 'utf-8'), $attribute);
}
if ($attribute->name == 'base') {
continue;
}
$return .= $attribute->name . '="' . htmlentities($attribute->value, NULL, 'utf-8') .'" ';
}
if (! empty($return)) {
return ' ' . trim($return);
}
return '';
}
 
/**
* Convert HTML entities based on the current character set.
*
* @param String
* @return String
*/
function processEntitiesForNodeValue($node) {
if (function_exists('iconv')) {
$current_encoding = $node->ownerDocument->encoding;
$value = iconv($current_encoding, 'UTF-8', $node->nodeValue);
} else if ($current_encoding == 'iso-8859-1') {
$value = utf8_encode($node->nodeValue);
} else {
$value = $node->nodeValue;
}
 
$decoded = html_entity_decode($value, NULL, 'UTF-8');
return htmlentities($decoded, NULL, 'UTF-8');
}
 
/**
* Part of our xml:base processing code
*
* We need a couple of methods to access XHTML content stored in feeds.
* This is because we dereference all xml:base references before returning
* the element. This method recurs through the tree descending from the node
* and builds our string.
*
* @param DOMElement $node The DOM node we are processing
* @return string
*/
function traverseNode($node) {
$content = '';
 
/* Add the opening of this node to the content */
if ($node instanceof DOMElement) {
$content .= '<' . $node->tagName .
$this->processXHTMLAttributes($node) . '>';
}
 
/* Process children */
if ($node->hasChildNodes()) {
foreach ($node->childNodes as $child) {
$content .= $this->traverseNode($child);
}
}
 
if ($node instanceof DOMText) {
$content .= $this->processEntitiesForNodeValue($node);
}
 
/* Add the closing of this node to the content */
if ($node instanceof DOMElement) {
$content .= '</' . $node->tagName . '>';
}
 
return $content;
}
 
/**
* Get content from RSS feeds (atom has its own implementation)
*
* The official way to include full content in an RSS1 entry is to use
* the content module's element 'encoded', and RSS2 feeds often duplicate that.
* Often, however, the 'description' element is used instead. We will offer that
* as a fallback. Atom uses its own approach and overrides this method.
*
* @return string|false
*/
protected function getContent($method, $arguments = array()) {
$options = array('encoded', 'description');
foreach ($options as $element) {
$test = $this->model->getElementsByTagName($element);
if ($test->length == 0) {
continue;
}
if ($test->item(0)->hasChildNodes()) {
$value = '';
foreach ($test->item(0)->childNodes as $child) {
if ($child instanceof DOMText) {
$value .= $child->nodeValue;
} else {
$simple = simplexml_import_dom($child);
$value .= $simple->asXML();
}
}
return $value;
} else if ($test->length > 0) {
return $test->item(0)->nodeValue;
}
}
return false;
}
 
/**
* Checks if this element has a particular child element.
*
* @param String
* @param Integer
* @return bool
**/
function hasKey($name, $offset = 0) {
$search = $this->model->getElementsByTagName($name);
return $search->length > $offset;
}
 
/**
* Return an XML serialization of the feed, should it be required. Most
* users however, will already have a serialization that they used when
* instantiating the object.
*
* @return string XML serialization of element
*/
function __toString() {
$simple = simplexml_import_dom($this->model);
return $simple->asXML();
}
/**
* Get directory holding RNG schemas. Method is based on that
* found in Contact_AddressBook.
*
* @return string PEAR data directory.
* @access public
* @static
*/
static function getSchemaDir() {
return dirname(__FILE__).'/../schemas';
}
 
public function relaxNGValidate() {
$dir = self::getSchemaDir();
$path = $dir . '/' . $this->relax;
return $this->model->relaxNGValidate($path);
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss1Element.php
New file
0,0 → 1,111
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS1 Element class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS1Element.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/*
* This class provides support for RSS 1.0 entries. It will usually be called by
* XML_Feed_Parser_RSS1 with which it shares many methods.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserRss1Element extends XmlFeedParserRss1 {
/**
* This will be a reference to the parent object for when we want
* to use a 'fallback' rule
* @var XML_Feed_Parser_RSS1
*/
protected $parent;
 
/**
* Our specific element map
* @var array
*/
protected $map = array(
'id' => array('Id'),
'title' => array('Text'),
'link' => array('Link'),
'description' => array('Text'), # or dc:description
'category' => array('Category'),
'rights' => array('Text'), # dc:rights
'creator' => array('Text'), # dc:creator
'publisher' => array('Text'), # dc:publisher
'contributor' => array('Text'), # dc:contributor
'date' => array('Date'), # dc:date
'content' => array('Content')
);
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS1.
* @var array
*/
protected $compatMap = array(
'content' => array('content'),
'updated' => array('lastBuildDate'),
'published' => array('date'),
'subtitle' => array('description'),
'updated' => array('date'),
'author' => array('creator'),
'contributor' => array('contributor')
);
 
/**
* Store useful information for later.
*
* @param DOMElement $element - this item as a DOM element
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
*/
function __construct(DOMElement $element, $parent, $xmlBase = '') {
$this->model = $element;
$this->parent = $parent;
}
 
/**
* If an rdf:about attribute is specified, return it as an ID
*
* There is no established way of showing an ID for an RSS1 entry. We will
* simulate it using the rdf:about attribute of the entry element. This cannot
* be relied upon for unique IDs but may prove useful.
*
* @return string|false
*/
function getId() {
if ($this->model->attributes->getNamedItem('about')) {
return $this->model->attributes->getNamedItem('about')->nodeValue;
}
return false;
}
 
/**
* How RSS1 should support for enclosures is not clear. For now we will return
* false.
*
* @return false
*/
function getEnclosure() {
return false;
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss11Element.php
New file
0,0 → 1,145
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS1 Element class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS11Element.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/*
* This class provides support for RSS 1.1 entries. It will usually be called by
* XML_Feed_Parser_RSS11 with which it shares many methods.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserRss11Element extends XmlFeedParserRss11 {
/**
* This will be a reference to the parent object for when we want
* to use a 'fallback' rule
* @var XML_Feed_Parser_RSS1
*/
protected $parent;
 
/**
* Our specific element map
* @var array
*/
protected $map = array(
'id' => array('Id'),
'title' => array('Text'),
'link' => array('Link'),
'description' => array('Text'), # or dc:description
'category' => array('Category'),
'rights' => array('Text'), # dc:rights
'creator' => array('Text'), # dc:creator
'publisher' => array('Text'), # dc:publisher
'contributor' => array('Text'), # dc:contributor
'date' => array('Date'), # dc:date
'content' => array('Content')
);
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS1.
* @var array
*/
protected $compatMap = array(
'content' => array('content'),
'updated' => array('lastBuildDate'),
'published' => array('date'),
'subtitle' => array('description'),
'updated' => array('date'),
'author' => array('creator'),
'contributor' => array('contributor')
);
 
/**
* Store useful information for later.
*
* @param DOMElement $element - this item as a DOM element
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
*/
function __construct(DOMElement $element, $parent, $xmlBase = '') {
$this->model = $element;
$this->parent = $parent;
}
 
/**
* If an rdf:about attribute is specified, return that as an ID
*
* There is no established way of showing an ID for an RSS1 entry. We will
* simulate it using the rdf:about attribute of the entry element. This cannot
* be relied upon for unique IDs but may prove useful.
*
* @return string|false
*/
function getId() {
if ($this->model->attributes->getNamedItem('about')) {
return $this->model->attributes->getNamedItem('about')->nodeValue;
}
return false;
}
 
/**
* Return the entry's content
*
* The official way to include full content in an RSS1 entry is to use
* the content module's element 'encoded'. Often, however, the 'description'
* element is used instead. We will offer that as a fallback.
*
* @return string|false
*/
function getContent() {
$options = array('encoded', 'description');
foreach ($options as $element) {
$test = $this->model->getElementsByTagName($element);
if ($test->length == 0) {
continue;
}
if ($test->item(0)->hasChildNodes()) {
$value = '';
foreach ($test->item(0)->childNodes as $child) {
if ($child instanceof DOMText) {
$value .= $child->nodeValue;
} else {
$simple = simplexml_import_dom($child);
$value .= $simple->asXML();
}
}
return $value;
} else if ($test->length > 0) {
return $test->item(0)->nodeValue;
}
}
return false;
}
/**
* How RSS1.1 should support for enclosures is not clear. For now we will return
* false.
*
* @return false
*/
function getEnclosure() {
return false;
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss2Element.php
New file
0,0 → 1,166
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Class representing entries in an RSS2 feed.
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS2Element.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class provides support for RSS 2.0 entries. It will usually be
* called by XML_Feed_Parser_RSS2 with which it shares many methods.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserRss2Element extends XmlFeedParserRss2 {
/**
* This will be a reference to the parent object for when we want
* to use a 'fallback' rule
* @var XML_Feed_Parser_RSS2
*/
protected $parent;
 
/**
* Our specific element map
* @var array
*/
protected $map = array(
'title' => array('Text'),
'guid' => array('Guid'),
'description' => array('Text'),
'author' => array('Text'),
'comments' => array('Text'),
'enclosure' => array('Enclosure'),
'pubDate' => array('Date'),
'source' => array('Source'),
'link' => array('Text'),
'content' => array('Content'));
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS2.
* @var array
*/
protected $compatMap = array(
'id' => array('guid'),
'updated' => array('lastBuildDate'),
'published' => array('pubdate'),
'guidislink' => array('guid', 'ispermalink'),
'summary' => array('description'));
 
/**
* Store useful information for later.
*
* @param DOMElement $element - this item as a DOM element
* @param XML_Feed_Parser_RSS2 $parent - the feed of which this is a member
*/
function __construct(DOMElement $element, $parent, $xmlBase = '') {
$this->model = $element;
$this->parent = $parent;
}
 
/**
* Get the value of the guid element, if specified
*
* guid is the closest RSS2 has to atom's ID. It is usually but not always a
* URI. The one attribute that RSS2 can posess is 'ispermalink' which specifies
* whether the guid is itself dereferencable. Use of guid is not obligatory,
* but is advisable. To get the guid you would call $item->id() (for atom
* compatibility) or $item->guid(). To check if this guid is a permalink call
* $item->guid("ispermalink").
*
* @param string $method - the method name being called
* @param array $params - parameters required
* @return string the guid or value of ispermalink
*/
protected function getGuid($method, $params) {
$attribute = (isset($params[0]) and $params[0] == 'ispermalink') ?
true : false;
$tag = $this->model->getElementsByTagName('guid');
if ($tag->length > 0) {
if ($attribute) {
if ($tag->hasAttribute("ispermalink")) {
return $tag->getAttribute("ispermalink");
}
}
return $tag->item(0)->nodeValue;
}
return false;
}
 
/**
* Access details of file enclosures
*
* The RSS2 spec is ambiguous as to whether an enclosure element must be
* unique in a given entry. For now we will assume it needn't, and allow
* for an offset.
*
* @param string $method - the method being called
* @param array $parameters - we expect the first of these to be our offset
* @return array|false
*/
protected function getEnclosure($method, $parameters) {
$encs = $this->model->getElementsByTagName('enclosure');
$offset = isset($parameters[0]) ? $parameters[0] : 0;
if ($encs->length > $offset) {
try {
if (! $encs->item($offset)->hasAttribute('url')) {
return false;
}
$attrs = $encs->item($offset)->attributes;
return array(
'url' => $attrs->getNamedItem('url')->value,
'length' => $attrs->getNamedItem('length')->value,
'type' => $attrs->getNamedItem('type')->value);
} catch (Exception $e) {
return false;
}
}
return false;
}
 
/**
* Get the entry source if specified
*
* source is an optional sub-element of item. Like atom:source it tells
* us about where the entry came from (eg. if it's been copied from another
* feed). It is not a rich source of metadata in the same way as atom:source
* and while it would be good to maintain compatibility by returning an
* XML_Feed_Parser_RSS2 element, it makes a lot more sense to return an array.
*
* @return array|false
*/
protected function getSource() {
$get = $this->model->getElementsByTagName('source');
if ($get->length) {
$source = $get->item(0);
$array = array(
'content' => $source->nodeValue);
foreach ($source->attributes as $attribute) {
$array[$attribute->name] = $attribute->value;
}
return $array;
}
return false;
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss1.php
New file
0,0 → 1,267
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS1 class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS1.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class handles RSS1.0 feeds.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
* @todo Find a Relax NG URI we can use
*/
class XmlFeedParserRss1 extends XmlFeedParserType {
/**
* The URI of the RelaxNG schema used to (optionally) validate the feed
* @var string
*/
protected $relax = 'rss10.rng';
 
/**
* We're likely to use XPath, so let's keep it global
* @var DOMXPath
*/
protected $xpath;
 
/**
* The feed type we are parsing
* @var string
*/
public $version = 'RSS 1.0';
 
/**
* The class used to represent individual items
* @var string
*/
protected $itemClass = 'XmlFeedParserRss1Element';
/**
* The element containing entries
* @var string
*/
protected $itemElement = 'item';
 
/**
* Here we map those elements we're not going to handle individually
* to the constructs they are. The optional second parameter in the array
* tells the parser whether to 'fall back' (not apt. at the feed level) or
* fail if the element is missing. If the parameter is not set, the function
* will simply return false and leave it to the client to decide what to do.
* @var array
*/
protected $map = array(
'title' => array('Text'),
'link' => array('Text'),
'description' => array('Text'),
'image' => array('Image'),
'textinput' => array('TextInput'),
'updatePeriod' => array('Text'),
'updateFrequency' => array('Text'),
'updateBase' => array('Date'),
'rights' => array('Text'), # dc:rights
'description' => array('Text'), # dc:description
'creator' => array('Text'), # dc:creator
'publisher' => array('Text'), # dc:publisher
'contributor' => array('Text'), # dc:contributor
'date' => array('Date') # dc:contributor
);
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS2.
* @var array
*/
protected $compatMap = array(
'title' => array('title'),
'link' => array('link'),
'subtitle' => array('description'),
'author' => array('creator'),
'updated' => array('date'));
 
/**
* We will be working with multiple namespaces and it is useful to
* keep them together
* @var array
*/
protected $namespaces = array(
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'rss' => 'http://purl.org/rss/1.0/',
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
'content' => 'http://purl.org/rss/1.0/modules/content/',
'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/');
 
/**
* Our constructor does nothing more than its parent.
*
* @param DOMDocument $xml A DOM object representing the feed
* @param bool (optional) $string Whether or not to validate this feed
*/
function __construct(DOMDocument $model, $strict = false) {
$this->model = $model;
if ($strict) {
if (! $this->relaxNGValidate()) {
throw new XML_Feed_Parser_Exception('Failed required validation');
}
}
 
$this->xpath = new DOMXPath($model);
foreach ($this->namespaces as $key => $value) {
$this->xpath->registerNamespace($key, $value);
}
$this->numberEntries = $this->count('item');
}
 
/**
* Allows retrieval of an entry by ID where the rdf:about attribute is used
*
* This is not really something that will work with RSS1 as it does not have
* clear restrictions on the global uniqueness of IDs. We will employ the
* _very_ hit and miss method of selecting entries based on the rdf:about
* attribute. If DOMXPath::evaluate is available, we also use that to store
* a reference to the entry in the array used by getEntryByOffset so that
* method does not have to seek out the entry if it's requested that way.
*
* @param string $id any valid ID.
* @return XML_Feed_Parser_RSS1Element
*/
function getEntryById($id) {
if (isset($this->idMappings[$id])) {
return $this->entries[$this->idMappings[$id]];
}
 
$entries = $this->xpath->query("//rss:item[@rdf:about='$id']");
if ($entries->length > 0) {
$classname = $this->itemClass;
$entry = new $classname($entries->item(0), $this);
if (in_array('evaluate', get_class_methods($this->xpath))) {
$offset = $this->xpath->evaluate("count(preceding-sibling::rss:item)", $entries->item(0));
$this->entries[$offset] = $entry;
}
$this->idMappings[$id] = $entry;
return $entry;
}
return false;
}
 
/**
* Get details of the image associated with the feed.
*
* @return array|false an array simply containing the child elements
*/
protected function getImage() {
$images = $this->model->getElementsByTagName('image');
if ($images->length > 0) {
$image = $images->item(0);
$details = array();
if ($image->hasChildNodes()) {
$details = array(
'title' => $image->getElementsByTagName('title')->item(0)->value,
'link' => $image->getElementsByTagName('link')->item(0)->value,
'url' => $image->getElementsByTagName('url')->item(0)->value);
} else {
$details = array('title' => false,
'link' => false,
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
}
$details = array_merge($details, array('description' => false, 'height' => false, 'width' => false));
if (! empty($details)) {
return $details;
}
}
return false;
}
 
/**
* The textinput element is little used, but in the interests of
* completeness we will support it.
*
* @return array|false
*/
protected function getTextInput() {
$inputs = $this->model->getElementsByTagName('textinput');
if ($inputs->length > 0) {
$input = $inputs->item(0);
$results = array();
$results['title'] = isset(
$input->getElementsByTagName('title')->item(0)->value) ?
$input->getElementsByTagName('title')->item(0)->value : null;
$results['description'] = isset(
$input->getElementsByTagName('description')->item(0)->value) ?
$input->getElementsByTagName('description')->item(0)->value : null;
$results['name'] = isset(
$input->getElementsByTagName('name')->item(0)->value) ?
$input->getElementsByTagName('name')->item(0)->value : null;
$results['link'] = isset(
$input->getElementsByTagName('link')->item(0)->value) ?
$input->getElementsByTagName('link')->item(0)->value : null;
if (empty($results['link']) and
$input->attributes->getNamedItem('resource')) {
$results['link'] =
$input->attributes->getNamedItem('resource')->nodeValue;
}
if (! empty($results)) {
return $results;
}
}
return false;
}
 
/**
* Employs various techniques to identify the author
*
* Dublin Core provides the dc:creator, dc:contributor, and dc:publisher
* elements for defining authorship in RSS1. We will try each of those in
* turn in order to simulate the atom author element and will return it
* as text.
*
* @return array|false
*/
function getAuthor() {
$options = array('creator', 'contributor', 'publisher');
foreach ($options as $element) {
$test = $this->model->getElementsByTagName($element);
if ($test->length > 0) {
return $test->item(0)->value;
}
}
return false;
}
/**
* Retrieve a link
*
* In RSS1 a link is a text element but in order to ensure that we resolve
* URLs properly we have a special function for them.
*
* @return string
*/
function getLink($offset = 0, $attribute = 'href', $params = false) {
$links = $this->model->getElementsByTagName('link');
if ($links->length <= $offset) {
return false;
}
$link = $links->item($offset);
return $this->addBase($link->nodeValue, $link);
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss11.php
New file
0,0 → 1,266
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS1.1 class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS11.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class handles RSS1.1 feeds. RSS1.1 is documented at:
* http://inamidst.com/rss1.1/
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
* @todo Support for RDF:List
* @todo Ensure xml:lang is accessible to users
*/
class XmlFeedParserRss11 extends XmlFeedParserType {
/**
* The URI of the RelaxNG schema used to (optionally) validate the feed
* @var string
*/
protected $relax = 'rss11.rng';
 
/**
* We're likely to use XPath, so let's keep it global
* @var DOMXPath
*/
protected $xpath;
 
/**
* The feed type we are parsing
* @var string
*/
public $version = 'RSS 1.0';
 
/**
* The class used to represent individual items
* @var string
*/
protected $itemClass = 'XmlFeedParserRss11Element';
/**
* The element containing entries
* @var string
*/
protected $itemElement = 'item';
 
/**
* Here we map those elements we're not going to handle individually
* to the constructs they are. The optional second parameter in the array
* tells the parser whether to 'fall back' (not apt. at the feed level) or
* fail if the element is missing. If the parameter is not set, the function
* will simply return false and leave it to the client to decide what to do.
* @var array
*/
protected $map = array(
'title' => array('Text'),
'link' => array('Text'),
'description' => array('Text'),
'image' => array('Image'),
'updatePeriod' => array('Text'),
'updateFrequency' => array('Text'),
'updateBase' => array('Date'),
'rights' => array('Text'), # dc:rights
'description' => array('Text'), # dc:description
'creator' => array('Text'), # dc:creator
'publisher' => array('Text'), # dc:publisher
'contributor' => array('Text'), # dc:contributor
'date' => array('Date') # dc:contributor
);
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS2.
* @var array
*/
protected $compatMap = array(
'title' => array('title'),
'link' => array('link'),
'subtitle' => array('description'),
'author' => array('creator'),
'updated' => array('date'));
 
/**
* We will be working with multiple namespaces and it is useful to
* keep them together. We will retain support for some common RSS1.0 modules
* @var array
*/
protected $namespaces = array(
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'rss' => 'http://purl.org/net/rss1.1#',
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
'content' => 'http://purl.org/rss/1.0/modules/content/',
'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/');
 
/**
* Our constructor does nothing more than its parent.
*
* @param DOMDocument $xml A DOM object representing the feed
* @param bool (optional) $string Whether or not to validate this feed
*/
function __construct(DOMDocument $model, $strict = false) {
$this->model = $model;
 
if ($strict) {
if (! $this->relaxNGValidate()) {
throw new XML_Feed_Parser_Exception('Failed required validation');
}
}
 
$this->xpath = new DOMXPath($model);
foreach ($this->namespaces as $key => $value) {
$this->xpath->registerNamespace($key, $value);
}
$this->numberEntries = $this->count('item');
}
 
/**
* Attempts to identify an element by ID given by the rdf:about attribute
*
* This is not really something that will work with RSS1.1 as it does not have
* clear restrictions on the global uniqueness of IDs. We will employ the
* _very_ hit and miss method of selecting entries based on the rdf:about
* attribute. Please note that this is even more hit and miss with RSS1.1 than
* with RSS1.0 since RSS1.1 does not require the rdf:about attribute for items.
*
* @param string $id any valid ID.
* @return XML_Feed_Parser_RSS1Element
*/
function getEntryById($id) {
if (isset($this->idMappings[$id])) {
return $this->entries[$this->idMappings[$id]];
}
 
$entries = $this->xpath->query("//rss:item[@rdf:about='$id']");
if ($entries->length > 0) {
$classname = $this->itemClass;
$entry = new $classname($entries->item(0), $this);
return $entry;
}
return false;
}
 
/**
* Get details of the image associated with the feed.
*
* @return array|false an array simply containing the child elements
*/
protected function getImage() {
$images = $this->model->getElementsByTagName('image');
if ($images->length > 0) {
$image = $images->item(0);
$details = array();
if ($image->hasChildNodes()) {
$details = array(
'title' => $image->getElementsByTagName('title')->item(0)->value,
'url' => $image->getElementsByTagName('url')->item(0)->value);
if ($image->getElementsByTagName('link')->length > 0) {
$details['link'] =
$image->getElementsByTagName('link')->item(0)->value;
}
} else {
$details = array('title' => false,
'link' => false,
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
}
$details = array_merge($details,
array('description' => false, 'height' => false, 'width' => false));
if (! empty($details)) {
return $details;
}
}
return false;
}
 
/**
* The textinput element is little used, but in the interests of
* completeness we will support it.
*
* @return array|false
*/
protected function getTextInput() {
$inputs = $this->model->getElementsByTagName('textinput');
if ($inputs->length > 0) {
$input = $inputs->item(0);
$results = array();
$results['title'] = isset(
$input->getElementsByTagName('title')->item(0)->value) ?
$input->getElementsByTagName('title')->item(0)->value : null;
$results['description'] = isset(
$input->getElementsByTagName('description')->item(0)->value) ?
$input->getElementsByTagName('description')->item(0)->value : null;
$results['name'] = isset(
$input->getElementsByTagName('name')->item(0)->value) ?
$input->getElementsByTagName('name')->item(0)->value : null;
$results['link'] = isset(
$input->getElementsByTagName('link')->item(0)->value) ?
$input->getElementsByTagName('link')->item(0)->value : null;
if (empty($results['link']) and
$input->attributes->getNamedItem('resource')) {
$results['link'] = $input->attributes->getNamedItem('resource')->nodeValue;
}
if (! empty($results)) {
return $results;
}
}
return false;
}
 
/**
* Attempts to discern authorship
*
* Dublin Core provides the dc:creator, dc:contributor, and dc:publisher
* elements for defining authorship in RSS1. We will try each of those in
* turn in order to simulate the atom author element and will return it
* as text.
*
* @return array|false
*/
function getAuthor() {
$options = array('creator', 'contributor', 'publisher');
foreach ($options as $element) {
$test = $this->model->getElementsByTagName($element);
if ($test->length > 0) {
return $test->item(0)->value;
}
}
return false;
}
/**
* Retrieve a link
*
* In RSS1 a link is a text element but in order to ensure that we resolve
* URLs properly we have a special function for them.
*
* @return string
*/
function getLink($offset = 0, $attribute = 'href', $params = false) {
$links = $this->model->getElementsByTagName('link');
if ($links->length <= $offset) {
return false;
}
$link = $links->item($offset);
return $this->addBase($link->nodeValue, $link);
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss2.php
New file
0,0 → 1,323
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Class representing feed-level data for an RSS2 feed
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS2.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class handles RSS2 feeds.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserRss2 extends XmlFeedParserType {
/**
* The URI of the RelaxNG schema used to (optionally) validate the feed
* @var string
*/
protected $relax = 'rss20.rng';
 
/**
* We're likely to use XPath, so let's keep it global
* @var DOMXPath
*/
protected $xpath;
 
/**
* The feed type we are parsing
* @var string
*/
public $version = 'RSS 2.0';
 
/**
* The class used to represent individual items
* @var string
*/
protected $itemClass = 'XmlFeedParserRss2Element';
/**
* The element containing entries
* @var string
*/
protected $itemElement = 'item';
 
/**
* Here we map those elements we're not going to handle individually
* to the constructs they are. The optional second parameter in the array
* tells the parser whether to 'fall back' (not apt. at the feed level) or
* fail if the element is missing. If the parameter is not set, the function
* will simply return false and leave it to the client to decide what to do.
* @var array
*/
protected $map = array(
'ttl' => array('Text'),
'pubDate' => array('Date'),
'lastBuildDate' => array('Date'),
'title' => array('Text'),
'link' => array('Link'),
'description' => array('Text'),
'language' => array('Text'),
'copyright' => array('Text'),
'managingEditor' => array('Text'),
'webMaster' => array('Text'),
'category' => array('Text'),
'generator' => array('Text'),
'docs' => array('Text'),
'ttl' => array('Text'),
'image' => array('Image'),
'skipDays' => array('skipDays'),
'skipHours' => array('skipHours'));
 
/**
* Here we map some elements to their atom equivalents. This is going to be
* quite tricky to pull off effectively (and some users' methods may vary)
* but is worth trying. The key is the atom version, the value is RSS2.
* @var array
*/
protected $compatMap = array(
'title' => array('title'),
'rights' => array('copyright'),
'updated' => array('lastBuildDate'),
'subtitle' => array('description'),
'date' => array('pubDate'),
'author' => array('managingEditor'));
 
protected $namespaces = array(
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
'content' => 'http://purl.org/rss/1.0/modules/content/');
 
/**
* Our constructor does nothing more than its parent.
*
* @param DOMDocument $xml A DOM object representing the feed
* @param bool (optional) $string Whether or not to validate this feed
*/
function __construct(DOMDocument $model, $strict = false) {
$this->model = $model;
 
if ($strict) {
if (! $this->relaxNGValidate()) {
throw new XmlFeedParserException('Failed required validation');
}
}
 
$this->xpath = new DOMXPath($this->model);
foreach ($this->namespaces as $key => $value) {
$this->xpath->registerNamespace($key, $value);
}
$this->numberEntries = $this->count('item');
}
 
/**
* Retrieves an entry by ID, if the ID is specified with the guid element
*
* This is not really something that will work with RSS2 as it does not have
* clear restrictions on the global uniqueness of IDs. But we can emulate
* it by allowing access based on the 'guid' element. If DOMXPath::evaluate
* is available, we also use that to store a reference to the entry in the array
* used by getEntryByOffset so that method does not have to seek out the entry
* if it's requested that way.
*
* @param string $id any valid ID.
* @return XML_Feed_Parser_RSS2Element
*/
function getEntryById($id) {
if (isset($this->idMappings[$id])) {
return $this->entries[$this->idMappings[$id]];
}
 
$entries = $this->xpath->query("//item[guid='$id']");
if ($entries->length > 0) {
$entry = new $this->itemElement($entries->item(0), $this);
if (in_array('evaluate', get_class_methods($this->xpath))) {
$offset = $this->xpath->evaluate("count(preceding-sibling::item)", $entries->item(0));
$this->entries[$offset] = $entry;
}
$this->idMappings[$id] = $entry;
return $entry;
}
}
 
/**
* Get a category from the element
*
* The category element is a simple text construct which can occur any number
* of times. We allow access by offset or access to an array of results.
*
* @param string $call for compatibility with our overloading
* @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array
* @return string|array|false
*/
function getCategory($call, $arguments = array()) {
$categories = $this->model->getElementsByTagName('category');
$offset = empty($arguments[0]) ? 0 : $arguments[0];
$array = empty($arguments[1]) ? false : true;
if ($categories->length <= $offset) {
return false;
}
if ($array) {
$list = array();
foreach ($categories as $category) {
array_push($list, $category->nodeValue);
}
return $list;
}
return $categories->item($offset)->nodeValue;
}
 
/**
* Get details of the image associated with the feed.
*
* @return array|false an array simply containing the child elements
*/
protected function getImage() {
$images = $this->xpath->query("//image");
if ($images->length > 0) {
$image = $images->item(0);
$desc = $image->getElementsByTagName('description');
$description = $desc->length ? $desc->item(0)->nodeValue : false;
$heigh = $image->getElementsByTagName('height');
$height = $heigh->length ? $heigh->item(0)->nodeValue : false;
$widt = $image->getElementsByTagName('width');
$width = $widt->length ? $widt->item(0)->nodeValue : false;
return array(
'title' => $image->getElementsByTagName('title')->item(0)->nodeValue,
'link' => $image->getElementsByTagName('link')->item(0)->nodeValue,
'url' => $image->getElementsByTagName('url')->item(0)->nodeValue,
'description' => $description,
'height' => $height,
'width' => $width);
}
return false;
}
 
/**
* The textinput element is little used, but in the interests of
* completeness...
*
* @return array|false
*/
function getTextInput() {
$inputs = $this->model->getElementsByTagName('input');
if ($inputs->length > 0) {
$input = $inputs->item(0);
return array(
'title' => $input->getElementsByTagName('title')->item(0)->value,
'description' =>
$input->getElementsByTagName('description')->item(0)->value,
'name' => $input->getElementsByTagName('name')->item(0)->value,
'link' => $input->getElementsByTagName('link')->item(0)->value);
}
return false;
}
 
/**
* Utility function for getSkipDays and getSkipHours
*
* This is a general function used by both getSkipDays and getSkipHours. It simply
* returns an array of the values of the children of the appropriate tag.
*
* @param string $tagName The tag name (getSkipDays or getSkipHours)
* @return array|false
*/
protected function getSkips($tagName) {
$hours = $this->model->getElementsByTagName($tagName);
if ($hours->length == 0) {
return false;
}
$skipHours = array();
foreach($hours->item(0)->childNodes as $hour) {
if ($hour instanceof DOMElement) {
array_push($skipHours, $hour->nodeValue);
}
}
return $skipHours;
}
 
/**
* Retrieve skipHours data
*
* The skiphours element provides a list of hours on which this feed should
* not be checked. We return an array of those hours (integers, 24 hour clock)
*
* @return array
*/
function getSkipHours() {
return $this->getSkips('skipHours');
}
 
/**
* Retrieve skipDays data
*
* The skipdays element provides a list of days on which this feed should
* not be checked. We return an array of those days.
*
* @return array
*/
function getSkipDays() {
return $this->getSkips('skipDays');
}
 
/**
* Return content of the little-used 'cloud' element
*
* The cloud element is rarely used. It is designed to provide some details
* of a location to update the feed.
*
* @return array an array of the attributes of the element
*/
function getCloud() {
$cloud = $this->model->getElementsByTagName('cloud');
if ($cloud->length == 0) {
return false;
}
$cloudData = array();
foreach ($cloud->item(0)->attributes as $attribute) {
$cloudData[$attribute->name] = $attribute->value;
}
return $cloudData;
}
/**
* Get link URL
*
* In RSS2 a link is a text element but in order to ensure that we resolve
* URLs properly we have a special function for them. We maintain the
* parameter used by the atom getLink method, though we only use the offset
* parameter.
*
* @param int $offset The position of the link within the feed. Starts from 0
* @param string $attribute The attribute of the link element required
* @param array $params An array of other parameters. Not used.
* @return string
*/
function getLink($offset, $attribute = 'href', $params = array()) {
$links = $this->model->getElementsByTagName('link');
 
if ($links->length <= $offset) {
return false;
}
$link = $links->item($offset);
return $this->addBase($link->nodeValue, $link);
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserAtomElement.php
New file
0,0 → 1,254
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* AtomElement class for XML_Feed_Parser package
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: AtomElement.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/**
* This class provides support for atom entries. It will usually be called by
* XML_Feed_Parser_Atom with which it shares many methods.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserAtomElement extends XmlFeedParserAtom {
/**
* This will be a reference to the parent object for when we want
* to use a 'fallback' rule
* @var XML_Feed_Parser_Atom
*/
protected $parent;
 
/**
* When performing XPath queries we will use this prefix
* @var string
*/
private $xpathPrefix = '';
/**
* xml:base values inherited by the element
* @var string
*/
protected $xmlBase;
 
/**
* Here we provide a few mappings for those very special circumstances in
* which it makes sense to map back to the RSS2 spec or to manage other
* compatibilities (eg. with the Univeral Feed Parser). Key is the other version's
* name for the command, value is an array consisting of the equivalent in our atom
* api and any attributes needed to make the mapping.
* @var array
*/
protected $compatMap = array(
'guid' => array('id'),
'links' => array('link'),
'tags' => array('category'),
'contributors' => array('contributor'));
/**
* Our specific element map
* @var array
*/
protected $map = array(
'author' => array('Person', 'fallback'),
'contributor' => array('Person'),
'id' => array('Text', 'fail'),
'published' => array('Date'),
'updated' => array('Date', 'fail'),
'title' => array('Text', 'fail'),
'rights' => array('Text', 'fallback'),
'summary' => array('Text'),
'content' => array('Content'),
'link' => array('Link'),
'enclosure' => array('Enclosure'),
'category' => array('Category'));
 
/**
* Store useful information for later.
*
* @param DOMElement $element - this item as a DOM element
* @param XML_Feed_Parser_Atom $parent - the feed of which this is a member
*/
function __construct(DOMElement $element, $parent, $xmlBase = '') {
$this->model = $element;
$this->parent = $parent;
$this->xmlBase = $xmlBase;
$this->xpathPrefix = "//atom:entry[atom:id='" . $this->id . "']/";
$this->xpath = $this->parent->xpath;
}
 
/**
* Provides access to specific aspects of the author data for an atom entry
*
* Author data at the entry level is more complex than at the feed level.
* If atom:author is not present for the entry we need to look for it in
* an atom:source child of the atom:entry. If it's not there either, then
* we look to the parent for data.
*
* @param array
* @return string
*/
function getAuthor($arguments) {
/* Find out which part of the author data we're looking for */
if (isset($arguments['param'])) {
$parameter = $arguments['param'];
} else {
$parameter = 'name';
}
$test = $this->model->getElementsByTagName('author');
if ($test->length > 0) {
$item = $test->item(0);
return $item->getElementsByTagName($parameter)->item(0)->nodeValue;
}
$source = $this->model->getElementsByTagName('source');
if ($source->length > 0) {
$test = $this->model->getElementsByTagName('author');
if ($test->length > 0) {
$item = $test->item(0);
return $item->getElementsByTagName($parameter)->item(0)->nodeValue;
}
}
return $this->parent->getAuthor($arguments);
}
 
/**
* Returns the content of the content element or info on a specific attribute
*
* This element may or may not be present. It cannot be present more than
* once. It may have a 'src' attribute, in which case there's no content
* If not present, then the entry must have link with rel="alternate".
* If there is content we return it, if not and there's a 'src' attribute
* we return the value of that instead. The method can take an 'attribute'
* argument, in which case we return the value of that attribute if present.
* eg. $item->content("type") will return the type of the content. It is
* recommended that all users check the type before getting the content to
* ensure that their script is capable of handling the type of returned data.
* (data carried in the content element can be either 'text', 'html', 'xhtml',
* or any standard MIME type).
*
* @return string|false
*/
protected function getContent($method, $arguments = array()) {
$attribute = empty($arguments[0]) ? false : $arguments[0];
$tags = $this->model->getElementsByTagName('content');
 
if ($tags->length == 0) {
return false;
}
 
$content = $tags->item(0);
 
if (! $content->hasAttribute('type')) {
$content->setAttribute('type', 'text');
}
if (! empty($attribute)) {
return $content->getAttribute($attribute);
}
 
$type = $content->getAttribute('type');
 
if (! empty($attribute)) {
if ($content->hasAttribute($attribute))
{
return $content->getAttribute($attribute);
}
return false;
}
 
if ($content->hasAttribute('src')) {
return $content->getAttribute('src');
}
 
return $this->parseTextConstruct($content);
}
 
/**
* For compatibility, this method provides a mapping to access enclosures.
*
* The Atom spec doesn't provide for an enclosure element, but it is
* generally supported using the link element with rel='enclosure'.
*
* @param string $method - for compatibility with our __call usage
* @param array $arguments - for compatibility with our __call usage
* @return array|false
*/
function getEnclosure($method, $arguments = array()) {
$offset = isset($arguments[0]) ? $arguments[0] : 0;
$query = "//atom:entry[atom:id='" . $this->getText('id', false) .
"']/atom:link[@rel='enclosure']";
 
$encs = $this->parent->xpath->query($query);
if ($encs->length > $offset) {
try {
if (! $encs->item($offset)->hasAttribute('href')) {
return false;
}
$attrs = $encs->item($offset)->attributes;
$length = $encs->item($offset)->hasAttribute('length') ?
$encs->item($offset)->getAttribute('length') : false;
return array(
'url' => $attrs->getNamedItem('href')->value,
'type' => $attrs->getNamedItem('type')->value,
'length' => $length);
} catch (Exception $e) {
return false;
}
}
return false;
}
/**
* Get details of this entry's source, if available/relevant
*
* Where an atom:entry is taken from another feed then the aggregator
* is supposed to include an atom:source element which replicates at least
* the atom:id, atom:title, and atom:updated metadata from the original
* feed. Atom:source therefore has a very similar structure to atom:feed
* and if we find it we will return it as an XML_Feed_Parser_Atom object.
*
* @return XML_Feed_Parser_Atom|false
*/
function getSource() {
$test = $this->model->getElementsByTagName('source');
if ($test->length == 0) {
return false;
}
$source = new XML_Feed_Parser_Atom($test->item(0));
}
 
/**
* Get the entry as an XML string
*
* Return an XML serialization of the feed, should it be required. Most
* users however, will already have a serialization that they used when
* instantiating the object.
*
* @return string XML serialization of element
*/
function __toString() {
$simple = simplexml_import_dom($this->model);
return $simple->asXML();
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserRss09Element.php
New file
0,0 → 1,59
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* RSS0.9 Element class for XML_Feed_Parser
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
* @version CVS: $Id: RSS09Element.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
 
/*
* This class provides support for RSS 0.9 entries. It will usually be called by
* XML_Feed_Parser_RSS09 with which it shares many methods.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserRss09Element extends XmlFeedParserRss09 {
/**
* This will be a reference to the parent object for when we want
* to use a 'fallback' rule
* @var XML_Feed_Parser_RSS09
*/
protected $parent;
 
/**
* Our specific element map
* @var array
*/
protected $map = array(
'title' => array('Text'),
'link' => array('Link'));
 
/**
* Store useful information for later.
*
* @param DOMElement $element - this item as a DOM element
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
*/
function __construct(DOMElement $element, $parent, $xmlBase = '') {
$this->model = $element;
$this->parent = $parent;
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/bibliotheque/xml_feed_parser/1.0.4/parsers/XmlFeedParserException.php
New file
0,0 → 1,36
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Keeps the exception class for XML_Feed_Parser.
*
* PHP versions 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category XML
* @package XML_Feed_Parser
* @author James Stewart <james@jystewart.net>
* @copyright 2005 James Stewart <james@jystewart.net>
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
* @version CVS: $Id: Exception.php 304308 2010-10-11 12:05:50Z clockwerx $
* @link http://pear.php.net/package/XML_Feed_Parser/
*/
/**
* XML_Feed_Parser_Exception is a simple extension of PEAR_Exception, existing
* to help with identification of the source of exceptions.
*
* @author James Stewart <james@jystewart.net>
* @version Release: @package_version@
* @package XML_Feed_Parser
*/
class XmlFeedParserException extends Exception {
 
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/widget/modules/photo/squelettes/contact.tpl.html
New file
0,0 → 1,38
<!-- Squelette du formulaire de contact -->
<div id="tpl-form-contact">
<h2 class="mb-3">Message à <span class="destinataire"><?php echo $donnees['auteur']; ?></span>&nbsp;:</h2>
<form id="form-contact" method="post" action="">
<div id="fc-zone-dialogue" class="mb-3"></div>
<div class="form-group mb-3">
<label for="fc_sujet">Sujet</label>
<input type="text" id="fc_sujet" class="form-control" name="fc_sujet" value="<?php echo $donnees['sujet']; ?>">
</div>
<div class="form-group mb-3">
<label for="fc_message">Message</label>
<textarea id="fc_message" class="form-control form-control-lg" name="fc_message"><?php echo $donnees['message']; ?></textarea>
</div>
<div class="form-group mb-3">
<label for="fc_utilisateur_courriel" title="Utilisez le courriel avec lequel vous êtes inscrit à Tela Botanica">Votre courriel</label>
<input type="email" id="fc_utilisateur_courriel" class="form-control" name="fc_utilisateur_courriel" placeholder="mail@exemple.com">
</div>
<div class="form-group">
<input type="hidden" id="fc_destinataire_id" name="fc_destinataire_id" value="<?php echo $donnees['id_image']; ?>">
<input type="hidden" name="fc_type_envoi" id="fc_type_envoi" value="non-inscrit">
<input type="submit" id="fc_envoyer" class="btn btn-success form-control" value="Envoyer">
<input type="reset" id="fc_effacer" class="btn btn-warning form-control" value="Effacer">
<?php if( isset( $donnees['popup_url'] ) ): ?>
<a id="fc_annuler" class="popup_url btn btn-danger form-control annuler" data-popup_url="<?php echo $donnees['popup_url'].'&popup_url='.urlencode($donnees['popup_url']); ?>">Annuler</a>
<?php else : ?>
<button id="fc_annuler" type="button" class="close btn btn-danger form-control annuler" data-dismiss="modal" aria-label="Close">Annuler</button>
<?php endif; ?>
</div>
</form>
</div>
<script type="text/Javascript">
//<![CDATA[
$( document ).ready( function() {
contact = new WidgetPhotoContact();
contact.init();
});
//]]>
</script>
/branches/v3.01-serpe/widget/modules/photo/squelettes/js/WidgetPhotoCommun.js
New file
0,0 → 1,108
function WidgetPhotoCommun() {}
 
WidgetPhotoCommun.prototype.init = function() {
this.initTpl();
this.initEvts();
};
 
WidgetPhotoCommun.prototype.chargerContenuModale = function( url ) {
const lthis = this;
$.ajax({
url: url,
success: function( squelette ) {
lthis.activerModale( squelette );
},
error: function() {
lthis.activerModale( 'Le contenu n\'a pas pu être chargé' );
}
});
};
 
// Activation/Desactivation et contenu de la modale Bootstrap
// https://getbootstrap.com/docs/3.3/javascript/#modals
WidgetPhotoCommun.prototype.activerModale = function( content ) {
if ( '' !== content ) {
$( '#print_content' ).html( content );
}
// Sortie avec la touche escape (ne fonctionne pas toujours)
$( '#fenetre-modal' ).modal({ keyboard : true });
 
// Affichage
$( '#fenetre-modal' ).modal({ show: true });
// Remplacer l'autofocus qui ne fonctionne plus en HTML5
// Message dans la doc de bootstrap :
// Due to how HTML5 defines its semantics,
// the autofocus HTML attribute has no effect in Bootstrap modals.
// To achieve the same effect, use some custom JavaScript
$( '#fenetre-modal' ).on( 'shown.bs.modal' , function () {
$( '#print_content' ).trigger( 'focus' );
});
// Réinitialisation
$( '#fenetre-modal' ).on( 'hidden.bs.modal' , function () {
$( '#print_content' ).empty();
});
};
 
/**
* Permet à la fois de vérifier qu'une valeur ou objet existe et n'est pas vide
* et de comparer à une autre valeur :
* Vérifie qu'une variable ou objet n'est pas : vide, null, undefined, NaN
* Si comparer est défini on le compare à valeur en fonction de sensComparaison
* Un booléen est une variable valide : on retourne true
* @param { string || number || object || undefined } valeur
* @param { boolean } sensComparaison : true = rechercher, false = refuser
* @param { string || number || object || undefined || boolean } comparer :valeur à comparer
* @returns {boolean}
*/
WidgetPhotoCommun.prototype.valOk = function (valeur, sensComparaison = true, comparer = undefined ) {
var retour = true;
if ( 'boolean' !== typeof valeur ) {
switch( typeof valeur ) {
case 'string' :
retour = ( '' !== valeur );
break;
case 'number' :
retour = ( !isNaN(valeur) );
break;
case 'object' :
retour = ( null !== valeur && undefined !== valeur && !$.isEmptyObject( valeur ) );
if ( null !== valeur && undefined !== valeur.length ) {
retour = ( retour && 0 < valeur.length );
}
break;
case 'undefined' :
default :
retour = false;
}
if ( retour && comparer !== undefined ) {
var resultComparaison = ( comparer === valeur );
retour = ( sensComparaison ) ? resultComparaison : !resultComparaison ;
}
 
return retour;
 
} else {
// Un booléen est une valeur valable
return true;
}
};
 
WidgetPhotoCommun.prototype.chaineValableAttributsHtml = function( chaine ) {
chaine = chaine.latinise();
return chaine.replace(/[^a-z0-9_\s]/gi, '').replace(/[_\s]/g, '_');
}
 
 
// see : http://semplicewebsites.com/removing-accents-javascript
var Latinise = {};
 
Latinise.latin_map = {"Á":"A","Ă":"A","Ắ":"A","Ặ":"A","Ằ":"A","Ẳ":"A","Ẵ":"A","Ǎ":"A","Â":"A","Ấ":"A","Ậ":"A","Ầ":"A","Ẩ":"A","Ẫ":"A","Ä":"A","Ǟ":"A","Ȧ":"A","Ǡ":"A","Ạ":"A","Ȁ":"A","À":"A","Ả":"A","Ȃ":"A","Ā":"A","Ą":"A","Å":"A","Ǻ":"A","Ḁ":"A","Ⱥ":"A","Ã":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ḃ":"B","Ḅ":"B","Ɓ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ć":"C","Č":"C","Ç":"C","Ḉ":"C","Ĉ":"C","Ċ":"C","Ƈ":"C","Ȼ":"C","Ď":"D","Ḑ":"D","Ḓ":"D","Ḋ":"D","Ḍ":"D","Ɗ":"D","Ḏ":"D","Dz":"D","Dž":"D","Đ":"D","Ƌ":"D","DZ":"DZ","DŽ":"DZ","É":"E","Ĕ":"E","Ě":"E","Ȩ":"E","Ḝ":"E","Ê":"E","Ế":"E","Ệ":"E","Ề":"E","Ể":"E","Ễ":"E","Ḙ":"E","Ë":"E","Ė":"E","Ẹ":"E","Ȅ":"E","È":"E","Ẻ":"E","Ȇ":"E","Ē":"E","Ḗ":"E","Ḕ":"E","Ę":"E","Ɇ":"E","Ẽ":"E","Ḛ":"E","Ꝫ":"ET","Ḟ":"F","Ƒ":"F","Ǵ":"G","Ğ":"G","Ǧ":"G","Ģ":"G","Ĝ":"G","Ġ":"G","Ɠ":"G","Ḡ":"G","Ǥ":"G","Ḫ":"H","Ȟ":"H","Ḩ":"H","Ĥ":"H","Ⱨ":"H","Ḧ":"H","Ḣ":"H","Ḥ":"H","Ħ":"H","Í":"I","Ĭ":"I","Ǐ":"I","Î":"I","Ï":"I","Ḯ":"I","İ":"I","Ị":"I","Ȉ":"I","Ì":"I","Ỉ":"I","Ȋ":"I","Ī":"I","Į":"I","Ɨ":"I","Ĩ":"I","Ḭ":"I","Ꝺ":"D","Ꝼ":"F","Ᵹ":"G","Ꞃ":"R","Ꞅ":"S","Ꞇ":"T","Ꝭ":"IS","Ĵ":"J","Ɉ":"J","Ḱ":"K","Ǩ":"K","Ķ":"K","Ⱪ":"K","Ꝃ":"K","Ḳ":"K","Ƙ":"K","Ḵ":"K","Ꝁ":"K","Ꝅ":"K","Ĺ":"L","Ƚ":"L","Ľ":"L","Ļ":"L","Ḽ":"L","Ḷ":"L","Ḹ":"L","Ⱡ":"L","Ꝉ":"L","Ḻ":"L","Ŀ":"L","Ɫ":"L","Lj":"L","Ł":"L","LJ":"LJ","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ń":"N","Ň":"N","Ņ":"N","Ṋ":"N","Ṅ":"N","Ṇ":"N","Ǹ":"N","Ɲ":"N","Ṉ":"N","Ƞ":"N","Nj":"N","Ñ":"N","NJ":"NJ","Ó":"O","Ŏ":"O","Ǒ":"O","Ô":"O","Ố":"O","Ộ":"O","Ồ":"O","Ổ":"O","Ỗ":"O","Ö":"O","Ȫ":"O","Ȯ":"O","Ȱ":"O","Ọ":"O","Ő":"O","Ȍ":"O","Ò":"O","Ỏ":"O","Ơ":"O","Ớ":"O","Ợ":"O","Ờ":"O","Ở":"O","Ỡ":"O","Ȏ":"O","Ꝋ":"O","Ꝍ":"O","Ō":"O","Ṓ":"O","Ṑ":"O","Ɵ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Õ":"O","Ṍ":"O","Ṏ":"O","Ȭ":"O","Ƣ":"OI","Ꝏ":"OO","Ɛ":"E","Ɔ":"O","Ȣ":"OU","Ṕ":"P","Ṗ":"P","Ꝓ":"P","Ƥ":"P","Ꝕ":"P","Ᵽ":"P","Ꝑ":"P","Ꝙ":"Q","Ꝗ":"Q","Ŕ":"R","Ř":"R","Ŗ":"R","Ṙ":"R","Ṛ":"R","Ṝ":"R","Ȑ":"R","Ȓ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꜿ":"C","Ǝ":"E","Ś":"S","Ṥ":"S","Š":"S","Ṧ":"S","Ş":"S","Ŝ":"S","Ș":"S","Ṡ":"S","Ṣ":"S","Ṩ":"S","Ť":"T","Ţ":"T","Ṱ":"T","Ț":"T","Ⱦ":"T","Ṫ":"T","Ṭ":"T","Ƭ":"T","Ṯ":"T","Ʈ":"T","Ŧ":"T","Ɐ":"A","Ꞁ":"L","Ɯ":"M","Ʌ":"V","Ꜩ":"TZ","Ú":"U","Ŭ":"U","Ǔ":"U","Û":"U","Ṷ":"U","Ü":"U","Ǘ":"U","Ǚ":"U","Ǜ":"U","Ǖ":"U","Ṳ":"U","Ụ":"U","Ű":"U","Ȕ":"U","Ù":"U","Ủ":"U","Ư":"U","Ứ":"U","Ự":"U","Ừ":"U","Ử":"U","Ữ":"U","Ȗ":"U","Ū":"U","Ṻ":"U","Ų":"U","Ů":"U","Ũ":"U","Ṹ":"U","Ṵ":"U","Ꝟ":"V","Ṿ":"V","Ʋ":"V","Ṽ":"V","Ꝡ":"VY","Ẃ":"W","Ŵ":"W","Ẅ":"W","Ẇ":"W","Ẉ":"W","Ẁ":"W","Ⱳ":"W","Ẍ":"X","Ẋ":"X","Ý":"Y","Ŷ":"Y","Ÿ":"Y","Ẏ":"Y","Ỵ":"Y","Ỳ":"Y","Ƴ":"Y","Ỷ":"Y","Ỿ":"Y","Ȳ":"Y","Ɏ":"Y","Ỹ":"Y","Ź":"Z","Ž":"Z","Ẑ":"Z","Ⱬ":"Z","Ż":"Z","Ẓ":"Z","Ȥ":"Z","Ẕ":"Z","Ƶ":"Z","IJ":"IJ","Œ":"OE","ᴀ":"A","ᴁ":"AE","ʙ":"B","ᴃ":"B","ᴄ":"C","ᴅ":"D","ᴇ":"E","ꜰ":"F","ɢ":"G","ʛ":"G","ʜ":"H","ɪ":"I","ʁ":"R","ᴊ":"J","ᴋ":"K","ʟ":"L","ᴌ":"L","ᴍ":"M","ɴ":"N","ᴏ":"O","ɶ":"OE","ᴐ":"O","ᴕ":"OU","ᴘ":"P","ʀ":"R","ᴎ":"N","ᴙ":"R","ꜱ":"S","ᴛ":"T","ⱻ":"E","ᴚ":"R","ᴜ":"U","ᴠ":"V","ᴡ":"W","ʏ":"Y","ᴢ":"Z","á":"a","ă":"a","ắ":"a","ặ":"a","ằ":"a","ẳ":"a","ẵ":"a","ǎ":"a","â":"a","ấ":"a","ậ":"a","ầ":"a","ẩ":"a","ẫ":"a","ä":"a","ǟ":"a","ȧ":"a","ǡ":"a","ạ":"a","ȁ":"a","à":"a","ả":"a","ȃ":"a","ā":"a","ą":"a","ᶏ":"a","ẚ":"a","å":"a","ǻ":"a","ḁ":"a","ⱥ":"a","ã":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ḃ":"b","ḅ":"b","ɓ":"b","ḇ":"b","ᵬ":"b","ᶀ":"b","ƀ":"b","ƃ":"b","ɵ":"o","ć":"c","č":"c","ç":"c","ḉ":"c","ĉ":"c","ɕ":"c","ċ":"c","ƈ":"c","ȼ":"c","ď":"d","ḑ":"d","ḓ":"d","ȡ":"d","ḋ":"d","ḍ":"d","ɗ":"d","ᶑ":"d","ḏ":"d","ᵭ":"d","ᶁ":"d","đ":"d","ɖ":"d","ƌ":"d","ı":"i","ȷ":"j","ɟ":"j","ʄ":"j","dz":"dz","dž":"dz","é":"e","ĕ":"e","ě":"e","ȩ":"e","ḝ":"e","ê":"e","ế":"e","ệ":"e","ề":"e","ể":"e","ễ":"e","ḙ":"e","ë":"e","ė":"e","ẹ":"e","ȅ":"e","è":"e","ẻ":"e","ȇ":"e","ē":"e","ḗ":"e","ḕ":"e","ⱸ":"e","ę":"e","ᶒ":"e","ɇ":"e","ẽ":"e","ḛ":"e","ꝫ":"et","ḟ":"f","ƒ":"f","ᵮ":"f","ᶂ":"f","ǵ":"g","ğ":"g","ǧ":"g","ģ":"g","ĝ":"g","ġ":"g","ɠ":"g","ḡ":"g","ᶃ":"g","ǥ":"g","ḫ":"h","ȟ":"h","ḩ":"h","ĥ":"h","ⱨ":"h","ḧ":"h","ḣ":"h","ḥ":"h","ɦ":"h","ẖ":"h","ħ":"h","ƕ":"hv","í":"i","ĭ":"i","ǐ":"i","î":"i","ï":"i","ḯ":"i","ị":"i","ȉ":"i","ì":"i","ỉ":"i","ȋ":"i","ī":"i","į":"i","ᶖ":"i","ɨ":"i","ĩ":"i","ḭ":"i","ꝺ":"d","ꝼ":"f","ᵹ":"g","ꞃ":"r","ꞅ":"s","ꞇ":"t","ꝭ":"is","ǰ":"j","ĵ":"j","ʝ":"j","ɉ":"j","ḱ":"k","ǩ":"k","ķ":"k","ⱪ":"k","ꝃ":"k","ḳ":"k","ƙ":"k","ḵ":"k","ᶄ":"k","ꝁ":"k","ꝅ":"k","ĺ":"l","ƚ":"l","ɬ":"l","ľ":"l","ļ":"l","ḽ":"l","ȴ":"l","ḷ":"l","ḹ":"l","ⱡ":"l","ꝉ":"l","ḻ":"l","ŀ":"l","ɫ":"l","ᶅ":"l","ɭ":"l","ł":"l","lj":"lj","ſ":"s","ẜ":"s","ẛ":"s","ẝ":"s","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ᵯ":"m","ᶆ":"m","ń":"n","ň":"n","ņ":"n","ṋ":"n","ȵ":"n","ṅ":"n","ṇ":"n","ǹ":"n","ɲ":"n","ṉ":"n","ƞ":"n","ᵰ":"n","ᶇ":"n","ɳ":"n","ñ":"n","nj":"nj","ó":"o","ŏ":"o","ǒ":"o","ô":"o","ố":"o","ộ":"o","ồ":"o","ổ":"o","ỗ":"o","ö":"o","ȫ":"o","ȯ":"o","ȱ":"o","ọ":"o","ő":"o","ȍ":"o","ò":"o","ỏ":"o","ơ":"o","ớ":"o","ợ":"o","ờ":"o","ở":"o","ỡ":"o","ȏ":"o","ꝋ":"o","ꝍ":"o","ⱺ":"o","ō":"o","ṓ":"o","ṑ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","õ":"o","ṍ":"o","ṏ":"o","ȭ":"o","ƣ":"oi","ꝏ":"oo","ɛ":"e","ᶓ":"e","ɔ":"o","ᶗ":"o","ȣ":"ou","ṕ":"p","ṗ":"p","ꝓ":"p","ƥ":"p","ᵱ":"p","ᶈ":"p","ꝕ":"p","ᵽ":"p","ꝑ":"p","ꝙ":"q","ʠ":"q","ɋ":"q","ꝗ":"q","ŕ":"r","ř":"r","ŗ":"r","ṙ":"r","ṛ":"r","ṝ":"r","ȑ":"r","ɾ":"r","ᵳ":"r","ȓ":"r","ṟ":"r","ɼ":"r","ᵲ":"r","ᶉ":"r","ɍ":"r","ɽ":"r","ↄ":"c","ꜿ":"c","ɘ":"e","ɿ":"r","ś":"s","ṥ":"s","š":"s","ṧ":"s","ş":"s","ŝ":"s","ș":"s","ṡ":"s","ṣ":"s","ṩ":"s","ʂ":"s","ᵴ":"s","ᶊ":"s","ȿ":"s","ɡ":"g","ᴑ":"o","ᴓ":"o","ᴝ":"u","ť":"t","ţ":"t","ṱ":"t","ț":"t","ȶ":"t","ẗ":"t","ⱦ":"t","ṫ":"t","ṭ":"t","ƭ":"t","ṯ":"t","ᵵ":"t","ƫ":"t","ʈ":"t","ŧ":"t","ᵺ":"th","ɐ":"a","ᴂ":"ae","ǝ":"e","ᵷ":"g","ɥ":"h","ʮ":"h","ʯ":"h","ᴉ":"i","ʞ":"k","ꞁ":"l","ɯ":"m","ɰ":"m","ᴔ":"oe","ɹ":"r","ɻ":"r","ɺ":"r","ⱹ":"r","ʇ":"t","ʌ":"v","ʍ":"w","ʎ":"y","ꜩ":"tz","ú":"u","ŭ":"u","ǔ":"u","û":"u","ṷ":"u","ü":"u","ǘ":"u","ǚ":"u","ǜ":"u","ǖ":"u","ṳ":"u","ụ":"u","ű":"u","ȕ":"u","ù":"u","ủ":"u","ư":"u","ứ":"u","ự":"u","ừ":"u","ử":"u","ữ":"u","ȗ":"u","ū":"u","ṻ":"u","ų":"u","ᶙ":"u","ů":"u","ũ":"u","ṹ":"u","ṵ":"u","ᵫ":"ue","ꝸ":"um","ⱴ":"v","ꝟ":"v","ṿ":"v","ʋ":"v","ᶌ":"v","ⱱ":"v","ṽ":"v","ꝡ":"vy","ẃ":"w","ŵ":"w","ẅ":"w","ẇ":"w","ẉ":"w","ẁ":"w","ⱳ":"w","ẘ":"w","ẍ":"x","ẋ":"x","ᶍ":"x","ý":"y","ŷ":"y","ÿ":"y","ẏ":"y","ỵ":"y","ỳ":"y","ƴ":"y","ỷ":"y","ỿ":"y","ȳ":"y","ẙ":"y","ɏ":"y","ỹ":"y","ź":"z","ž":"z","ẑ":"z","ʑ":"z","ⱬ":"z","ż":"z","ẓ":"z","ȥ":"z","ẕ":"z","ᵶ":"z","ᶎ":"z","ʐ":"z","ƶ":"z","ɀ":"z","ff":"ff","ffi":"ffi","ffl":"ffl","fi":"fi","fl":"fl","ij":"ij","œ":"oe","st":"st","ₐ":"a","ₑ":"e","ᵢ":"i","ⱼ":"j","ₒ":"o","ᵣ":"r","ᵤ":"u","ᵥ":"v","ₓ":"x"};
 
String.prototype.latinise = function() {
return this.replace(
/[^A-Za-z0-9\[\] ]/g,
function( a ) {
return Latinise.latin_map[a]||a
}
)
};
/branches/v3.01-serpe/widget/modules/photo/squelettes/js/masonry.pkgd.js
New file
0,0 → 1,2504
/*!
* Masonry PACKAGED v4.2.2
* Cascading grid layout library
* https://masonry.desandro.com
* MIT License
* by David DeSandro
*/
 
/**
* Bridget makes jQuery widgets
* v2.0.1
* MIT license
*/
 
/* jshint browser: true, strict: true, undef: true, unused: true */
 
( function( window, factory ) {
// universal module definition
/*jshint strict: false */ /* globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
// AMD
define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
return factory( window, jQuery );
});
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
window,
require('jquery')
);
} else {
// browser global
window.jQueryBridget = factory(
window,
window.jQuery
);
}
 
}( window, function factory( window, jQuery ) {
'use strict';
 
// ----- utils ----- //
 
var arraySlice = Array.prototype.slice;
 
// helper function for logging errors
// $.error breaks jQuery chaining
var console = window.console;
var logError = typeof console == 'undefined' ? function() {} :
function( message ) {
console.error( message );
};
 
// ----- jQueryBridget ----- //
 
function jQueryBridget( namespace, PluginClass, $ ) {
$ = $ || jQuery || window.jQuery;
if ( !$ ) {
return;
}
 
// add option method -> $().plugin('option', {...})
if ( !PluginClass.prototype.option ) {
// option setter
PluginClass.prototype.option = function( opts ) {
// bail out if not an object
if ( !$.isPlainObject( opts ) ){
return;
}
this.options = $.extend( true, this.options, opts );
};
}
 
// make jQuery plugin
$.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
if ( typeof arg0 == 'string' ) {
// method call $().plugin( 'methodName', { options } )
// shift arguments by 1
var args = arraySlice.call( arguments, 1 );
return methodCall( this, arg0, args );
}
// just $().plugin({ options })
plainCall( this, arg0 );
return this;
};
 
// $().plugin('methodName')
function methodCall( $elems, methodName, args ) {
var returnValue;
var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
 
$elems.each( function( i, elem ) {
// get instance
var instance = $.data( elem, namespace );
if ( !instance ) {
logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
pluginMethodStr );
return;
}
 
var method = instance[ methodName ];
if ( !method || methodName.charAt(0) == '_' ) {
logError( pluginMethodStr + ' is not a valid method' );
return;
}
 
// apply method, get return value
var value = method.apply( instance, args );
// set return value if value is returned, use only first value
returnValue = returnValue === undefined ? value : returnValue;
});
 
return returnValue !== undefined ? returnValue : $elems;
}
 
function plainCall( $elems, options ) {
$elems.each( function( i, elem ) {
var instance = $.data( elem, namespace );
if ( instance ) {
// set options & init
instance.option( options );
instance._init();
} else {
// initialize new instance
instance = new PluginClass( elem, options );
$.data( elem, namespace, instance );
}
});
}
 
updateJQuery( $ );
 
}
 
// ----- updateJQuery ----- //
 
// set $.bridget for v1 backwards compatibility
function updateJQuery( $ ) {
if ( !$ || ( $ && $.bridget ) ) {
return;
}
$.bridget = jQueryBridget;
}
 
updateJQuery( jQuery || window.jQuery );
 
// ----- ----- //
 
return jQueryBridget;
 
}));
 
/**
* EvEmitter v1.1.0
* Lil' event emitter
* MIT License
*/
 
/* jshint unused: true, undef: true, strict: true */
 
( function( global, factory ) {
// universal module definition
/* jshint strict: false */ /* globals define, module, window */
if ( typeof define == 'function' && define.amd ) {
// AMD - RequireJS
define( 'ev-emitter/ev-emitter',factory );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS - Browserify, Webpack
module.exports = factory();
} else {
// Browser globals
global.EvEmitter = factory();
}
 
}( typeof window != 'undefined' ? window : this, function() {
 
 
 
function EvEmitter() {}
 
var proto = EvEmitter.prototype;
 
proto.on = function( eventName, listener ) {
if ( !eventName || !listener ) {
return;
}
// set events hash
var events = this._events = this._events || {};
// set listeners array
var listeners = events[ eventName ] = events[ eventName ] || [];
// only add once
if ( listeners.indexOf( listener ) == -1 ) {
listeners.push( listener );
}
 
return this;
};
 
proto.once = function( eventName, listener ) {
if ( !eventName || !listener ) {
return;
}
// add event
this.on( eventName, listener );
// set once flag
// set onceEvents hash
var onceEvents = this._onceEvents = this._onceEvents || {};
// set onceListeners object
var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
// set flag
onceListeners[ listener ] = true;
 
return this;
};
 
proto.off = function( eventName, listener ) {
var listeners = this._events && this._events[ eventName ];
if ( !listeners || !listeners.length ) {
return;
}
var index = listeners.indexOf( listener );
if ( index != -1 ) {
listeners.splice( index, 1 );
}
 
return this;
};
 
proto.emitEvent = function( eventName, args ) {
var listeners = this._events && this._events[ eventName ];
if ( !listeners || !listeners.length ) {
return;
}
// copy over to avoid interference if .off() in listener
listeners = listeners.slice(0);
args = args || [];
// once stuff
var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
 
for ( var i=0; i < listeners.length; i++ ) {
var listener = listeners[i]
var isOnce = onceListeners && onceListeners[ listener ];
if ( isOnce ) {
// remove listener
// remove before trigger to prevent recursion
this.off( eventName, listener );
// unset once flag
delete onceListeners[ listener ];
}
// trigger listener
listener.apply( this, args );
}
 
return this;
};
 
proto.allOff = function() {
delete this._events;
delete this._onceEvents;
};
 
return EvEmitter;
 
}));
 
/*!
* getSize v2.0.3
* measure size of elements
* MIT license
*/
 
/* jshint browser: true, strict: true, undef: true, unused: true */
/* globals console: false */
 
( function( window, factory ) {
/* jshint strict: false */ /* globals define, module */
if ( typeof define == 'function' && define.amd ) {
// AMD
define( 'get-size/get-size',factory );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory();
} else {
// browser global
window.getSize = factory();
}
 
})( window, function factory() {
'use strict';
 
// -------------------------- helpers -------------------------- //
 
// get a number from a string, not a percentage
function getStyleSize( value ) {
var num = parseFloat( value );
// not a percent like '100%', and a number
var isValid = value.indexOf('%') == -1 && !isNaN( num );
return isValid && num;
}
 
function noop() {}
 
var logError = typeof console == 'undefined' ? noop :
function( message ) {
console.error( message );
};
 
// -------------------------- measurements -------------------------- //
 
var measurements = [
'paddingLeft',
'paddingRight',
'paddingTop',
'paddingBottom',
'marginLeft',
'marginRight',
'marginTop',
'marginBottom',
'borderLeftWidth',
'borderRightWidth',
'borderTopWidth',
'borderBottomWidth'
];
 
var measurementsLength = measurements.length;
 
function getZeroSize() {
var size = {
width: 0,
height: 0,
innerWidth: 0,
innerHeight: 0,
outerWidth: 0,
outerHeight: 0
};
for ( var i=0; i < measurementsLength; i++ ) {
var measurement = measurements[i];
size[ measurement ] = 0;
}
return size;
}
 
// -------------------------- getStyle -------------------------- //
 
/**
* getStyle, get style of element, check for Firefox bug
* https://bugzilla.mozilla.org/show_bug.cgi?id=548397
*/
function getStyle( elem ) {
var style = getComputedStyle( elem );
if ( !style ) {
logError( 'Style returned ' + style +
'. Are you running this code in a hidden iframe on Firefox? ' +
'See https://bit.ly/getsizebug1' );
}
return style;
}
 
// -------------------------- setup -------------------------- //
 
var isSetup = false;
 
var isBoxSizeOuter;
 
/**
* setup
* check isBoxSizerOuter
* do on first getSize() rather than on page load for Firefox bug
*/
function setup() {
// setup once
if ( isSetup ) {
return;
}
isSetup = true;
 
// -------------------------- box sizing -------------------------- //
 
/**
* Chrome & Safari measure the outer-width on style.width on border-box elems
* IE11 & Firefox<29 measures the inner-width
*/
var div = document.createElement('div');
div.style.width = '200px';
div.style.padding = '1px 2px 3px 4px';
div.style.borderStyle = 'solid';
div.style.borderWidth = '1px 2px 3px 4px';
div.style.boxSizing = 'border-box';
 
var body = document.body || document.documentElement;
body.appendChild( div );
var style = getStyle( div );
// round value for browser zoom. desandro/masonry#928
isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
getSize.isBoxSizeOuter = isBoxSizeOuter;
 
body.removeChild( div );
}
 
// -------------------------- getSize -------------------------- //
 
function getSize( elem ) {
setup();
 
// use querySeletor if elem is string
if ( typeof elem == 'string' ) {
elem = document.querySelector( elem );
}
 
// do not proceed on non-objects
if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
return;
}
 
var style = getStyle( elem );
 
// if hidden, everything is 0
if ( style.display == 'none' ) {
return getZeroSize();
}
 
var size = {};
size.width = elem.offsetWidth;
size.height = elem.offsetHeight;
 
var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
 
// get all measurements
for ( var i=0; i < measurementsLength; i++ ) {
var measurement = measurements[i];
var value = style[ measurement ];
var num = parseFloat( value );
// any 'auto', 'medium' value will be 0
size[ measurement ] = !isNaN( num ) ? num : 0;
}
 
var paddingWidth = size.paddingLeft + size.paddingRight;
var paddingHeight = size.paddingTop + size.paddingBottom;
var marginWidth = size.marginLeft + size.marginRight;
var marginHeight = size.marginTop + size.marginBottom;
var borderWidth = size.borderLeftWidth + size.borderRightWidth;
var borderHeight = size.borderTopWidth + size.borderBottomWidth;
 
var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
 
// overwrite width and height if we can get it from style
var styleWidth = getStyleSize( style.width );
if ( styleWidth !== false ) {
size.width = styleWidth +
// add padding and border unless it's already including it
( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
}
 
var styleHeight = getStyleSize( style.height );
if ( styleHeight !== false ) {
size.height = styleHeight +
// add padding and border unless it's already including it
( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
}
 
size.innerWidth = size.width - ( paddingWidth + borderWidth );
size.innerHeight = size.height - ( paddingHeight + borderHeight );
 
size.outerWidth = size.width + marginWidth;
size.outerHeight = size.height + marginHeight;
 
return size;
}
 
return getSize;
 
});
 
/**
* matchesSelector v2.0.2
* matchesSelector( element, '.selector' )
* MIT license
*/
 
/*jshint browser: true, strict: true, undef: true, unused: true */
 
( function( window, factory ) {
/*global define: false, module: false */
'use strict';
// universal module definition
if ( typeof define == 'function' && define.amd ) {
// AMD
define( 'desandro-matches-selector/matches-selector',factory );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory();
} else {
// browser global
window.matchesSelector = factory();
}
 
}( window, function factory() {
'use strict';
 
var matchesMethod = ( function() {
var ElemProto = window.Element.prototype;
// check for the standard method name first
if ( ElemProto.matches ) {
return 'matches';
}
// check un-prefixed
if ( ElemProto.matchesSelector ) {
return 'matchesSelector';
}
// check vendor prefixes
var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
 
for ( var i=0; i < prefixes.length; i++ ) {
var prefix = prefixes[i];
var method = prefix + 'MatchesSelector';
if ( ElemProto[ method ] ) {
return method;
}
}
})();
 
return function matchesSelector( elem, selector ) {
return elem[ matchesMethod ]( selector );
};
 
}));
 
/**
* Fizzy UI utils v2.0.7
* MIT license
*/
 
/*jshint browser: true, undef: true, unused: true, strict: true */
 
( function( window, factory ) {
// universal module definition
/*jshint strict: false */ /*globals define, module, require */
 
if ( typeof define == 'function' && define.amd ) {
// AMD
define( 'fizzy-ui-utils/utils',[
'desandro-matches-selector/matches-selector'
], function( matchesSelector ) {
return factory( window, matchesSelector );
});
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
window,
require('desandro-matches-selector')
);
} else {
// browser global
window.fizzyUIUtils = factory(
window,
window.matchesSelector
);
}
 
}( window, function factory( window, matchesSelector ) {
 
 
 
var utils = {};
 
// ----- extend ----- //
 
// extends objects
utils.extend = function( a, b ) {
for ( var prop in b ) {
a[ prop ] = b[ prop ];
}
return a;
};
 
// ----- modulo ----- //
 
utils.modulo = function( num, div ) {
return ( ( num % div ) + div ) % div;
};
 
// ----- makeArray ----- //
 
var arraySlice = Array.prototype.slice;
 
// turn element or nodeList into an array
utils.makeArray = function( obj ) {
if ( Array.isArray( obj ) ) {
// use object if already an array
return obj;
}
// return empty array if undefined or null. #6
if ( obj === null || obj === undefined ) {
return [];
}
 
var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
if ( isArrayLike ) {
// convert nodeList to array
return arraySlice.call( obj );
}
 
// array of single index
return [ obj ];
};
 
// ----- removeFrom ----- //
 
utils.removeFrom = function( ary, obj ) {
var index = ary.indexOf( obj );
if ( index != -1 ) {
ary.splice( index, 1 );
}
};
 
// ----- getParent ----- //
 
utils.getParent = function( elem, selector ) {
while ( elem.parentNode && elem != document.body ) {
elem = elem.parentNode;
if ( matchesSelector( elem, selector ) ) {
return elem;
}
}
};
 
// ----- getQueryElement ----- //
 
// use element as selector string
utils.getQueryElement = function( elem ) {
if ( typeof elem == 'string' ) {
return document.querySelector( elem );
}
return elem;
};
 
// ----- handleEvent ----- //
 
// enable .ontype to trigger from .addEventListener( elem, 'type' )
utils.handleEvent = function( event ) {
var method = 'on' + event.type;
if ( this[ method ] ) {
this[ method ]( event );
}
};
 
// ----- filterFindElements ----- //
 
utils.filterFindElements = function( elems, selector ) {
// make array of elems
elems = utils.makeArray( elems );
var ffElems = [];
 
elems.forEach( function( elem ) {
// check that elem is an actual element
if ( !( elem instanceof HTMLElement ) ) {
return;
}
// add elem if no selector
if ( !selector ) {
ffElems.push( elem );
return;
}
// filter & find items if we have a selector
// filter
if ( matchesSelector( elem, selector ) ) {
ffElems.push( elem );
}
// find children
var childElems = elem.querySelectorAll( selector );
// concat childElems to filterFound array
for ( var i=0; i < childElems.length; i++ ) {
ffElems.push( childElems[i] );
}
});
 
return ffElems;
};
 
// ----- debounceMethod ----- //
 
utils.debounceMethod = function( _class, methodName, threshold ) {
threshold = threshold || 100;
// original method
var method = _class.prototype[ methodName ];
var timeoutName = methodName + 'Timeout';
 
_class.prototype[ methodName ] = function() {
var timeout = this[ timeoutName ];
clearTimeout( timeout );
 
var args = arguments;
var _this = this;
this[ timeoutName ] = setTimeout( function() {
method.apply( _this, args );
delete _this[ timeoutName ];
}, threshold );
};
};
 
// ----- docReady ----- //
 
utils.docReady = function( callback ) {
var readyState = document.readyState;
if ( readyState == 'complete' || readyState == 'interactive' ) {
// do async to allow for other scripts to run. metafizzy/flickity#441
setTimeout( callback );
} else {
document.addEventListener( 'DOMContentLoaded', callback );
}
};
 
// ----- htmlInit ----- //
 
// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
utils.toDashed = function( str ) {
return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
return $1 + '-' + $2;
}).toLowerCase();
};
 
var console = window.console;
/**
* allow user to initialize classes via [data-namespace] or .js-namespace class
* htmlInit( Widget, 'widgetName' )
* options are parsed from data-namespace-options
*/
utils.htmlInit = function( WidgetClass, namespace ) {
utils.docReady( function() {
var dashedNamespace = utils.toDashed( namespace );
var dataAttr = 'data-' + dashedNamespace;
var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
var elems = utils.makeArray( dataAttrElems )
.concat( utils.makeArray( jsDashElems ) );
var dataOptionsAttr = dataAttr + '-options';
var jQuery = window.jQuery;
 
elems.forEach( function( elem ) {
var attr = elem.getAttribute( dataAttr ) ||
elem.getAttribute( dataOptionsAttr );
var options;
try {
options = attr && JSON.parse( attr );
} catch ( error ) {
// log error, do not initialize
if ( console ) {
console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
': ' + error );
}
return;
}
// initialize
var instance = new WidgetClass( elem, options );
// make available via $().data('namespace')
if ( jQuery ) {
jQuery.data( elem, namespace, instance );
}
});
 
});
};
 
// ----- ----- //
 
return utils;
 
}));
 
/**
* Outlayer Item
*/
 
( function( window, factory ) {
// universal module definition
/* jshint strict: false */ /* globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
// AMD - RequireJS
define( 'outlayer/item',[
'ev-emitter/ev-emitter',
'get-size/get-size'
],
factory
);
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS - Browserify, Webpack
module.exports = factory(
require('ev-emitter'),
require('get-size')
);
} else {
// browser global
window.Outlayer = {};
window.Outlayer.Item = factory(
window.EvEmitter,
window.getSize
);
}
 
}( window, function factory( EvEmitter, getSize ) {
'use strict';
 
// ----- helpers ----- //
 
function isEmptyObj( obj ) {
for ( var prop in obj ) {
return false;
}
prop = null;
return true;
}
 
// -------------------------- CSS3 support -------------------------- //
 
 
var docElemStyle = document.documentElement.style;
 
var transitionProperty = typeof docElemStyle.transition == 'string' ?
'transition' : 'WebkitTransition';
var transformProperty = typeof docElemStyle.transform == 'string' ?
'transform' : 'WebkitTransform';
 
var transitionEndEvent = {
WebkitTransition: 'webkitTransitionEnd',
transition: 'transitionend'
}[ transitionProperty ];
 
// cache all vendor properties that could have vendor prefix
var vendorProperties = {
transform: transformProperty,
transition: transitionProperty,
transitionDuration: transitionProperty + 'Duration',
transitionProperty: transitionProperty + 'Property',
transitionDelay: transitionProperty + 'Delay'
};
 
// -------------------------- Item -------------------------- //
 
function Item( element, layout ) {
if ( !element ) {
return;
}
 
this.element = element;
// parent layout class, i.e. Masonry, Isotope, or Packery
this.layout = layout;
this.position = {
x: 0,
y: 0
};
 
this._create();
}
 
// inherit EvEmitter
var proto = Item.prototype = Object.create( EvEmitter.prototype );
proto.constructor = Item;
 
proto._create = function() {
// transition objects
this._transn = {
ingProperties: {},
clean: {},
onEnd: {}
};
 
this.css({
position: 'absolute'
});
};
 
// trigger specified handler for event type
proto.handleEvent = function( event ) {
var method = 'on' + event.type;
if ( this[ method ] ) {
this[ method ]( event );
}
};
 
proto.getSize = function() {
this.size = getSize( this.element );
};
 
/**
* apply CSS styles to element
* @param {Object} style
*/
proto.css = function( style ) {
var elemStyle = this.element.style;
 
for ( var prop in style ) {
// use vendor property if available
var supportedProp = vendorProperties[ prop ] || prop;
elemStyle[ supportedProp ] = style[ prop ];
}
};
 
// measure position, and sets it
proto.getPosition = function() {
var style = getComputedStyle( this.element );
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
var xValue = style[ isOriginLeft ? 'left' : 'right' ];
var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
var x = parseFloat( xValue );
var y = parseFloat( yValue );
// convert percent to pixels
var layoutSize = this.layout.size;
if ( xValue.indexOf('%') != -1 ) {
x = ( x / 100 ) * layoutSize.width;
}
if ( yValue.indexOf('%') != -1 ) {
y = ( y / 100 ) * layoutSize.height;
}
// clean up 'auto' or other non-integer values
x = isNaN( x ) ? 0 : x;
y = isNaN( y ) ? 0 : y;
// remove padding from measurement
x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
 
this.position.x = x;
this.position.y = y;
};
 
// set settled position, apply padding
proto.layoutPosition = function() {
var layoutSize = this.layout.size;
var style = {};
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
 
// x
var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
var xProperty = isOriginLeft ? 'left' : 'right';
var xResetProperty = isOriginLeft ? 'right' : 'left';
 
var x = this.position.x + layoutSize[ xPadding ];
// set in percentage or pixels
style[ xProperty ] = this.getXValue( x );
// reset other property
style[ xResetProperty ] = '';
 
// y
var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
var yProperty = isOriginTop ? 'top' : 'bottom';
var yResetProperty = isOriginTop ? 'bottom' : 'top';
 
var y = this.position.y + layoutSize[ yPadding ];
// set in percentage or pixels
style[ yProperty ] = this.getYValue( y );
// reset other property
style[ yResetProperty ] = '';
 
this.css( style );
this.emitEvent( 'layout', [ this ] );
};
 
proto.getXValue = function( x ) {
var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && !isHorizontal ?
( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
};
 
proto.getYValue = function( y ) {
var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && isHorizontal ?
( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
};
 
proto._transitionTo = function( x, y ) {
this.getPosition();
// get current x & y from top/left
var curX = this.position.x;
var curY = this.position.y;
 
var didNotMove = x == this.position.x && y == this.position.y;
 
// save end position
this.setPosition( x, y );
 
// if did not move and not transitioning, just go to layout
if ( didNotMove && !this.isTransitioning ) {
this.layoutPosition();
return;
}
 
var transX = x - curX;
var transY = y - curY;
var transitionStyle = {};
transitionStyle.transform = this.getTranslate( transX, transY );
 
this.transition({
to: transitionStyle,
onTransitionEnd: {
transform: this.layoutPosition
},
isCleaning: true
});
};
 
proto.getTranslate = function( x, y ) {
// flip cooridinates if origin on right or bottom
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
x = isOriginLeft ? x : -x;
y = isOriginTop ? y : -y;
return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
};
 
// non transition + transform support
proto.goTo = function( x, y ) {
this.setPosition( x, y );
this.layoutPosition();
};
 
proto.moveTo = proto._transitionTo;
 
proto.setPosition = function( x, y ) {
this.position.x = parseFloat( x );
this.position.y = parseFloat( y );
};
 
// ----- transition ----- //
 
/**
* @param {Object} style - CSS
* @param {Function} onTransitionEnd
*/
 
// non transition, just trigger callback
proto._nonTransition = function( args ) {
this.css( args.to );
if ( args.isCleaning ) {
this._removeStyles( args.to );
}
for ( var prop in args.onTransitionEnd ) {
args.onTransitionEnd[ prop ].call( this );
}
};
 
/**
* proper transition
* @param {Object} args - arguments
* @param {Object} to - style to transition to
* @param {Object} from - style to start transition from
* @param {Boolean} isCleaning - removes transition styles after transition
* @param {Function} onTransitionEnd - callback
*/
proto.transition = function( args ) {
// redirect to nonTransition if no transition duration
if ( !parseFloat( this.layout.options.transitionDuration ) ) {
this._nonTransition( args );
return;
}
 
var _transition = this._transn;
// keep track of onTransitionEnd callback by css property
for ( var prop in args.onTransitionEnd ) {
_transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
}
// keep track of properties that are transitioning
for ( prop in args.to ) {
_transition.ingProperties[ prop ] = true;
// keep track of properties to clean up when transition is done
if ( args.isCleaning ) {
_transition.clean[ prop ] = true;
}
}
 
// set from styles
if ( args.from ) {
this.css( args.from );
// force redraw. http://blog.alexmaccaw.com/css-transitions
var h = this.element.offsetHeight;
// hack for JSHint to hush about unused var
h = null;
}
// enable transition
this.enableTransition( args.to );
// set styles that are transitioning
this.css( args.to );
 
this.isTransitioning = true;
 
};
 
// dash before all cap letters, including first for
// WebkitTransform => -webkit-transform
function toDashedAll( str ) {
return str.replace( /([A-Z])/g, function( $1 ) {
return '-' + $1.toLowerCase();
});
}
 
var transitionProps = 'opacity,' + toDashedAll( transformProperty );
 
proto.enableTransition = function(/* style */) {
// HACK changing transitionProperty during a transition
// will cause transition to jump
if ( this.isTransitioning ) {
return;
}
 
// make `transition: foo, bar, baz` from style object
// HACK un-comment this when enableTransition can work
// while a transition is happening
// var transitionValues = [];
// for ( var prop in style ) {
// // dash-ify camelCased properties like WebkitTransition
// prop = vendorProperties[ prop ] || prop;
// transitionValues.push( toDashedAll( prop ) );
// }
// munge number to millisecond, to match stagger
var duration = this.layout.options.transitionDuration;
duration = typeof duration == 'number' ? duration + 'ms' : duration;
// enable transition styles
this.css({
transitionProperty: transitionProps,
transitionDuration: duration,
transitionDelay: this.staggerDelay || 0
});
// listen for transition end event
this.element.addEventListener( transitionEndEvent, this, false );
};
 
// ----- events ----- //
 
proto.onwebkitTransitionEnd = function( event ) {
this.ontransitionend( event );
};
 
proto.onotransitionend = function( event ) {
this.ontransitionend( event );
};
 
// properties that I munge to make my life easier
var dashedVendorProperties = {
'-webkit-transform': 'transform'
};
 
proto.ontransitionend = function( event ) {
// disregard bubbled events from children
if ( event.target !== this.element ) {
return;
}
var _transition = this._transn;
// get property name of transitioned property, convert to prefix-free
var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
 
// remove property that has completed transitioning
delete _transition.ingProperties[ propertyName ];
// check if any properties are still transitioning
if ( isEmptyObj( _transition.ingProperties ) ) {
// all properties have completed transitioning
this.disableTransition();
}
// clean style
if ( propertyName in _transition.clean ) {
// clean up style
this.element.style[ event.propertyName ] = '';
delete _transition.clean[ propertyName ];
}
// trigger onTransitionEnd callback
if ( propertyName in _transition.onEnd ) {
var onTransitionEnd = _transition.onEnd[ propertyName ];
onTransitionEnd.call( this );
delete _transition.onEnd[ propertyName ];
}
 
this.emitEvent( 'transitionEnd', [ this ] );
};
 
proto.disableTransition = function() {
this.removeTransitionStyles();
this.element.removeEventListener( transitionEndEvent, this, false );
this.isTransitioning = false;
};
 
/**
* removes style property from element
* @param {Object} style
**/
proto._removeStyles = function( style ) {
// clean up transition styles
var cleanStyle = {};
for ( var prop in style ) {
cleanStyle[ prop ] = '';
}
this.css( cleanStyle );
};
 
var cleanTransitionStyle = {
transitionProperty: '',
transitionDuration: '',
transitionDelay: ''
};
 
proto.removeTransitionStyles = function() {
// remove transition
this.css( cleanTransitionStyle );
};
 
// ----- stagger ----- //
 
proto.stagger = function( delay ) {
delay = isNaN( delay ) ? 0 : delay;
this.staggerDelay = delay + 'ms';
};
 
// ----- show/hide/remove ----- //
 
// remove element from DOM
proto.removeElem = function() {
this.element.parentNode.removeChild( this.element );
// remove display: none
this.css({ display: '' });
this.emitEvent( 'remove', [ this ] );
};
 
proto.remove = function() {
// just remove element if no transition support or no transition
if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
this.removeElem();
return;
}
 
// start transition
this.once( 'transitionEnd', function() {
this.removeElem();
});
this.hide();
};
 
proto.reveal = function() {
delete this.isHidden;
// remove display: none
this.css({ display: '' });
 
var options = this.layout.options;
 
var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
 
this.transition({
from: options.hiddenStyle,
to: options.visibleStyle,
isCleaning: true,
onTransitionEnd: onTransitionEnd
});
};
 
proto.onRevealTransitionEnd = function() {
// check if still visible
// during transition, item may have been hidden
if ( !this.isHidden ) {
this.emitEvent('reveal');
}
};
 
/**
* get style property use for hide/reveal transition end
* @param {String} styleProperty - hiddenStyle/visibleStyle
* @returns {String}
*/
proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
var optionStyle = this.layout.options[ styleProperty ];
// use opacity
if ( optionStyle.opacity ) {
return 'opacity';
}
// get first property
for ( var prop in optionStyle ) {
return prop;
}
};
 
proto.hide = function() {
// set flag
this.isHidden = true;
// remove display: none
this.css({ display: '' });
 
var options = this.layout.options;
 
var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
 
this.transition({
from: options.visibleStyle,
to: options.hiddenStyle,
// keep hidden stuff hidden
isCleaning: true,
onTransitionEnd: onTransitionEnd
});
};
 
proto.onHideTransitionEnd = function() {
// check if still hidden
// during transition, item may have been un-hidden
if ( this.isHidden ) {
this.css({ display: 'none' });
this.emitEvent('hide');
}
};
 
proto.destroy = function() {
this.css({
position: '',
left: '',
right: '',
top: '',
bottom: '',
transition: '',
transform: ''
});
};
 
return Item;
 
}));
 
/*!
* Outlayer v2.1.1
* the brains and guts of a layout library
* MIT license
*/
 
( function( window, factory ) {
'use strict';
// universal module definition
/* jshint strict: false */ /* globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
// AMD - RequireJS
define( 'outlayer/outlayer',[
'ev-emitter/ev-emitter',
'get-size/get-size',
'fizzy-ui-utils/utils',
'./item'
],
function( EvEmitter, getSize, utils, Item ) {
return factory( window, EvEmitter, getSize, utils, Item);
}
);
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS - Browserify, Webpack
module.exports = factory(
window,
require('ev-emitter'),
require('get-size'),
require('fizzy-ui-utils'),
require('./item')
);
} else {
// browser global
window.Outlayer = factory(
window,
window.EvEmitter,
window.getSize,
window.fizzyUIUtils,
window.Outlayer.Item
);
}
 
}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
'use strict';
 
// ----- vars ----- //
 
var console = window.console;
var jQuery = window.jQuery;
var noop = function() {};
 
// -------------------------- Outlayer -------------------------- //
 
// globally unique identifiers
var GUID = 0;
// internal store of all Outlayer intances
var instances = {};
 
 
/**
* @param {Element, String} element
* @param {Object} options
* @constructor
*/
function Outlayer( element, options ) {
var queryElement = utils.getQueryElement( element );
if ( !queryElement ) {
if ( console ) {
console.error( 'Bad element for ' + this.constructor.namespace +
': ' + ( queryElement || element ) );
}
return;
}
this.element = queryElement;
// add jQuery
if ( jQuery ) {
this.$element = jQuery( this.element );
}
 
// options
this.options = utils.extend( {}, this.constructor.defaults );
this.option( options );
 
// add id for Outlayer.getFromElement
var id = ++GUID;
this.element.outlayerGUID = id; // expando
instances[ id ] = this; // associate via id
 
// kick it off
this._create();
 
var isInitLayout = this._getOption('initLayout');
if ( isInitLayout ) {
this.layout();
}
}
 
// settings are for internal use only
Outlayer.namespace = 'outlayer';
Outlayer.Item = Item;
 
// default options
Outlayer.defaults = {
containerStyle: {
position: 'relative'
},
initLayout: true,
originLeft: true,
originTop: true,
resize: true,
resizeContainer: true,
// item options
transitionDuration: '0.4s',
hiddenStyle: {
opacity: 0,
transform: 'scale(0.001)'
},
visibleStyle: {
opacity: 1,
transform: 'scale(1)'
}
};
 
var proto = Outlayer.prototype;
// inherit EvEmitter
utils.extend( proto, EvEmitter.prototype );
 
/**
* set options
* @param {Object} opts
*/
proto.option = function( opts ) {
utils.extend( this.options, opts );
};
 
/**
* get backwards compatible option value, check old name
*/
proto._getOption = function( option ) {
var oldOption = this.constructor.compatOptions[ option ];
return oldOption && this.options[ oldOption ] !== undefined ?
this.options[ oldOption ] : this.options[ option ];
};
 
Outlayer.compatOptions = {
// currentName: oldName
initLayout: 'isInitLayout',
horizontal: 'isHorizontal',
layoutInstant: 'isLayoutInstant',
originLeft: 'isOriginLeft',
originTop: 'isOriginTop',
resize: 'isResizeBound',
resizeContainer: 'isResizingContainer'
};
 
proto._create = function() {
// get items from children
this.reloadItems();
// elements that affect layout, but are not laid out
this.stamps = [];
this.stamp( this.options.stamp );
// set container style
utils.extend( this.element.style, this.options.containerStyle );
 
// bind resize method
var canBindResize = this._getOption('resize');
if ( canBindResize ) {
this.bindResize();
}
};
 
// goes through all children again and gets bricks in proper order
proto.reloadItems = function() {
// collection of item elements
this.items = this._itemize( this.element.children );
};
 
 
/**
* turn elements into Outlayer.Items to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - collection of new Outlayer Items
*/
proto._itemize = function( elems ) {
 
var itemElems = this._filterFindItemElements( elems );
var Item = this.constructor.Item;
 
// create new Outlayer Items for collection
var items = [];
for ( var i=0; i < itemElems.length; i++ ) {
var elem = itemElems[i];
var item = new Item( elem, this );
items.push( item );
}
 
return items;
};
 
/**
* get item elements to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - item elements
*/
proto._filterFindItemElements = function( elems ) {
return utils.filterFindElements( elems, this.options.itemSelector );
};
 
/**
* getter method for getting item elements
* @returns {Array} elems - collection of item elements
*/
proto.getItemElements = function() {
return this.items.map( function( item ) {
return item.element;
});
};
 
// ----- init & layout ----- //
 
/**
* lays out all items
*/
proto.layout = function() {
this._resetLayout();
this._manageStamps();
 
// don't animate first layout
var layoutInstant = this._getOption('layoutInstant');
var isInstant = layoutInstant !== undefined ?
layoutInstant : !this._isLayoutInited;
this.layoutItems( this.items, isInstant );
 
// flag for initalized
this._isLayoutInited = true;
};
 
// _init is alias for layout
proto._init = proto.layout;
 
/**
* logic before any new layout
*/
proto._resetLayout = function() {
this.getSize();
};
 
 
proto.getSize = function() {
this.size = getSize( this.element );
};
 
/**
* get measurement from option, for columnWidth, rowHeight, gutter
* if option is String -> get element from selector string, & get size of element
* if option is Element -> get size of element
* else use option as a number
*
* @param {String} measurement
* @param {String} size - width or height
* @private
*/
proto._getMeasurement = function( measurement, size ) {
var option = this.options[ measurement ];
var elem;
if ( !option ) {
// default to 0
this[ measurement ] = 0;
} else {
// use option as an element
if ( typeof option == 'string' ) {
elem = this.element.querySelector( option );
} else if ( option instanceof HTMLElement ) {
elem = option;
}
// use size of element, if element
this[ measurement ] = elem ? getSize( elem )[ size ] : option;
}
};
 
/**
* layout a collection of item elements
* @api public
*/
proto.layoutItems = function( items, isInstant ) {
items = this._getItemsForLayout( items );
 
this._layoutItems( items, isInstant );
 
this._postLayout();
};
 
/**
* get the items to be laid out
* you may want to skip over some items
* @param {Array} items
* @returns {Array} items
*/
proto._getItemsForLayout = function( items ) {
return items.filter( function( item ) {
return !item.isIgnored;
});
};
 
/**
* layout items
* @param {Array} items
* @param {Boolean} isInstant
*/
proto._layoutItems = function( items, isInstant ) {
this._emitCompleteOnItems( 'layout', items );
 
if ( !items || !items.length ) {
// no items, emit event with empty array
return;
}
 
var queue = [];
 
items.forEach( function( item ) {
// get x/y object from method
var position = this._getItemLayoutPosition( item );
// enqueue
position.item = item;
position.isInstant = isInstant || item.isLayoutInstant;
queue.push( position );
}, this );
 
this._processLayoutQueue( queue );
};
 
/**
* get item layout position
* @param {Outlayer.Item} item
* @returns {Object} x and y position
*/
proto._getItemLayoutPosition = function( /* item */ ) {
return {
x: 0,
y: 0
};
};
 
/**
* iterate over array and position each item
* Reason being - separating this logic prevents 'layout invalidation'
* thx @paul_irish
* @param {Array} queue
*/
proto._processLayoutQueue = function( queue ) {
this.updateStagger();
queue.forEach( function( obj, i ) {
this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
}, this );
};
 
// set stagger from option in milliseconds number
proto.updateStagger = function() {
var stagger = this.options.stagger;
if ( stagger === null || stagger === undefined ) {
this.stagger = 0;
return;
}
this.stagger = getMilliseconds( stagger );
return this.stagger;
};
 
/**
* Sets position of item in DOM
* @param {Outlayer.Item} item
* @param {Number} x - horizontal position
* @param {Number} y - vertical position
* @param {Boolean} isInstant - disables transitions
*/
proto._positionItem = function( item, x, y, isInstant, i ) {
if ( isInstant ) {
// if not transition, just set CSS
item.goTo( x, y );
} else {
item.stagger( i * this.stagger );
item.moveTo( x, y );
}
};
 
/**
* Any logic you want to do after each layout,
* i.e. size the container
*/
proto._postLayout = function() {
this.resizeContainer();
};
 
proto.resizeContainer = function() {
var isResizingContainer = this._getOption('resizeContainer');
if ( !isResizingContainer ) {
return;
}
var size = this._getContainerSize();
if ( size ) {
this._setContainerMeasure( size.width, true );
this._setContainerMeasure( size.height, false );
}
};
 
/**
* Sets width or height of container if returned
* @returns {Object} size
* @param {Number} width
* @param {Number} height
*/
proto._getContainerSize = noop;
 
/**
* @param {Number} measure - size of width or height
* @param {Boolean} isWidth
*/
proto._setContainerMeasure = function( measure, isWidth ) {
if ( measure === undefined ) {
return;
}
 
var elemSize = this.size;
// add padding and border width if border box
if ( elemSize.isBorderBox ) {
measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
elemSize.borderLeftWidth + elemSize.borderRightWidth :
elemSize.paddingBottom + elemSize.paddingTop +
elemSize.borderTopWidth + elemSize.borderBottomWidth;
}
 
measure = Math.max( measure, 0 );
this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
};
 
/**
* emit eventComplete on a collection of items events
* @param {String} eventName
* @param {Array} items - Outlayer.Items
*/
proto._emitCompleteOnItems = function( eventName, items ) {
var _this = this;
function onComplete() {
_this.dispatchEvent( eventName + 'Complete', null, [ items ] );
}
 
var count = items.length;
if ( !items || !count ) {
onComplete();
return;
}
 
var doneCount = 0;
function tick() {
doneCount++;
if ( doneCount == count ) {
onComplete();
}
}
 
// bind callback
items.forEach( function( item ) {
item.once( eventName, tick );
});
};
 
/**
* emits events via EvEmitter and jQuery events
* @param {String} type - name of event
* @param {Event} event - original event
* @param {Array} args - extra arguments
*/
proto.dispatchEvent = function( type, event, args ) {
// add original event to arguments
var emitArgs = event ? [ event ].concat( args ) : args;
this.emitEvent( type, emitArgs );
 
if ( jQuery ) {
// set this.$element
this.$element = this.$element || jQuery( this.element );
if ( event ) {
// create jQuery event
var $event = jQuery.Event( event );
$event.type = type;
this.$element.trigger( $event, args );
} else {
// just trigger with type if no event available
this.$element.trigger( type, args );
}
}
};
 
// -------------------------- ignore & stamps -------------------------- //
 
 
/**
* keep item in collection, but do not lay it out
* ignored items do not get skipped in layout
* @param {Element} elem
*/
proto.ignore = function( elem ) {
var item = this.getItem( elem );
if ( item ) {
item.isIgnored = true;
}
};
 
/**
* return item to layout collection
* @param {Element} elem
*/
proto.unignore = function( elem ) {
var item = this.getItem( elem );
if ( item ) {
delete item.isIgnored;
}
};
 
/**
* adds elements to stamps
* @param {NodeList, Array, Element, or String} elems
*/
proto.stamp = function( elems ) {
elems = this._find( elems );
if ( !elems ) {
return;
}
 
this.stamps = this.stamps.concat( elems );
// ignore
elems.forEach( this.ignore, this );
};
 
/**
* removes elements to stamps
* @param {NodeList, Array, or Element} elems
*/
proto.unstamp = function( elems ) {
elems = this._find( elems );
if ( !elems ){
return;
}
 
elems.forEach( function( elem ) {
// filter out removed stamp elements
utils.removeFrom( this.stamps, elem );
this.unignore( elem );
}, this );
};
 
/**
* finds child elements
* @param {NodeList, Array, Element, or String} elems
* @returns {Array} elems
*/
proto._find = function( elems ) {
if ( !elems ) {
return;
}
// if string, use argument as selector string
if ( typeof elems == 'string' ) {
elems = this.element.querySelectorAll( elems );
}
elems = utils.makeArray( elems );
return elems;
};
 
proto._manageStamps = function() {
if ( !this.stamps || !this.stamps.length ) {
return;
}
 
this._getBoundingRect();
 
this.stamps.forEach( this._manageStamp, this );
};
 
// update boundingLeft / Top
proto._getBoundingRect = function() {
// get bounding rect for container element
var boundingRect = this.element.getBoundingClientRect();
var size = this.size;
this._boundingRect = {
left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
top: boundingRect.top + size.paddingTop + size.borderTopWidth,
right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
};
};
 
/**
* @param {Element} stamp
**/
proto._manageStamp = noop;
 
/**
* get x/y position of element relative to container element
* @param {Element} elem
* @returns {Object} offset - has left, top, right, bottom
*/
proto._getElementOffset = function( elem ) {
var boundingRect = elem.getBoundingClientRect();
var thisRect = this._boundingRect;
var size = getSize( elem );
var offset = {
left: boundingRect.left - thisRect.left - size.marginLeft,
top: boundingRect.top - thisRect.top - size.marginTop,
right: thisRect.right - boundingRect.right - size.marginRight,
bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
};
return offset;
};
 
// -------------------------- resize -------------------------- //
 
// enable event handlers for listeners
// i.e. resize -> onresize
proto.handleEvent = utils.handleEvent;
 
/**
* Bind layout to window resizing
*/
proto.bindResize = function() {
window.addEventListener( 'resize', this );
this.isResizeBound = true;
};
 
/**
* Unbind layout to window resizing
*/
proto.unbindResize = function() {
window.removeEventListener( 'resize', this );
this.isResizeBound = false;
};
 
proto.onresize = function() {
this.resize();
};
 
utils.debounceMethod( Outlayer, 'onresize', 100 );
 
proto.resize = function() {
// don't trigger if size did not change
// or if resize was unbound. See #9
if ( !this.isResizeBound || !this.needsResizeLayout() ) {
return;
}
 
this.layout();
};
 
/**
* check if layout is needed post layout
* @returns Boolean
*/
proto.needsResizeLayout = function() {
var size = getSize( this.element );
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var hasSizes = this.size && size;
return hasSizes && size.innerWidth !== this.size.innerWidth;
};
 
// -------------------------- methods -------------------------- //
 
/**
* add items to Outlayer instance
* @param {Array or NodeList or Element} elems
* @returns {Array} items - Outlayer.Items
**/
proto.addItems = function( elems ) {
var items = this._itemize( elems );
// add items to collection
if ( items.length ) {
this.items = this.items.concat( items );
}
return items;
};
 
/**
* Layout newly-appended item elements
* @param {Array or NodeList or Element} elems
*/
proto.appended = function( elems ) {
var items = this.addItems( elems );
if ( !items.length ) {
return;
}
// layout and reveal just the new items
this.layoutItems( items, true );
this.reveal( items );
};
 
/**
* Layout prepended elements
* @param {Array or NodeList or Element} elems
*/
proto.prepended = function( elems ) {
var items = this._itemize( elems );
if ( !items.length ) {
return;
}
// add items to beginning of collection
var previousItems = this.items.slice(0);
this.items = items.concat( previousItems );
// start new layout
this._resetLayout();
this._manageStamps();
// layout new stuff without transition
this.layoutItems( items, true );
this.reveal( items );
// layout previous items
this.layoutItems( previousItems );
};
 
/**
* reveal a collection of items
* @param {Array of Outlayer.Items} items
*/
proto.reveal = function( items ) {
this._emitCompleteOnItems( 'reveal', items );
if ( !items || !items.length ) {
return;
}
var stagger = this.updateStagger();
items.forEach( function( item, i ) {
item.stagger( i * stagger );
item.reveal();
});
};
 
/**
* hide a collection of items
* @param {Array of Outlayer.Items} items
*/
proto.hide = function( items ) {
this._emitCompleteOnItems( 'hide', items );
if ( !items || !items.length ) {
return;
}
var stagger = this.updateStagger();
items.forEach( function( item, i ) {
item.stagger( i * stagger );
item.hide();
});
};
 
/**
* reveal item elements
* @param {Array}, {Element}, {NodeList} items
*/
proto.revealItemElements = function( elems ) {
var items = this.getItems( elems );
this.reveal( items );
};
 
/**
* hide item elements
* @param {Array}, {Element}, {NodeList} items
*/
proto.hideItemElements = function( elems ) {
var items = this.getItems( elems );
this.hide( items );
};
 
/**
* get Outlayer.Item, given an Element
* @param {Element} elem
* @param {Function} callback
* @returns {Outlayer.Item} item
*/
proto.getItem = function( elem ) {
// loop through items to get the one that matches
for ( var i=0; i < this.items.length; i++ ) {
var item = this.items[i];
if ( item.element == elem ) {
// return item
return item;
}
}
};
 
/**
* get collection of Outlayer.Items, given Elements
* @param {Array} elems
* @returns {Array} items - Outlayer.Items
*/
proto.getItems = function( elems ) {
elems = utils.makeArray( elems );
var items = [];
elems.forEach( function( elem ) {
var item = this.getItem( elem );
if ( item ) {
items.push( item );
}
}, this );
 
return items;
};
 
/**
* remove element(s) from instance and DOM
* @param {Array or NodeList or Element} elems
*/
proto.remove = function( elems ) {
var removeItems = this.getItems( elems );
 
this._emitCompleteOnItems( 'remove', removeItems );
 
// bail if no items to remove
if ( !removeItems || !removeItems.length ) {
return;
}
 
removeItems.forEach( function( item ) {
item.remove();
// remove item from collection
utils.removeFrom( this.items, item );
}, this );
};
 
// ----- destroy ----- //
 
// remove and disable Outlayer instance
proto.destroy = function() {
// clean up dynamic styles
var style = this.element.style;
style.height = '';
style.position = '';
style.width = '';
// destroy items
this.items.forEach( function( item ) {
item.destroy();
});
 
this.unbindResize();
 
var id = this.element.outlayerGUID;
delete instances[ id ]; // remove reference to instance by id
delete this.element.outlayerGUID;
// remove data for jQuery
if ( jQuery ) {
jQuery.removeData( this.element, this.constructor.namespace );
}
 
};
 
// -------------------------- data -------------------------- //
 
/**
* get Outlayer instance from element
* @param {Element} elem
* @returns {Outlayer}
*/
Outlayer.data = function( elem ) {
elem = utils.getQueryElement( elem );
var id = elem && elem.outlayerGUID;
return id && instances[ id ];
};
 
 
// -------------------------- create Outlayer class -------------------------- //
 
/**
* create a layout class
* @param {String} namespace
*/
Outlayer.create = function( namespace, options ) {
// sub-class Outlayer
var Layout = subclass( Outlayer );
// apply new options and compatOptions
Layout.defaults = utils.extend( {}, Outlayer.defaults );
utils.extend( Layout.defaults, options );
Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions );
 
Layout.namespace = namespace;
 
Layout.data = Outlayer.data;
 
// sub-class Item
Layout.Item = subclass( Item );
 
// -------------------------- declarative -------------------------- //
 
utils.htmlInit( Layout, namespace );
 
// -------------------------- jQuery bridge -------------------------- //
 
// make into jQuery plugin
if ( jQuery && jQuery.bridget ) {
jQuery.bridget( namespace, Layout );
}
 
return Layout;
};
 
function subclass( Parent ) {
function SubClass() {
Parent.apply( this, arguments );
}
 
SubClass.prototype = Object.create( Parent.prototype );
SubClass.prototype.constructor = SubClass;
 
return SubClass;
}
 
// ----- helpers ----- //
 
// how many milliseconds are in each unit
var msUnits = {
ms: 1,
s: 1000
};
 
// munge time-like parameter into millisecond number
// '0.4s' -> 40
function getMilliseconds( time ) {
if ( typeof time == 'number' ) {
return time;
}
var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
var num = matches && matches[1];
var unit = matches && matches[2];
if ( !num.length ) {
return 0;
}
num = parseFloat( num );
var mult = msUnits[ unit ] || 1;
return num * mult;
}
 
// ----- fin ----- //
 
// back in global
Outlayer.Item = Item;
 
return Outlayer;
 
}));
 
/*!
* Masonry v4.2.2
* Cascading grid layout library
* https://masonry.desandro.com
* MIT License
* by David DeSandro
*/
 
( function( window, factory ) {
// universal module definition
/* jshint strict: false */ /*globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
// AMD
define( [
'outlayer/outlayer',
'get-size/get-size'
],
factory );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
require('outlayer'),
require('get-size')
);
} else {
// browser global
window.Masonry = factory(
window.Outlayer,
window.getSize
);
}
 
}( window, function factory( Outlayer, getSize ) {
 
 
 
// -------------------------- masonryDefinition -------------------------- //
 
// create an Outlayer layout class
var Masonry = Outlayer.create('masonry');
// isFitWidth -> fitWidth
Masonry.compatOptions.fitWidth = 'isFitWidth';
 
var proto = Masonry.prototype;
 
proto._resetLayout = function() {
this.getSize();
this._getMeasurement( 'columnWidth', 'outerWidth' );
this._getMeasurement( 'gutter', 'outerWidth' );
this.measureColumns();
 
// reset column Y
this.colYs = [];
for ( var i=0; i < this.cols; i++ ) {
this.colYs.push( 0 );
}
 
this.maxY = 0;
this.horizontalColIndex = 0;
};
 
proto.measureColumns = function() {
this.getContainerWidth();
// if columnWidth is 0, default to outerWidth of first item
if ( !this.columnWidth ) {
var firstItem = this.items[0];
var firstItemElem = firstItem && firstItem.element;
// columnWidth fall back to item of first element
this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
// if first elem has no width, default to size of container
this.containerWidth;
}
 
var columnWidth = this.columnWidth += this.gutter;
 
// calculate columns
var containerWidth = this.containerWidth + this.gutter;
var cols = containerWidth / columnWidth;
// fix rounding errors, typically with gutters
var excess = columnWidth - containerWidth % columnWidth;
// if overshoot is less than a pixel, round up, otherwise floor it
var mathMethod = excess && excess < 1 ? 'round' : 'floor';
cols = Math[ mathMethod ]( cols );
this.cols = Math.max( cols, 1 );
};
 
proto.getContainerWidth = function() {
// container is parent if fit width
var isFitWidth = this._getOption('fitWidth');
var container = isFitWidth ? this.element.parentNode : this.element;
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var size = getSize( container );
this.containerWidth = size && size.innerWidth;
};
 
proto._getItemLayoutPosition = function( item ) {
item.getSize();
// how many columns does this brick span
var remainder = item.size.outerWidth % this.columnWidth;
var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
// round if off by 1 pixel, otherwise use ceil
var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
colSpan = Math.min( colSpan, this.cols );
// use horizontal or top column position
var colPosMethod = this.options.horizontalOrder ?
'_getHorizontalColPosition' : '_getTopColPosition';
var colPosition = this[ colPosMethod ]( colSpan, item );
// position the brick
var position = {
x: this.columnWidth * colPosition.col,
y: colPosition.y
};
// apply setHeight to necessary columns
var setHeight = colPosition.y + item.size.outerHeight;
var setMax = colSpan + colPosition.col;
for ( var i = colPosition.col; i < setMax; i++ ) {
this.colYs[i] = setHeight;
}
 
return position;
};
 
proto._getTopColPosition = function( colSpan ) {
var colGroup = this._getTopColGroup( colSpan );
// get the minimum Y value from the columns
var minimumY = Math.min.apply( Math, colGroup );
 
return {
col: colGroup.indexOf( minimumY ),
y: minimumY,
};
};
 
/**
* @param {Number} colSpan - number of columns the element spans
* @returns {Array} colGroup
*/
proto._getTopColGroup = function( colSpan ) {
if ( colSpan < 2 ) {
// if brick spans only one column, use all the column Ys
return this.colYs;
}
 
var colGroup = [];
// how many different places could this brick fit horizontally
var groupCount = this.cols + 1 - colSpan;
// for each group potential horizontal position
for ( var i = 0; i < groupCount; i++ ) {
colGroup[i] = this._getColGroupY( i, colSpan );
}
return colGroup;
};
 
proto._getColGroupY = function( col, colSpan ) {
if ( colSpan < 2 ) {
return this.colYs[ col ];
}
// make an array of colY values for that one group
var groupColYs = this.colYs.slice( col, col + colSpan );
// and get the max value of the array
return Math.max.apply( Math, groupColYs );
};
 
// get column position based on horizontal index. #873
proto._getHorizontalColPosition = function( colSpan, item ) {
var col = this.horizontalColIndex % this.cols;
var isOver = colSpan > 1 && col + colSpan > this.cols;
// shift to next row if item can't fit on current row
col = isOver ? 0 : col;
// don't let zero-size items take up space
var hasSize = item.size.outerWidth && item.size.outerHeight;
this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
 
return {
col: col,
y: this._getColGroupY( col, colSpan ),
};
};
 
proto._manageStamp = function( stamp ) {
var stampSize = getSize( stamp );
var offset = this._getElementOffset( stamp );
// get the columns that this stamp affects
var isOriginLeft = this._getOption('originLeft');
var firstX = isOriginLeft ? offset.left : offset.right;
var lastX = firstX + stampSize.outerWidth;
var firstCol = Math.floor( firstX / this.columnWidth );
firstCol = Math.max( 0, firstCol );
var lastCol = Math.floor( lastX / this.columnWidth );
// lastCol should not go over if multiple of columnWidth #425
lastCol -= lastX % this.columnWidth ? 0 : 1;
lastCol = Math.min( this.cols - 1, lastCol );
// set colYs to bottom of the stamp
 
var isOriginTop = this._getOption('originTop');
var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
stampSize.outerHeight;
for ( var i = firstCol; i <= lastCol; i++ ) {
this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
}
};
 
proto._getContainerSize = function() {
this.maxY = Math.max.apply( Math, this.colYs );
var size = {
height: this.maxY
};
 
if ( this._getOption('fitWidth') ) {
size.width = this._getContainerFitWidth();
}
 
return size;
};
 
proto._getContainerFitWidth = function() {
var unusedCols = 0;
// count unused columns
var i = this.cols;
while ( --i ) {
if ( this.colYs[i] !== 0 ) {
break;
}
unusedCols++;
}
// fit container to columns that have been used
return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
};
 
proto.needsResizeLayout = function() {
var previousWidth = this.containerWidth;
this.getContainerWidth();
return previousWidth != this.containerWidth;
};
 
return Masonry;
 
}));
 
/branches/v3.01-serpe/widget/modules/photo/squelettes/js/WidgetPhoto.js
New file
0,0 → 1,47
function WidgetPhoto( proprietes ) {
if ( this.valOk( proprietes ) ) {
this.id = proprietes.id;
this.galerieId = proprietes.galerieId;
}
}
 
WidgetPhoto.prototype = new WidgetPhotoCommun();
 
WidgetPhoto.prototype.initTpl = function() {
$('.grid').masonry({
itemSelector: '.grid-item',
columnWidth: '.grid-sizer',
gutter: 10,
percentPosition: true
});
 
};
 
WidgetPhoto.prototype.initEvts = function() {
const lthis = this;
const $thisGalerie = $( '#cel-photo-contenu' + this.id );
var url = '',
focus = $( '#print_content' );
 
$thisGalerie.on( 'click', 'a.cel-img, a.cel-img-contact', function( event ) {
event.preventDefault();
var lienImage = this.href;
 
if ( !/contact/.test( this.className ) ) {
url = '?mode=popup&url_image=' + lienImage + '&galerie_id=' + lthis.galerieId;
url += '&popup_url=' + encodeURIComponent( url );
} else {
url = lienImage;
}
lthis.chargerContenuModale( url );
});
$( '.bouton-plus-filtres', $thisGalerie ).on( 'click', function( event ) {
event.preventDefault();
$( '.autres-filtres, .plus, .moins', $thisGalerie ).toggleClass( 'hidden' );
});
$( '.bouton-fermer-filtres', $thisGalerie ).on( 'click', function( event ) {
event.preventDefault();
$( '.autres-filtres, .bouton-plus-filtres .moins', $thisGalerie ).addClass( 'hidden' );
$( '.bouton-plus-filtres .plus', $thisGalerie ).removeClass( 'hidden' );
});
};
/branches/v3.01-serpe/widget/modules/photo/squelettes/js/WidgetPhotoPopup.js
New file
0,0 → 1,685
function WidgetPhotoPopup( proprietes ) {
if( this.valOk( proprietes ) ) {
this.urlWidget = proprietes.urlWidget;
this.urls = proprietes.urls;
this.infosImages = proprietes.infosImages;
this.urlImage = proprietes.urlImage;
this.indexPremiereImage = proprietes.indexPremiereImage;
this.indexImage = this.indexPremiereImage;
this.tailleMax = proprietes.tailleMax;
this.popupUrl = proprietes.popupUrl;
this.urlBaseTelechargement = proprietes.urlBaseTelechargement;
this.urlServiceRegenererMiniature = proprietes.urlServiceRegenererMiniature;
}
 
this.mettreAJourInfosImage();
}
 
WidgetPhotoPopup.prototype = new WidgetPhotoCommun();
 
WidgetPhotoPopup.prototype.initTpl = function() {
this.redimensionnerGalerie();
$( '#info-img-galerie' ).find( '.active' ).removeClass( 'active' );
$( '#img-cadre-' + this.indexImage + ',#indicateur-img-' + this.indexImage ).addClass( 'active' );
 
this.mettreAJourPopup();
 
this.redimentionnerModaleCarousel();
};
 
WidgetPhotoPopup.prototype.initEvts = function() {
const lthis = this;
 
this.initEvtsDefilerImage();
this.initEvtsContact();
$( window ).on( 'resize', lthis.redimentionnerModaleCarousel.bind( lthis ) );
this.initEvtsFonctionsPhoto();
this.initEvtsRetourGalerieResponsive();
this.initEvtsTagsPF();
};
 
WidgetPhotoPopup.prototype.mettreAJourPopup = function() {
this.mettreAJourInfosImage();
this.afficherTitreImage();
this.traiterMetas();
this.regenererMiniature();
this.fournirLienIdentiplante();
};
 
WidgetPhotoPopup.prototype.mettreAJourInfosImage = function() {
this.item = this.infosImages[this.urls[this.indexImage]];
this.titreImage = this.item['titre'];
this.urlLienEflore = this.item['lien'];
this.idImage = this.item['id_photo'];
this.urlThisImage = this.item['url_photo']+'.jpg';
this.obs = this.item['obs'];
this.nn = '[nn' + this.obs['nom_sel_nn']+']';
this.urlIP = this.obs['url_ip'];
this.tagsImage = this.tagsToArray( this.item['tags_photo'] );
this.tagsObs = this.tagsToArray( this.obs['tags_obs'] );
this.auteur = this.item['utilisateur']['nom_utilisateur'];
this.date = this.item['date'];
};
 
WidgetPhotoPopup.prototype.tagsToArray = function( tags ) {
if(!this.valOk(tags)) {
return [];
}
tags = tags.replace( new RegExp('\\.'), '' ).split( ',' );
 
let cleanTags = [],
nbTags = tags.length,
tag = '',
tagsSansEspaces = '',
cleanTagIndex = 0;
 
for(let i = 0; i < nbTags; i++) {
tag = tags[i];
tagsSansEspaces = tag.replace( ' ', '');
if( '' !== tagsSansEspaces ) {
cleanTags.push( tag.trim() );
}
}
 
return cleanTags;
};
 
WidgetPhotoPopup.prototype.initEvtsDefilerImage = function() {
const lthis = this;
 
$( '#precedent, #suivant' ).on( 'click', function() {
lthis.defilerImage( this.id );
});
 
$( '#print_content:not(saisir-tag)' ).on( 'keydown', function( event ) {
 
const determinerSens = function( enventKey, left, right ) {
switch ( enventKey ) {
case left:
return 'suivant';
case right:
return 'precedent';
default:
break;
}
 
return;
}
 
event = (event || window.event);
// event.keyCode déprécié, on tente d'abord event.key
let sens = ( 'key' in event ) ? determinerSens( event.key, 'ArrowLeft', 'ArrowRight' ) : determinerSens( event.keyCode, 37, 39 );;
 
if ( lthis.valOk( sens ) ) {
lthis.defilerImage( sens );
}
});
};
 
WidgetPhotoPopup.prototype.initEvtsContact = function() {
const lthis = this;
 
$( '#bloc-infos-img' ).on( 'click', '.lien_contact', function( event ) {
event.preventDefault();
lthis.chargerContenuModale( this.href );
});
};
 
WidgetPhotoPopup.prototype.initEvtsFonctionsPhoto = function() {
const lthis = this;
 
$( '#boutons-footer #bloc-fct a, #retour-metas' ).on( 'click', function( event ){
event.preventDefault();
var voletAOuvrir = $( this ).data( 'volet' ),
voletAFermer = $( '.bloc-volet:not(.hidden)' ).data( 'volet' );
 
lthis.ouvrirVoletFct( voletAOuvrir, voletAFermer );
if ( window.matchMedia( '(max-width: 991px)' ).matches ) {
$( '#info-img-galerie' ).addClass( 'hidden' );
$( '#volet, #retour-galerie' ).removeClass( 'hidden' );
}
});
};
 
WidgetPhotoPopup.prototype.initEvtsRetourGalerieResponsive = function() {
$( '#retour-galerie' ).on( 'click', function( event ) {
event.preventDefault();
$( '#info-img-galerie' ).removeClass( 'hidden' );
$( this ).addClass( 'hidden' );
if ( window.matchMedia( '(max-width: 991px)' ).matches ) {
$( '#volet' ).addClass( 'hidden' );
$( '.bouton-fct.actif' ).removeClass( 'actif' );
}
});
};
 
WidgetPhotoPopup.prototype.initEvtsTagsPF = function() {
//recupérer tags en ajax (voir pictoflora, peut-être dans le php?)
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
// _GET
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
this.tagsPfCustom();
$( '#bloc-tags' ).on( 'click', '.tag', function( event ) {
event.preventDefault();
$( this ).toggleClass( 'actif' );
});
$( '#bloc-tags' ).on( 'click', '.custom-tag.actif .fermer', function( event ) {
event.preventDefault();
// Supprimer un custom-tag
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/38368
// _paramètres
// L'id du tag à la fin de l'url
// _DELETE
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/38368
// _réponse:
// ""
// Mettre à jour les mots cles
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
// _GET
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
$( this ).parent( '.custom-tag' ).remove();
});
 
$( '#bloc-tags' ).on( 'keyup', '.custom-tag.actif', function( event ) {
let supprimerTag = false;
 
event = ( event || window.event );
// event.keyCode déprécié, on tente d'abord event.key
if ( 'key' in event ) {
supprimerTag = ( 'Delete' === event.key || 'Backspace' === event.key );
} else {
supprimerTag = ( 46 === event.keyCode || 8 === event.keyCode );
}
if ( supprimerTag ) {
// Supprimer un custom-tag
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/38368
// _paramètres
// L'id du tag à la fin de l'url
// _DELETE
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/38368
// _réponse:
// ""
// Mettre à jour les mots cles
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
// _GET
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
$( this ).parent( '.custom-tag' ).remove();
}
});
};
 
WidgetPhotoPopup.prototype.defilerImage = function( sens ) {
if ( 'suivant' === sens ) {
this.indexImage++ ;
if( this.indexImage >= this.urls.length ) {
this.indexImage = 0;
}
} else if ( 'precedent' === sens ) {
this.indexImage--;
if( this.indexImage <= 0 ) {
this.indexImage = this.urls.length -1;
}
}
// @TODO: Modifier l'attr content de 'meta[property=og:image]' et y mettre l'url de l'image
this.mettreAJourPopup();
};
 
WidgetPhotoPopup.prototype.afficherTitreImage = function() {
let lienContact =
this.urlWidget +'?mode=contact&nn=' + this.nn +
'&nom_sci=' + this.obs['nom_sel'] +
'&date=' + this.date +
'&localisation=' + this.obs['localisation'] +
'&id_image=' + this.idImage +
'&auteur=' + this.auteur;
 
if ( this.valOk( this.popupUrl ) ) {
if (! this.popupUrl.match( new RegExp( 'img:' + this.idImage ) ) ) {
this.popupUrl = this.actualiserPopupUrl( this.popupUrl, this.urlThisImage );
}
lienContact += '&popup_url=' + encodeURIComponent( this.popupUrl );
}
 
$( '#bloc-infos-img' ).html(
this.afficherLien( this.urlLienEflore, this.obs['nom_sel'] )+
' par '+
'<a class="lien_contact" href="' + lienContact + '">' + this.auteur + '</a> '+
' le ' + this.date + ' - ' + this.obs['localisation']
);
};
 
WidgetPhotoPopup.prototype.actualiserPopupUrl = function( queryString, remplacement ) {
let queryStringParsee = queryString.substring(1).split('&');
 
$.each( queryStringParsee, function( i, param ) {
if( /url_image/.test( param ) ) {
queryString = queryString.replace( param, 'url_image=' + remplacement );
return false;
}
});
return queryString;
};
 
WidgetPhotoPopup.prototype.redimentionnerModaleCarousel = function() {
this.redimensionnerGalerie();
if ( window.matchMedia( '(max-width: 991px)' ).matches ) {
$( '#volet, #retour-galerie' ).addClass( 'hidden' );
$( '#info-img-galerie' ).removeClass( 'hidden' );
$( '.bouton-fct.actif' ).removeClass( 'actif' );
$( '.nettoyage-volet.haut' ).text( $( '#bloc-infos-img' ).text() );
$( '#boutons-footer, #info-img-galerie' ).removeClass( 'col-lg-8' );
$( '#bloc-infos-img, #volet' ).removeClass( 'col-lg-4' );
} else {
$( '#volet, #info-img-galerie' ).removeClass( 'hidden' );
if ( this.valOk( $( '.bloc-volet:not(.hidden)' ) ) ) {
$( '.bouton-fct.' + $( '.bloc-volet:not(.hidden)' ).data( 'volet' ) ).addClass( 'actif' );
}
$( '.nettoyage-volet.bas' ).text( $( '#bloc-infos-img' ).text() );
$( '#boutons-footer, #info-img-galerie' ).addClass( 'col-lg-8' );
$( '#bloc-infos-img, #volet' ).addClass( 'col-lg-4' );
$( '#retour-galerie' ).addClass( 'hidden' );
}
};
 
WidgetPhotoPopup.prototype.redimensionnerGalerie = function() {
var maxSize = ( $( window ).width() / $( window ).height() ) < 1 ? $( window ).width() : $( window ).height();
 
maxSize -= 30;
$( '.carousel-item img' ).each( function( index, image ) {
var proportion = image.dataset.width / image.dataset.height,
cssResize = {};
 
if ( proportion >= 1 ) {
cssResize['width'] = maxSize;
}
if ( proportion <= 1) {
cssResize['height'] = maxSize;
}
$( image ).css( cssResize );
});
};
 
WidgetPhotoPopup.prototype.ouvrirVoletFct = function( voletAOuvrir, voletAFermer ) {
if( voletAOuvrir !== voletAFermer ) {
$( '#boutons-footer .' + voletAFermer ).removeClass( 'actif' );
$( '#boutons-footer .' + voletAOuvrir ).addClass( 'actif' );
$( '#bloc-' + voletAFermer ).addClass( 'hidden' );
$( '#bloc-' + voletAOuvrir ).removeClass( 'hidden' );
$( '#volet' ).scrollTop(0);
$( '#retour-metas' ).removeClass( 'hidden', 'meta' === voletAOuvrir );
}
};
 
WidgetPhotoPopup.prototype.tagsPfCustom = function() {
const lthis = this;
 
$( '#saisir-tag' ).on( 'blur keyup', function( event ) {
event = ( event || window.event );
 
var ajouterTag = ( 'blur' === event.type );
 
// event.keyCode déprécié, on tente d'abord event.key
if ( 'key' in event ) {
if ( 'Enter' === event.key ) {
ajouterTag = true;
}
} else if ( 13 === event.keyCode ) {
ajouterTag = true;
}
if ( ajouterTag ) {
var nouveauTag = $( this ).val(),
nouveauTagAttr = lthis.chaineValableAttributsHtml( nouveauTag.toLowerCase() );
 
if( lthis.valOk( nouveauTagAttr ) && !lthis.valOk( $( '#' + nouveauTagAttr + '.tag' ) ) ) {
// Envoyer tags en ajax :
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/
// _paramètres :
//rien
// _PUT
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles/
// _paramètres :
// image=197938&mot_cle=motcleperso&auteur.id=44084
// Mettre à jour les mots cles
// _OPTIONS
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
// _GET
// https://api-test.tela-botanica.org/service:del:0.1/mots-cles?image=197938
$( '#tags-pf-supp' ).append(
'<a id="' + nouveauTagAttr + '" class="btn tag custom-tag actif">' +
nouveauTag + '&nbsp;<i class="fas fa-times-circle fermer"></i>' +
'</a>'
);
$( '#form-tags-auteur' )[0].reset();
$( this ).val( '' );
}
}
});
};
 
WidgetPhotoPopup.prototype.traiterMetas = function() {
this.afficherMetas();
this.afficherPopupLocalisation();
this.afficherMetasPlus();
this.fournirLienTelechargement();
};
 
WidgetPhotoPopup.prototype.afficherMetas = function() {
const lthis = this;
const META_CONTENUS = {
'nom' : this.afficherLien( this.urlLienEflore, this.obs['nom_sel'] ),
'localisation' : this.obs['localisation'],
'auteur' : this.auteur,
'date-obs' : this.date,
'commentaire' : this.obs['commentaire'],
'certitude' : this.obs['certitude'],
'fiabilite' : this.obs['fiabilite'],
'num-photo' : this.idImage,
'titre-original' : this.item['nom_original'],
'date-photo' : this.formaterDate( this.item['date_photo'] ),
'attribution-copy' : this.item['attribution'],
'url-copy' : this.urlThisImage
};
 
$.each( META_CONTENUS, function( attrId, contenu ) {
let $metaContainer = $( '#bloc-meta #'+attrId );
 
if ( lthis.valOk( contenu ) ) {
switch( attrId ) {
case 'attribution-copy' :
case 'url-copy' :
$metaContainer.val( contenu );
lthis.copieAutoChamp( $metaContainer );
break;
case 'nom' :
$( '.contenu', $metaContainer ).html( contenu );
$( '.bouton', $metaContainer ).attr( 'href', lthis.urlLienEflore );
break;
case 'auteur' :
$( '.bouton', $metaContainer ).attr( 'href', lthis.item['urlProfil'] );
default:
$( '.contenu', $metaContainer ).text( contenu );
break;
}
}
});
};
 
WidgetPhotoPopup.prototype.copieAutoChamp = function( $champACopier ) {
$champACopier.off( 'click' ).on( 'click', function() {
$( '#attribution-copy, #url-copy' ).removeClass( 'hidden' )
.find( '.copy-message' ).remove();
 
$( this ).select();
document.execCommand( 'copy' );
 
$( this ).after(
'<p class="copy-message alert-success" style="width: 100%; height:' + $( this ).outerHeight() + 'px; margin: 0; display:flex;">'+
'<span style="margin:auto; font-size:1rem;">Copié dans le presse papier</span>'+
'</p>'
).addClass( 'hidden' );
 
setTimeout( function() {
$( '.copy-message' ).remove();
$champACopier.removeClass( 'hidden' );
}, 1000 );
});
};
 
WidgetPhotoPopup.prototype.afficherMetasPlus = function() {
const lthis = this;
const META_LABELS = {
'id_obs' : 'observation n°',
'projet' : 'projet',
'nom_referentiel' : 'réferentiel',
'date_obs' : 'date d´observation',
'nom_sel': 'nom scientifique',
'nom_sel_nn' : 'nom scientifique n°',
'nom_ret' : 'nom retenu',
'nom_ret_nn' : 'nom retenu n°',
'famille' : 'famille',
'tags_obs' : 'tags de l´observation',
'lieudit' : 'lieu dit',
'station' : 'station',
'milieu' : 'milieu',
'latitude' : 'latitude',
'longitude' : 'longitude',
'altitude' : 'altitude',
'localisation_precision': 'précision de la localisation',
'code_insee' : 'code insee de la commune',
'dept' : 'département',
'pays' : 'pays',
'est_ip_valide' : 'validée sur identiplante',
'score_ip' : 'score identiplante',
'url_ip' : 'url identiplante',
'abondance' : 'abondance',
'phenologie' : 'phénologie',
'spontaneite' : 'spontaneite',
'type_donnees' : 'type de donnees',
'biblio' : 'bibliographie',
'source' : 'source',
'herbier' : 'herbier',
'observateur' : 'observateur',
'observateur_structure' : 'structure'
};
 
const $contenuPlusMeta = $( '#contenu-meta-plus' );
let degres = $contenuPlusMeta.is( ':visible' ) ? '180' : '0';
 
this.rotationFleche( degres );
$contenuPlusMeta.empty();
 
$.each( META_LABELS, function( cle, label ) {
let idAttr = cle.replace( '_', '-' ),
contenu = lthis.obs[cle];
 
switch( cle ) {
case 'nom_sel':
contenu = lthis.afficherLien( lthis.urlLienEflore, contenu );
break;
 
case 'nom_ret':
let urlEfloreNomRetenu = lthis.urlLienEflore.replace( lthis.obs['nom_sel_nn'], lthis.obs['nom_ret_nn'] );
 
contenu = lthis.afficherLien( urlEfloreNomRetenu, contenu );
break;
 
case 'url_ip':
contenu = lthis.afficherLien( contenu, contenu );
break;
 
case 'est_ip_valide':
case 'herbier':
if( '0' === contenu ) {
contenu = 'non';
}
break;
 
case 'date_obs':
contenu = lthis.formaterDate( contenu );
break;
 
case 'tags_obs':
let tagsObsLength = lthis.tagsObs.length;
contenu = lthis.tagsObs.join( '<br>' );
break;
 
default:
break;
}
 
if ( lthis.valOk( contenu ) ) {
$contenuPlusMeta.append(
'<li id="' + idAttr + '-meta-plus" class="row">'+
'<div class="col-5 label">' + label.charAt( 0 ).toUpperCase() + label.slice( 1 ) + '</div>'+
'<div class="col-7 contenu">' + contenu + '</div>'+
'</li>'
);
}
});
 
if( !$contenuPlusMeta.hasClass( 'actif' ) ) {
$contenuPlusMeta.hide();
}
 
let estVisible = false;
 
$( '#plus-meta' ).off( 'click' ).on( 'click', function( event ) {
event.preventDefault();
$contenuPlusMeta.toggle( 200, function() {
estVisible = $contenuPlusMeta.is( ':visible' );
degres = estVisible ? '180' : '0';
$( this ).toggleClass( 'actif', estVisible );
lthis.rotationFleche( degres );
});
});
};
 
WidgetPhotoPopup.prototype.rotationFleche = function( degres ) {
$( '#plus-meta i' ).css({
'-webkit-transform' : 'rotate('+ degres +'deg)',
'-moz-transform' : 'rotate('+ degres +'deg)',
'-ms-transform' : 'rotate('+ degres +'deg)',
'transform' : 'rotate('+ degres +'deg)'
});
};
 
WidgetPhotoPopup.prototype.fournirLienTelechargement = function() {
const lthis = this;
 
$( '#formats' ).on( 'change', function() {
let format = ( $( this ).val() || 'O' ),
lienTelechargement = lthis.urlBaseTelechargement + lthis.idImage + '?methode=telecharger&format=' + format;
 
$( '#telecharger' ).attr( 'href', lienTelechargement );
});
 
$( '#formats' ).trigger( 'change' );
};
 
 
WidgetPhotoPopup.prototype.afficherPopupLocalisation = function() {
const lthis = this;
 
$( '#localisation a.bouton' ).on( 'click', function( event ){
event.preventDefault();
 
$( this ).after(
'<div id="localisation-map-container">'+
'<button id="map-close" type="button" class="bouton btn btn-sm btn-outline-secondary" aria-label="Close">'+
'<span aria-hidden="true">×</span>'+
'</button>'+
'<div id="localisation-map"></div>'+
'</div>'
);
 
let lat = lthis.obs['latitude'],
lng = lthis.obs['longitude'],
map = L.map( 'localisation-map', {
zoomControl: true,
dragging: false,
scrollWheelZoom: 'center'
} ).setView( [lat, lng], 12 );
 
map.markers = [];
 
L.tileLayer(
'https://osm.tela-botanica.org/tuiles/osmfr/{z}/{x}/{y}.png',
{
attribution: 'Data © <a href="http://osm.org/copyright">OpenStreetMap</a>',
maxZoom: 18
}
).addTo( map );
 
map.addLayer( new L.FeatureGroup() );
 
let marker = new L.Marker(
{
'lat': lat,
'lng': lng
},
{
draggable: false,
}
);
 
 
map.addLayer( marker );
map.markers.push( marker );
 
$( '#map-close' ).on( 'click', function( event ){
$( '#localisation-map-container' ).remove();
});
});
 
$( '#fenetre-modal' ).on( 'click', function( event ) {
if(
!$( event.target ).closest( '#localisation-map-container' ).length
&& !$( event.target ).closest( '#obs-localisation' ).length
) {
$( '#localisation-map-container' ).remove();
}
});
};
 
 
WidgetPhotoPopup.prototype.regenererMiniature = function() {
const lthis = this;
$( '#regenerer-miniature' ).off( 'click' ).on( 'click', function( event ) {
event.preventDefault();
 
let url = lthis.urlServiceRegenererMiniature + lthis.idImage;
 
$.get( url, function( data ) {
console.log( data );
}
).fail( function() {
console.log( 'La régénérétion d´image ne s´est pas faite' );
});
});
};
 
WidgetPhotoPopup.prototype.formaterDate = function( sqlDate ) {
dateFormatee = sqlDate
.substring( 0, 10 )
.split( '-' )
.reverse()
.join('/');
 
return dateFormatee;
};
 
WidgetPhotoPopup.prototype.afficherLien = function( url, nom ) {
if( !/https?:\/\//.test( url ) ) {
url = 'https://' + url;
}
return '<a href="' + url + '" target="_blank">' + nom + '</a> ';
};
 
WidgetPhotoPopup.prototype.fournirLienIdentiplante = function() {
const lthis = this;
$( '.signaler-erreur-obs' ).each( function() {
$( this ).attr( 'href', lthis.urlIP );
});
};
 
// WidgetPhotoPopup.prototype.afficherTags = function() {
// const lthis = this;
// const TAGS_BASE = [
// 'port',
// 'fleur',
// 'fruit',
// 'feuille',
// 'ecorce',
// 'rameau',
// 'planche',
// 'insecte'
// ];
 
// };
/branches/v3.01-serpe/widget/modules/photo/squelettes/js/WidgetPhotoContact.js
New file
0,0 → 1,158
function WidgetPhotoContact () {}
 
WidgetPhotoContact.prototype = new WidgetPhotoCommun();
 
WidgetPhotoContact.prototype.initTpl = function() {
$( '#form-contact' ).validate({
rules: {
fc_sujet : 'required',
fc_message : 'required',
fc_utilisateur_courriel : {
required : true,
email : true
}
}
});
};
 
WidgetPhotoContact.prototype.initEvts = function() {
const lthis = this;
 
$( '#form-contact' ).on( 'submit', function( event ) {
event.preventDefault();
lthis.envoyerCourriel();
});
this.initEvtsRetourPopupPhoto();
};
 
WidgetPhotoContact.prototype.initEvtsRetourPopupPhoto = function() {
const lthis = this;
 
$( '#fc_annuler.popup_url' ).on( 'click', function( event ) {
event.preventDefault();
lthis.retourPopupPhoto();
});
$( '#fc_annuler.popup_url' ).on( 'keydown', function( event ) {
var isEnter = false;
 
event = event || window.event;
// event.keyCode déprécié, on tente d'abord event.key
if ( 'key' in event) {
isEnter = ( event.key === 'Enter' );
} else {
isEnter = ( event.keyCode === 13 );
}
if ( isEnter ) {
lthis.retourPopupPhoto();
}
});
$( 'body' ).on( 'keyup', function( event ) {
if( $( '#fenetre-modal' ).hasClass( 'show' ) ) {
var isEscape = false;
 
event = event || window.event;
// event.keyCode déprécié, on tente d'abord event.key
if ( 'key' in event) {
isEscape = ( event.key === 'Escape' || event.key === 'Esc' );
} else {
isEscape = ( event.keyCode === 27 );
}
if ( isEscape ) {
lthis.retourPopupPhoto();
}
}
});
};
 
WidgetPhotoContact.prototype.envoyerCourriel = function() {
const lthis = this;
var donnees = [];
 
if ( $( '#form-contact' ).valid() ) {
var destinataireId = $( '#fc_destinataire_id' ).val(),
typeEnvoi = $( '#fc_type_envoi' ).val(),
// l'envoi aux non inscrits passe par le service intermédiaire du cel
// qui va récupérer le courriel associé à l'image indiquée
urlMessage = 'http://api.tela-botanica.org/service:cel:celMessage/image/' + destinataireId,
erreurMsg = '';
 
$.each( $( '#form-contact' ).serializeArray(), function ( index, champ ) {
var cle = champ.name;
 
cle = cle.replace( /^fc_/, '' );
if ( cle === 'sujet' ) {
champ.value += ' - Carnet en ligne - Tela Botanica';
}
if ( cle === 'message' ) {
champ.value +=
"\n--\n" +
"Ce message vous est envoyé par l'intermédiaire du widget photo " +
"du Carnet en Ligne du réseau Tela Botanica.\n" +
"http://www.tela-botanica.org/widget:cel:photo";
}
donnees[index] = {
'name' : cle,
'value': champ.value
};
});
$.ajax({
type : "POST",
cache : false,
url : urlMessage,
data : donnees,
beforeSend : function() {
$( '.msg' ).remove();
},
success : function( data ) {
$( '#fc-zone-dialogue' ).append( '<pre class="msg info">' + data.message + '</pre>' );
},
error : function( jqXHR, textStatus, errorThrown ) {
erreurMsg += "Erreur Ajax :\ntype : " + textStatus + ' ' + errorThrown + "\n";
reponse = jQuery.parseJSON( jqXHR.responseText );
if ( lthis.valOk( reponse ) ) {
$.each( reponse, function ( cle, valeur ) {
erreurMsg += valeur + "\n";
});
}
},
complete : function( jqXHR, textStatus ) {
var debugMsg = '';
if ( lthis.valOk( jqXHR.getResponseHeader( "X-DebugJrest-Data" ) ) ) {
debugInfos = jQuery.parseJSON( jqXHR.getResponseHeader( "X-DebugJrest-Data" ) );
if ( lthis.valOk( debugInfos ) ) {
$.each( debugInfos, function ( cle, valeur ) {
debugMsg += valeur + "\n";
});
}
}
if ( lthis.valOk( erreurMsg ) ) {
$( '#fc-zone-dialogue' ).append(
'<p class="msg">' +
'Une erreur est survenue lors de la transmission de votre message.<br>' +
'Vous pouvez signaler le disfonctionnement à '+
'<a '+
'href="mailto:cel-remarques@tela-botanica.org?'+
'subject=Disfonctionnement du widget carto'+
"&body=" + erreurMsg + "\nDébogage :\n" + debugMsg+
'"' +
'>'+
'cel-remarques@tela-botanica.org'+
'</a>'+
'.'+
'</p>'
);
}
}
});
}
return false;
};
 
 
WidgetPhotoContact.prototype.retourPopupPhoto = function() {
const lthis = this;
var popup_url = $( '#fc_annuler.popup_url' ).data( 'popup_url' );
if ( lthis.valOk( popup_url ) ) {
lthis.chargerContenuModale( popup_url );
}
};
/branches/v3.01-serpe/widget/modules/photo/squelettes/popup_nl.tpl.html
New file
0,0 → 1,145
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="<?=$url_css?>popup.css" media="screen" />
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/1.6/jquery-1.6.min.js"></script>
</head>
<body>
<script type="text/javascript">
//<![CDATA[
var urls = [<?= '"'.implode($urls, '","').'"'; ?>];
var infos_images = <?= json_encode($infos_images); ?>;
var indexImage = 0;
var urlImage = "<?= $url_image; ?>";
var tailleMax = 580;
 
function redimensionnerImage(objet) {
 
objet.removeAttr("width");
objet.removeAttr("height");
 
var hauteurImage = objet.height();
var largeurImage = objet.width();
var rapport = 1;
if(hauteurImage > largeurImage && hauteurImage > tailleMax) {
rapport = largeurImage/hauteurImage;
hauteurImage = 580;
 
largeurImage = hauteurImage*rapport;
$('#illustration').attr("height", hauteurImage);
$('#illustration').attr("width", largeurImage);
}
hauteurFleches = ((hauteurImage+90)/2);
$('#info-img-galerie .conteneur-precedent').attr("top", hauteurFleches);
$('#info-img-galerie .conteneur-suivant').attr("top", hauteurFleches);
 
window.resizeTo(largeurImage+120,hauteurImage+120);
}
 
function imageSuivante() {
indexImage++;
if(indexImage >= urls.length) {
indexImage = 0;
}
afficherTitreImage();
$('#illustration').attr('src', urls[indexImage]);
}
 
function imagePrecedente() {
indexImage--;
if(indexImage <= 0) {
indexImage = urls.length - 1;
}
afficherTitreImage();
$('#illustration').attr('src', urls[indexImage]);
}
 
function afficherTitreImage() {
item = infos_images[urls[indexImage]];
var titre = item['titre'];
var infos = decouperTitre(titre);
var lienContact = '<?= $url_widget ?>?mode=contact&nn='+infos.nn+
'&nom_sci='+infos.nom_sci+
'&date='+infos.date+
'&id_image='+item['guid'];
titre = '<a href="'+item['lien']+'">'+infos.nom_sci+'</a> '+
' door <a class="lien_contact" href="'+lienContact+'">'+infos.auteur+'</a> '+
' op '+infos.date+' ';
$('#bloc-infos-img').html(titre);
}
 
function decouperTitre(titre) {
var tab_titre = titre.split('[nn');
var nom_sci = tab_titre[0];
var tab_titre_suite = tab_titre[1].split(' door ');
var nn = '[nn'+tab_titre_suite[0];
var tab_titre_fin = tab_titre_suite[1].split(' op ');
var utilisateur = tab_titre_fin[0];
var date = tab_titre_fin[1];
 
var titre_decoupe = {'nom_sci' : nom_sci, 'nn' : nn, 'date' : date, 'auteur' : utilisateur};
return titre_decoupe;
}
 
function ouvrirFenetreContact(lienImage) {
var url = lienImage.attr("href");
window.open(url, '_blank', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no, width='+(400)+', height='+(550));
}
 
$(document).ready(function() {
$('#precedent').click(function() {
imagePrecedente();
});
 
$('#suivant').click(function() {
imageSuivante();
});
 
if(urlImage != "null" && urlImage != "") {
indexImage = Array.indexOf(urls, urlImage);
$('#illustration').attr('src', urls[indexImage]);
afficherTitreImage();
}
 
$('#illustration').load(function() {
redimensionnerImage($(this));
});
 
$("body").keydown(function(e) {
if(e.keyCode == 37) { // gauche
imagePrecedente();
}
else if(e.keyCode == 39) { // droite
imageSuivante();
}
});
 
$('.lien_contact').live('click', function(event) {
event.preventDefault();
ouvrirFenetreContact($(this));
});
});
//]]>
</script>
 
<div id="info-img-galerie">
<div class="conteneur-precedent">
<a id="precedent" href="#" title="Klik hier of maak gebruik van het pijltje naar links om de vorige afbeelding weer te geven">
<img style="border:none" src="https://www.tela-botanica.org/sites/commun/generique/images/flecheGauche.jpg" alt="&lt;" />
</a>
</div>
<div class="img-cadre">
<img id="illustration" src="<?=$urls[0]?>" alt="" /><br />
</div>
<div class="conteneur-suivant">
<a id="suivant" href="#" title="Klik hier of maak gebruik van het pijltje naar rechts om de volgende afbeelding weer te geven">
<img style="border:none" src="https://www.tela-botanica.org/sites/commun/generique/images/flecheDroite.jpg" alt="&gt;" />
</a>
</div>
<hr class="nettoyage" />
<div id="bloc-infos-img"></div>
</div>
</body>
</html>
/branches/v3.01-serpe/widget/modules/photo/squelettes/photo_retrocompatibilite_ajax.tpl.html
New file
0,0 → 1,8
<!-- Retrocompatibilité avec l'ancien mode ajax-->
<script type="text/javascript">
function resizeIframe(iframe) {
iframe.height = (iframe.contentWindow.document.body.scrollHeight+20)+'px';
window.requestAnimationFrame(() => resizeIframe(iframe));
}
</script>
<iframe id="ajax-widget-photo<?php echo $id;?>" src="<?php echo $url_widget; ?>" onload="resizeIframe(this);" frameBorder="0" style="width: 100%;"></iframe>
/branches/v3.01-serpe/widget/modules/photo/squelettes/photo_nl.tpl.html
New file
0,0 → 1,208
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Publieke foto's CEL - Tela Botanica</title>
 
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-style-type" content="text/css" />
<meta http-equiv="Content-script-type" content="text/javascript" />
<meta http-equiv="Content-language" content="fr" />
 
<meta name="revisit-after" content="15 days" />
<meta name="robots" content="index,follow" />
<meta name="author" content="Tela Botanica" />
<meta name="keywords" content="Tela Botanica, foto, CEL" />
<meta name="description" content="Presentatiewidget van de meest recente foto’s die op de ‘Carnet en Ligne’ van Tela Botanica werden gepubliceerd" />
 
<!-- OpenGraph pour Facebook, Pinterest, Google+ -->
<meta property="og:type" content="website" />
<meta property="og:title" content="Widgetfoto CeL" />
<meta property="og:site_name" content="Tela Botanica" />
<meta property="og:description" content="Minifotoreeks publieke waarnemingen van de ‘Carnet en Ligne’" />
<?php
if (isset($items[0])) {
$iz = $items[0];
$izUrl = sprintf($iz['url_tpl'], 'CRS');
echo '<meta property="og:image" content="' . $izUrl . '" />';
} else {
echo '<meta property="og:image" content="https://resources.tela-botanica.org/tb/img/256x256/carre_englobant.png" />'
.'<meta property="og:image:type" content="image/png" />'
.'<meta property="og:image:width" content="256" />'
.'<meta property="og:image:height" content="256" />';
}
?>
<meta property="og:locale" content="fr_FR" />
 
<!-- Spécial mobile -->
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
 
<!-- Favicones -->
<link rel="icon" type="image/png" href="https://resources.tela-botanica.org/tb/img/16x16/favicon.png" />
<link rel="shortcut icon" type="image/x-icon" href="https://resources.tela-botanica.org/tb/img/16x16/favicon.ico" />
 
<!-- Feuilles de styles -->
<link rel="stylesheet" type="text/css" href="https://www.tela-botanica.org/commun/jquery/fancybox/1.3.4/jquery.fancybox-1.3.4.css" media="screen" />
<link rel="stylesheet" type="text/css" href="<?=$url_css?>photo.css" media="screen" />
<style type="text/css">
html {
overflow:hidden;
}
body{
overflow:hidden;
padding:0;
margin:0;
width:100%;
height:100%;
background-color:#DDDDDD;
color:black;
}
#cel-photo-contenu<?=$id?>, #cel-galerie-photo<?=$id?>{
width:<?=(($colonne * 69))?>px;
}
#cel-galerie-photo<?=$id?> #cel-photo-extra<?=$id?> img{
width:<?=(($colonne * 69)-6)?>px;
}
</style>
 
<!-- Javascript : bibliothèques -->
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/1.6/jquery-1.6.min.js"></script>
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/fancybox/1.3.4/jquery.fancybox-1.3.4.js"></script>
 
<!-- Google Analytics -->
<?php if($prod): ?>
<?php include "analytics.html"; ?>
<?php endif; ?>
</head>
<body>
<!-- WIDGET:CEL:PHOTO - DEBUT -->
<div id="cel-photo-contenu<?=$id?>" class="cel-photo-contenu">
<?php if (isset($erreurs) || isset($informations)) : ?>
<h1>Fouten en informatie</h1>
<p>Kan flow niet weergeven</p>
<!-- Affichage des erreurs et messages d'information : -->
<?php if ($erreurs) : ?>
<?php foreach ($erreurs as $erreur) : ?>
<p class="erreur"><?=$erreur;?></p>
<?php endforeach; ?>
<?php endif; ?>
 
<?php if ($informations) : ?>
<?php foreach ($informations as $information) : ?>
<p class="info"><?=$information;?></p>
<?php endforeach; ?>
<?php endif; ?>
<?php else : ?>
<h1>
<? if (!empty($titre)) : ?>
<?=$titre?>
<? endif ; ?>
<? if($icone_rss) : ?>
<a href="<?=$flux_rss_url?>"
class="cel-photo-flux"
title="Afbeeldingen volgen"
onclick="window.open(this.href);return false;">
<img src="https://www.tela-botanica.org/sites/commun/generique/images/rss.png" alt="Afbeeldingen volgen" />
</a>
<? endif; ?>
</h1>
<div id="cel-galerie-photo<?=$id?>">
<?php foreach ($items as $item) : ?>
<div class="cel-photo">
<a href="<?=sprintf($item['url_tpl'], 'XL')?>" class="cel-img" title="<?=$item['titre']?> - Gepubliceerd op <?=$item['date']?> - GUID : <?=$item['guid']?>" rel="galerie-princ<?=$id?>">
<img src="<?=sprintf($item['url_tpl'], 'CRX2S')?>" alt="<?=$item['titre']?>"/>
</a>
<div id="cel-info-<?=$item['guid']?>" class="cel-infos">
<strong>
<?php if ($item['eflore_url'] != '#' && $item['eflore_url'] != '') { ?>
<a class="cel-img-titre" href="<?=$item['eflore_url']?>"
onclick="window.open(this.href);return false;"
title="Klik hier om toegang te krijgen tot de eFlore fiche">
<?=$item['infos']['nom_sci']?>
</a> door
<a class="cel-img-contact"
href="?mode=contact&nn=<?= urlencode($item['infos']['nn']) ;?>&nom_sci=<?= urlencode($item['infos']['nom_sci']) ;?>&date=<?= urlencode($item['infos']['date']) ;?>&id_image=<?= $item['guid']; ?>&lang=nl"
title="Klik hier om contact op te nemen met de auteur van de foto">
<?=$item['infos']['auteur']?>
</a>
te <?= $item['infos']['localite'] ?>
op <?=$item['infos']['date']?>
<?php } else { ?>
<?=$item['titre']?>
<?php } ?>
</strong><br />
<span class="cel-img-date">Gepubliceerd op <?=$item['date']?></span>
</div>
</div>
<?php endforeach; ?>
<?php if ($extra_actif) : ?>
<div id="cel-photo-extra<?=$id?>" class="cel-photo-extra cel-photo">
<a href="<?=sprintf($extra['url_tpl'], 'XL')?>" class="cel-img" title="<?=$extra['titre']?> - Gepubliceerd op <?=$extra['date']?> - GUID : <?=$extra['guid']?>" rel="galerie-princ<?=$id?>">
<img src="<?=sprintf($extra['url_tpl'], 'CRS')?>" alt="<?=$extra['titre']?>"/>
</a>
</div>
</div>
<?php endif ?>
<p class="cel-photo-pieds discretion nettoyage">
<span class="cel-photo-source">
Bron :
<a href="http://www.tela-botanica.org/page:cel" title="Carnet en Ligne" onclick="window.open(this.href);return false;">
CEL
</a>
</span>
<span class="cel-photo-date-generation">Au <?=strftime('%A %d %B %Y te %H:%M:%S')?></span>
</p>
<script type="text/Javascript">
//<![CDATA[
var utiliseFancybox = "<?= $utilise_fancybox; ?>";
if(utiliseFancybox) {
$('a.cel-img').attr('rel', 'galerie-princ<?=$id?>').fancybox({
transitionIn:'elastic',
transitionOut:'elastic',
speedIn :600,
speedOut:200,
overlayShow:true,
titleShow:true,
titlePosition:'inside',
titleFormat:function (titre, currentArray, currentIndex, currentOpts) {
var motif = /GUID : ([0-9]+)$/;
motif.exec(titre);
var guid = RegExp.$1;
var info = $('#cel-info-'+guid).clone().html();
var tpl =
'<div class="cel-legende">'+
'<p class="cel-legende-vei">'+'Beeld nr.' + (currentIndex + 1) + ' op ' + currentArray.length +'<\/p>'+
(titre && titre.length ? '<p>'+info+'<\/p>' : '' )+
'<\/div>';
return tpl;
}
});
} else {
$('a.cel-img').click(function(event) {
ouvrirFenetrePopup($(this));
event.preventDefault();
});
}
 
$(document).ready(function() {
$('a.cel-img-contact').live('click', function(event) {
event.preventDefault();
ouvrirFenetreContact($(this));
});
});
 
function ouvrirFenetrePopup(lienImage) {
var url = "?mode=popup&url_image="+lienImage.attr('href')+'&galerie_id=<?= $galerie_id ?>';
window.open(url, '', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no, width='+(700)+', height='+(650));
}
 
function ouvrirFenetreContact(lienImage) {
var url = lienImage.attr("href");
window.open(url, '_blank', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no, width='+(400)+', height='+(550));
}
//]]>
</script>
<?php endif; ?>
</div>
<!-- WIDGET:CEL:PHOTO - FIN -->
</body>
</html>
/branches/v3.01-serpe/widget/modules/photo/squelettes/popup.tpl.html
New file
0,0 → 1,314
<div id="bloc-infos-img"></div>
<div id="volet" class="col-lg-4 col-12">
<div id="volets-fct">
<a id="retour-metas" class="btn hidden" data-volet="meta"><i class="fas fa-info-circle"></i>&nbsp;<i class="fas fa-angle-double-left"></i></a>
<div class="nettoyage-volet haut"></div>
<div id="bloc-tags" class="bloc-volet tags hidden todo" data-volet="tags">
<h2>Tags</h2>
<h3>Tags CEL (propres à l'auteur)</h3>
<form id="form-tags-auteur">
<input type="text" name="null" id="tags-auteur" placeholder="Aucun tag ajouté par l'auteur de l'observation" disabled>
</form>
<h3>Tags Pictoflora</h3>
<div id="tags-pf">
<a id="port" class="btn tag">Port</a><!--
--><a id="fleur" class="btn tag">Fleur</a><!--
--><a id="fruit" class="btn tag">Fruit</a><!--
--><a id="feuille" class="btn tag">Feuille</a><!--
--><a id="ecorce" class="btn tag">Ecorce</a><!--
--><a id="rameau" class="btn tag">Rameau</a><!--
--><a id="planche" class="btn tag">Planche</a><!--
--><a id="insecte" class="btn tag">Insecte</a>
</div>
<label for="saisir-tag">Saisir un tag</label>
<input type="text" class="form-control" id="saisir-tag" name="saisir-tag">
<div id="tags-pf-supp"></div>
<a id="signaler-photo" class="btn btn-sm btn-warning"><i class="fas fa-exclamation-triangle"></i>&nbsp;Signaler une photo inappropriée</a>
<a id="signaler-erreur-id-bis" class="btn btn-sm btn-warning signaler-erreur-obs" title="Signaler une mauvaise identification ou en proposer une autre via l'outil identiplante" target="_blank"><i class="fas fa-exclamation-triangle"></i>&nbsp;Signaler une erreur d'identification</a>
</div>
<div id="bloc-noter" class="bloc-volet noter hidden todo" data-volet="noter">
<h2>Protocoles</h2>
<select name="protocole" id="protocole" class="form-control custom-select">
<option value="" selected hidden>Choix du protocole</option>
<option id="capitalisation_image" value="capitalisation_image">Capitalisation d'images</option>
<option id="aide_identification" value="aide_identification">Aide à l'identification</option>
<option id="defi_photo" value="defi_photo">Défi photo</option>
<option id="gentiane_azure" value="gentiane_azure">Enquête Gentiane-azuré</option>
<option id="arbres_tetards" value="arbres_tetards">Arbres têtards</option>
</select>
<p id="message-protocole" class="message">
Choisissez un protocole pour pouvoir noter la photo
<!-- le message change en fonction du protocole -->
</p>
<div id="bloc-notes-protocole" class="hidden">
<ul id="notes-protocole-fct">
<li id="plus-infos-protocole" class="row">
<div class="col-10 label">Plus d'infos sur le wiki</div>
<a class="bouton btn btn-sm btn-outline-secondary" target="_blank"><i class="fas fa-question-circle"></i></a>
</li>
<li id="note">
<div class="col-5 label">Notez</div>
<div class="col-5 contenu"><!-- étoiles --></div>
<a class="bouton btn btn-sm btn-outline-secondary"><i class="fas fa-backspace"></i></a>
</li>
<li id="note-moyenne">
<div class="col-5 label">Note Moyenne</div>
<div class="col-5 contenu" style="text-align:right;"></div>
</li>
<li id="note">
<div class="col-5 label">Nombre de votes</div>
<div class="col-5 contenu" style="text-align:right;"></div>
</li>
</ul>
</div>
</div>
<div id="bloc-signaler" class="bloc-volet signaler hidden todo" data-volet="signaler">
<h2>Signaler</h2>
<h3>Signaler une photo inappropriée</h3>
<p id="message-signaler" class="message">
En signalant cette photo vous participez à la qualification des données d'observation botaniques. Les photos qualifiées d'inappropriées pour l'une des raison ci-dessous ne seront pas affichées parmi les autres illustrations sur eFlore, voire pourront être dépubliées.
</p>
<li id="exemple-inapproprie" class="row">
<div class="col-10 label">Exemple de photos inappropriées</div>
<a class="bouton btn btn-sm btn-outline-secondary"><i class="fas fa-question-circle"></i></a>
</li>
<li id="plus-infos-signaler" class="row">
<div class="col-10 label">Plus d'infos sur le wiki</div>
<a class="bouton btn btn-sm btn-outline-secondary" target="_blank"><i class="fas fa-question-circle"></i></a>
</li>
<form id="type-inapprorie">
<div class="list-label">
En quoi cette photo est-elle inappropriée ?
</div>
<div class="list">
<div class="form-check">
<input type="checkbox" id="non-vegetale" name="type-inapprorie" class="non-vegetale form-check-input" value="non-vegetale">
<label for="non-vegetale" class="non-vegetale form-check-label">Photo non végétale</label>
</div>
<div class="form-check">
<input type="checkbox" id="ecran" name="type-inapprorie" class="ecran form-check-input" value="ecran">
<label for="ecran" class="ecran form-check-label">Photo d'écran</label>
</div>
<div class="form-check">
<input type="checkbox" id="floue-pixelisee" name="type-inapprorie" class="floue-pixelisee form-check-input" value="floue-pixelisee">
<label for="floue-pixelisee" class="floue-pixelisee form-check-label">Photo floue ou pixelisée</label>
</div>
<div class="form-check">
<input type="checkbox" id="cultivee-pot" name="type-inapprorie" class="cultivee-pot form-check-input" value="cultivee-pot">
<label for="cultivee-pot" class="cultivee-pot form-check-label">Plante cultivée / en pot</label>
</div>
</div>
</form>
<a id="signaler-erreur-id-signaler" class="btn btn-sm btn-warning signaler-erreur-obs" title="Signaler une mauvaise identification ou en proposer une autre via l'outil identiplante" target="_blank"><i class="fas fa-exclamation-triangle"></i>&nbsp;Signaler une erreur d'identification</a>
</div>
 
 
<!-- pas pour la version 1 -->
<div id="bloc-revision" class="bloc-volet revision hidden todo" data-volet="revision">
<h2>Révision</h2>
<h3>Proposition de détermination</h3>
 
</div>
 
 
 
<div id="bloc-meta" class="bloc-volet meta" data-volet="meta">
<h2>Métadonnées</h2>
<ul id="contenu-meta">
<li id="nom" class="row">
<div class="col-5 label">Nom</div>
<div class="col-5 contenu"></div>
<a class="bouton btn btn-sm btn-outline-secondary" target="_blank"><i class="fas fa-search"></i></a>
</li>
<li id="localisation" class="row">
<div class="col-5 label">Localisation</div>
<div class="col-5 contenu"></div>
<a id="obs-localisation" class="bouton btn btn-sm btn-outline-secondary"><i class="fas fa-map-marker-alt"></i></a>
</li>
<li id="auteur" class="row">
<div class="col-5 label">Auteur</div>
<div class="col-5 contenu"></div>
<a class="bouton btn btn-sm btn-outline-secondary" target="_blank"><i class="fas fa-user"></i></a>
</li>
<li id="date-obs" class="row">
<div class="col-5 label">Date d'observation</div>
<div class="col-5 contenu"></div>
</li>
<li id="commentaire" class="row">
<div class="col-5 label">Commentaires</div>
<div class="col-5 contenu"></div>
</li>
<li id="certitude" class="row">
<div class="col-5 label">Certitude de l'identification</div>
<div class="col-5 contenu"></div>
</li>
<li id="fiabilite" class="row">
<div class="col-5 label">Grade</div>
<div class="col-5 contenu"></div>
<a class="bouton btn btn-sm btn-outline-secondary todo"><i class="fas fa-question-circle"></i></a>
</li>
</ul>
<a id="plus-meta" class="afficher-plus"><i class="fas fa-angle-down"></i>&nbsp;Afficher plus de metadonnées sur l'observation</a>
<ul id="contenu-meta-plus"></ul>
<ul id="contenu-meta-suite">
<li id="num-photo" class="row">
<div class="col-5 label">Photo n°</div>
<div class="col-5 contenu"></div>
</li>
<li id="licence" class="row">
<div class="col-5 label">Licence</div>
<div class="col-5 contenu">
<a target="_blank" href="http://creativecommons.org/licenses/by-sa/2.0/fr/">CC-BY-SA 2.0 FR</a>
</div>
</li>
</ul>
 
<a id="signaler-erreur-id" class="btn btn-sm btn-warning signaler-erreur-obs" title="Signaler une mauvaise identification ou en proposer une autre via l'outil identiplante" target="_blank" href="https://www.tela-botanica.org/appli:identiplante"><i class="fas fa-exclamation-triangle"></i>&nbsp;Signaler une erreur d'identification</a>
 
<h2>Téléchargement</h2>
<ul id="contenu-telechargement">
<li id="titre-original" class="row">
<div class="col-5 label">Titre original</div>
<div class="col-7 contenu"></div>
</li>
<li id="date-photo" class="row">
<div class="col-5 label">Date de la photo</div>
<div class="col-7 contenu"></div>
</li>
<li id="Licence-bis" class="row">
<div class="col-5 label">Licence</div>
<div class="col-7 contenu">
<a target="_blank" href="http://creativecommons.org/licenses/by-sa/2.0/fr/">CC-BY-SA 2.0 FR</a>
</div>
</li>
<li id="attribution" class="row">
<div class="col-12 label">Attribution</div>
<div class="col-12 contenu">
<input id="attribution-copy" type="text" name="attribution-copy" rows="4" class="form-control" readonly="readonly" style="width: 100%; height: 100%;">
</div>
</li>
<li id="url" class="row">
<div class="col-12 label">Url</div>
<div class="col-12 contenu">
<input id="url-copy" type="text" name="url-copy" rows="2" class="form-control" readonly="readonly" style="width: 100%; height: 100%;">
</div>
</li>
</ul>
<ul id="contenu-telechargement-suite" class="mb-0">
<li id="autres-formats" class="row">
<div class="col-12 label">Autres formats</div>
<div class="col-12 contenu">
<select name="formats" id="formats" class="form-control custom-select">
<?php foreach ($formats_description as $format => $description):?>
<option value="<?php echo $format; ?>" <?php echo $format === 'O' ? 'selected' : ''; ?>><?php echo $description; ?></option>
<?php endforeach; ?>
</select>
</div>
</li>
</ul>
<a href="" data-url-base-telechargement="<?php echo $url_base_telechargement; ?>" id="telecharger" class="btn btn-success mt-0"><i class="fas fa-upload"></i>&nbsp;Télécharger</a>
<h2 class="todo">Partagez !</h2>
<p class="message todo">
Partagez cette photo sur les réseaux sociaux
</p>
<div id="boutons-reseaux-sociaux" class="todo">
<a id="facebook" class="btn btn-outline-secondary btn-lg"><i class="fab fa-facebook-f"></i></a>
<a id="twitter" class="btn btn-outline-secondary btn-lg"><i class="fab fa-twitter"></i></a>
<a id="mail" class="btn btn-outline-secondary btn-lg"><i class="fas fa-envelope"></i></a>
</div>
</div>
<div id="bloc-modif" class="bloc-volet modif hidden" data-volet="modif">
<h2>Modifier la photo</h2>
<h3 class="todo">Faire pivoter la photo</h3>
<div id="pivoter-photo" class="d-flex justify-content-around todo">
<div id="bloc-pivoter-droite" class="d-flex flex-column">
<label for="pivoter-droite">Pivoter à droite</label>
<a id="pivoter-droite" class="btn btn-success btn-lg"><i class="fas fa-redo"></i></a>
</div>
<div id="bloc-pivoter-gauche" class="d-flex flex-column">
<label for="pivoter-gauche">Pivoter à gauche</label>
<a id="pivoter-gauche" class="btn btn-success btn-lg"><i class="fas fa-undo"></i></a>
</div>
</div>
<h3>Régénérer miniature</h3>
<p id="message-regenerer" class="message">
Vous avez remarqué un problème dans l'affichage de la miniature de cette photo ? Vous pouvez la régénérer ci-dessous !
</p>
<a id="regenerer-miniature" class="btn btn-warning btn-lg"><i class="fas fa-recycle"></i>&nbsp;Régénérer la miniature</a>
</div>
<div id="bloc-aide" class="bloc-volet aide hidden todo" data-volet="aide">
<h2>Aide</h2>
<p id="texte-aide" class="message">
Auxerunt haec vulgi sordidioris audaciam, quod cum ingravesceret penuria commeatuum, famis et furoris inpulsu Eubuli cuiusdam inter suos clari domum ambitiosam ignibus subditis inflammavit rectoremque ut sibi iudicio imperiali addictum calcibus incessens et pugnis conculcans seminecem laniatu miserando discerpsit. post cuius lacrimosum interitum in unius exitio quisque imaginem periculi sui considerans documento recenti similia formidabat.
 
Novitates autem si spem adferunt, ut tamquam in herbis non fallacibus fructus appareat, non sunt illae quidem repudiandae, vetustas tamen suo loco conservanda; maxima est enim vis vetustatis et consuetudinis. Quin in ipso equo, cuius modo feci mentionem, si nulla res impediat, nemo est, quin eo, quo consuevit, libentius utatur quam intractato et novo. Nec vero in hoc quod est animal, sed in iis etiam quae sunt inanima, consuetudo valet, cum locis ipsis delectemur, montuosis etiam et silvestribus, in quibus diutius commorati sumus.
 
Erat autem diritatis eius hoc quoque indicium nec obscurum nec latens, quod ludicris cruentis delectabatur et in circo sex vel septem aliquotiens vetitis certaminibus pugilum vicissim se concidentium perfusorumque sanguine specie ut lucratus ingentia laetabatur.
</p>
<ul id="aide-plus">
<li id="plus-infos" class="row">
<div class="col-10 label">Plus d'infos sur le wiki</div>
<a class="bouton btn btn-sm btn-outline-secondary" target="_blank"><i class="fas fa-question-circle"></i></a>
</li>
<li id="autres-questions" class="row">
<div class="col-10 label">D'autres questions ? Écrivez-nous !</div>
<a class="bouton btn btn-sm btn-outline-secondary"><i class="fas fa-envelope"></i></a>
</li>
</ul>
 
</div>
 
<div class="nettoyage-volet bas"></div>
</div>
 
</div>
<div id="info-img-galerie" class="carousel col-lg-8 col-12" data-ride="carousel" data-interval="false">
<div class="carousel-inner h-100 w-100">
<?php $urls = array_keys($infos_images); ?>
<?php for($index = 0; $index < count($urls); $index++):?>
<div id="img-cadre-<?php echo $index; ?>" class="carousel-item">
<img id="illustration-<?php echo $index;?>" class="d-block align-middle" src="<?php echo $urls[$index];?>" alt="" data-width="<?php echo $infos_image[$urls[$index]]['width'];?>" data-height="<?php echo $infos_image[$urls[$index]]['height'];?>">
</div>
<?php endfor; ?>
<a id="precedent" class="carousel-control-prev carousel-control" href="#info-img-galerie" role="button" data-slide="prev">
<i class="fas fa-chevron-circle-left"></i>
<span class="sr-only">Precedent</span>
</a>
<a id="suivant" class="carousel-control-next carousel-control" href="#info-img-galerie" role="button" data-slide="next">
<i class="fas fa-chevron-circle-right"></i>
<span class="sr-only">Suivant</span>
</a>
</div>
</div>
<div id="boutons-footer">
<div id="bloc-fct" class="">
<a id="bouton-tags" class="btn bouton-fct tags todo" data-volet="tags"><i class="fas fa-tags"></i></a>
<a id="bouton-noter" class="btn bouton-fct noter todo" data-volet="noter"><i class="far fa-star"></i></a>
<a id="bouton-signaler" class="btn bouton-fct signaler todo" data-volet="signaler"><i class="fas fa-exclamation-triangle"></i></a>
<a id="bouton-revision" class="btn bouton-fct revision todo" data-volet="revision"><i class="fas fa-edit"></i></a>
<a id="bouton-meta" class="btn bouton-fct meta actif" data-volet="meta"><i class="fas fa-info-circle"></i></a>
<a id="bouton-modif" class="btn bouton-fct modif" data-volet="modif"><i class="fas fa-redo-alt"></i></a>
<a id="bouton-aide" class="btn bouton-fct aide todo" data-volet="aide"><i class="fas fa-question-circle"></i></a>
</div>
<a id="retour-galerie" class="btn btn-outline-dark btn-lg bouton-fct hidden"><i class="fa fa-angle-double-down" aria-hidden="true"></i></a>
</div>
<script type="text/Javascript">
//<![CDATA[
var widgetProp = {
'keys':[<?php echo '"'.implode($keys, '","').'"'; ?>],
'urlWidget' : "<?php echo $url_widget; ?>",
'urls' : [<?php echo '"'.implode($urls, '","').'"'; ?>],
'infosImages' : <?php echo json_encode($infos_images); ?>,
'urlImage' : "<?php echo $url_image; ?>",
'indexPremiereImage' : <?php echo array_search($url_image, $urls); ?>,
'tailleMax' : 580,
'popupUrl' : "<?php echo $popup_url; ?>",
'urlBaseTelechargement' : "<?php echo $url_base_telechargement; ?>",
'urlServiceRegenererMiniature' : "<?php echo $url_ws_regenerer_img; ?>"
};
$( document ).ready( function() {
popup = new WidgetPhotoPopup( widgetProp );
popup.init();
});
//]]>
</script>
/branches/v3.01-serpe/widget/modules/photo/squelettes/contact_nl.tpl.html
New file
0,0 → 1,131
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Neem contact op met de auteur van de afbeelding</title>
<link rel="stylesheet" type="text/css" href="<?=$url_css?>contact.css" media="screen" />
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/1.6.2/jquery-1.6.2.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://www.tela-botanica.org/commun/bootstrap/2.0.2/css/bootstrap.css">
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/validate/1.8.1/jquery.validate.min.js"></script>
<script type="text/javascript" src="https://www.tela-botanica.org/commun/jquery/validate/1.8.1/messages_fr.js"></script>
</head>
<body>
<script type="text/javascript">
//<![CDATA[
 
var donnees = new Array();
function envoyerCourriel() {
//console.log('Formulaire soumis');
if ($("#form-contact").valid()) {
var destinataireId = $("#fc_destinataire_id").attr('value');
var typeEnvoi = $("#fc_type_envoi").attr('value');
// l'envoi aux non inscrits passe par le service intermédiaire du cel
// qui va récupérer le courriel associé à l'image indiquée
var urlMessage = "https://www.tela-botanica.org/service:cel:celMessage/image/"+destinataireId;
var erreurMsg = "";
console.log($(this));
$.each($("#form-contact").serializeArray(), function (index, champ) {
var cle = champ.name;
cle = cle.replace(/^fc_/, '');
 
if (cle == 'sujet') {
champ.value += " - Carnet en ligne - Tela Botanica";
}
if (cle == 'message') {
champ.value += "\n--\n"+
"Dit bericht wordt u toegestuurd via de fotowidget van de ‘Carnet en Ligne’ van het Tela Botanica netwerk.\n"+
"http://www.tela-botanica.org/widget:cel:photo";
}
 
donnees[index] = {'name':cle,'value':champ.value};
});
$.ajax({
type : "POST",
cache : false,
url : urlMessage,
data : donnees,
beforeSend : function() {
$(".msg").remove();
},
success : function(data) {
$("#fc-zone-dialogue").append('<pre class="msg info">'+data.message+'</pre>');
},
error : function(jqXHR, textStatus, errorThrown) {
erreurMsg += "Erreur Ajax :\ntype : "+textStatus+' '+errorThrown+"\n";
reponse = jQuery.parseJSON(jqXHR.responseText);
if (reponse != null) {
$.each(reponse, function (cle, valeur) {
erreurMsg += valeur + "\n";
});
}
},
complete : function(jqXHR, textStatus) {
var debugMsg = '';
if (jqXHR.getResponseHeader("X-DebugJrest-Data") != '') {
debugInfos = jQuery.parseJSON(jqXHR.getResponseHeader("X-DebugJrest-Data"));
if (debugInfos != null) {
$.each(debugInfos, function (cle, valeur) {
debugMsg += valeur + "\n";
});
}
}
if (erreurMsg != '') {
$("#fc-zone-dialogue").append('<p class="msg">'+
'Er is een fout opgetreden bij het versturen van uw bericht.'+'<br />'+
'U kunt de storing melden bij <a href="'+
'mailto:cel@tela-botanica.org'+'?'+
'subject=Disfonctionnement du widget carto'+
"&body="+erreurMsg+"\nDébogage :\n"+debugMsg+
'">cel@tela-botanica.org</a>.'+
'</p>');
}
}
});
}
return false;
}
 
function initialiserFormulaireContact() {
$("#form-contact").validate({
rules: {
fc_sujet : "required",
fc_message : "required",
fc_utilisateur_courriel : {
required : true,
email : true}
}
});
$("#form-contact").live("submit", function(event) {
event.preventDefault();
envoyerCourriel();
});
$("#fc_annuler").live("click", function() {window.close();});
}
 
$(document).ready(function() {
initialiserFormulaireContact();
});
//]]>
</script>
<!-- Squelette du formulaire de contact -->
<div id="tpl-form-contact">
<form id="form-contact" method="post" action="">
<div id="fc-zone-dialogue"></div>
<div>
<div><label for="fc_sujet">Onderwerp</label></div>
<div><input id="fc_sujet" name="fc_sujet" value="<?= $donnees['sujet'] ?>"/></div>
<div><label for="fc_message">Bericht</label></div>
<div><textarea id="fc_message" name="fc_message"><?= $donnees['message'] ?></textarea></div>
<div><label for="fc_utilisateur_courriel" title="Gebruik het e-mailadres waarmee u bent aangemeld bij Tela Botanica">Jouw e-mailadres</label></div>
<div><input id="fc_utilisateur_courriel" name="fc_utilisateur_courriel"/></div>
</div>
<p>
<input id="fc_destinataire_id" name="fc_destinataire_id" type="hidden" value="<?= $donnees['id_image'] ?>" />
<input type="hidden" name="fc_type_envoi" id="fc_type_envoi" value="non-inscrit" />
<input id="fc_annuler" type="button" value="Annuleren">
<input id="fc_effacer" type="reset" value="Wissen">
<input id="fc_envoyer" type="submit" value="Verzenden" />
</form>
</div>
</body>
</html>
/branches/v3.01-serpe/widget/modules/photo/squelettes/css/contact.css
New file
0,0 → 1,80
.error {
color: red;
}
 
#tpl-form-contact {
width: 350px;
max-height: 100vh;
padding: 15px;
margin: auto;
border-radius: 0.25rem;
background-color: #fff;
overflow: auto;
}
 
#tpl-form-contact #fc_message,
#tpl-form-contact .form-group input {
font-size: 0.8rem;
}
 
#tpl-form-contact .form-group input.btn,
#tpl-form-contact .form-group #fc_annuler {
border: 0 none;
font-size: 1rem;
font-weight: 400;
text-shadow: none;
opacity: 1;
color: #fff;
margin: 0;
margin-bottom: 0.25rem;
box-shadow: none;
}
 
#tpl-form-contact .form-group #fc_annuler {
background-color: #ff5d55;
transition: background .2s ease;
}
 
#tpl-form-contact .form-group #fc_annuler:hover {
background-color: #ff847e;
}
 
#tpl-form-contact #fc_message {
min-height: 200px;
}
 
@media screen and ( max-width: 991px ) {
#tpl-form-contact {
max-height: 100vh;
width: 100vw;
position: fixed;
border-radius: 0;
background-color: transparent;
top: 0;
right: 0;
left: 0;
z-index: 9;
overflow: scroll;
margin: auto;
padding-top: 5vh;
}
 
#tpl-form-contact h2 {
max-width: 100%;
margin: 0 auto;
width: 350px;
color: #fff;
text-align: center;
}
 
#tpl-form-contact #form-contact {
max-width: 100%;
width: 350px;
margin: auto;
padding: 15px;
}
 
#tpl-form-contact #form-contact label {
color: #fff;
}
}
/branches/v3.01-serpe/widget/modules/photo/squelettes/css/popup.css
New file
0,0 → 1,410
@CHARSET "UTF-8";
 
#info-img-galerie {
display: flex;
justify-content: center;
height: 100vh;
}
 
.modal-open .modal {
/*overflow: hidden;*/
}
 
.modal-header {
padding: 1rem;
border: none;
position: fixed;
top: 20px;
right: 20px;
color: #fff;
font-size: 1.5rem;
z-index: 10;
}
 
.modal-header .close {
text-shadow: none;
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
font-size: 1rem;
padding: 1px;
margin: 0;
position: fixed;
top: 2px;
right: 2px;
opacity: 1;
}
 
.close:not(:disabled):not(.disabled):focus,
.close:not(:disabled):not(.disabled):hover {
color: #918a6f;
background-color: rgba(0, 0, 0, 0.2);
box-shadow: none;
}
 
.modal-body {
padding: 0;
margin: 0;
min-height: 100vh;
}
 
.modal-dialog {
width: 100vw;
height: 100vh;
max-width: 100vw;
max-height: 100vh;
margin: 0;
padding: 0;
}
 
.modal-content {
max-height: 100vh;
min-height: 100vh;
border-radius: 0;
margin: 0;
padding: 0;
background-color: rgba(0, 0, 0, 0.8);
border:none;
}
 
.carousel-inner {
display: flex;
align-items: center;
justify-content: center;
}
 
.carousel-item.active {
text-align: center;
}
 
.carousel-item.active img {
margin: auto;
}
 
.carousel-item img {
padding: 1rem;
max-height: 100vh;
max-width: 100vh;
}
 
.carousel-control {
background-color: rgba(0,0,0,0.2);
width: initial;
padding: 0 2%;
}
 
.carousel-control,
#info-img-galerie a {
font-size: 1.5rem;
color: #fff;
opacity: 1;
}
 
.carousel-control:hover,
#info-img-galerie a:hover {
color: #918a6f;
}
 
hr.nettoyage {
visibility: hidden;
}
 
#boutons-footer {
position: absolute;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
}
 
#boutons-footer #bloc-fct .bouton-fct.actif {
color: #c3d45d;
}
 
#bloc-fct {
padding: 1rem;
display: flex;
justify-content: center;
}
 
#bloc-fct .bouton-fct {
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
margin: 0;
}
 
#bloc-fct .bouton-fct:not(:last-child) {
margin-right: 5px;
}
 
#bloc-fct .bouton-fct:hover {
color: #918a6f;
}
 
#pivoter-photo a {
max-width: inherit;
padding: 1rem;
}
 
#volets-fct .btn#retour-metas {
position: fixed;
top: 2px;
left: 2px;
z-index: 10;
padding: 1px 5px;
font-size: 0.8rem;
margin: 0;
opacity: 1;
color: #fff;
background-color: rgba(0, 0, 0, 0.2);
text-shadow: none;
}
 
#volets-fct .btn#retour-metas:hover {
color: #918a6f;
}
 
#retour-galerie {
width: 100%;
margin: 0;
border: none !important;
border-radius: 0;
color: #fff;
background-color: rgba(0, 0, 0, 0.2);
}
 
#retour-galerie:hover {
color: #918a6f;
}
 
/*----------------------------------------------------------------------------------------------------------*/
 
#volet {
position: relative;
background-color: #fff;
justify-content: center;
display: flex;
height: 100vh;
overflow: scroll;
}
 
#bloc-infos-img {
position: fixed;
top: unset;
bottom: 0;
left: 0;
padding: 1.5rem;
z-index: 9;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
color: #fff !important;
font-weight: 400;
}
 
#bloc-infos-img a {
color: #fff;
bottom: unset;
left: unset;
}
 
#bloc-infos-img a:hover {
background-color: #918a6f;
}
 
/*----------------------------------------------------------------------------------------------------------*/
 
#volets-fct {
padding: 0 1rem;
width: calc(100% - 1rem);
overflow-wrap: break-word;
}
 
#volets-fct h2 {
text-align: center;
padding: 1rem;
}
 
#volets-fct h2:not(:first-child) {
margin-top: 1rem;
}
 
#volets-fct li {
position: relative;
padding: 0.5rem 0;
}
 
#print_content #volet #volets-fct .btn.btn-outline-secondary:not(#plus-meta),
#print_content #volet #volets-fct .btn.btn-success,
#print_content #volet #volets-fct .btn.btn-warning {
border: 0 none !important;
}
 
#volets-fct .bouton {
position: absolute;
right: 0.5rem;
top: 0.25rem;
margin: 0;
}
 
#volets-fct .afficher-plus {
cursor: pointer;
border-bottom: 1px solid;
border-bottom: .1rem solid;
color: #918a6f;
font-weight: 400;
}
 
#volets-fct .afficher-plus:hover {
color: #000;
}
 
#volets-fct .btn:not(.btn-outline-secondary),
#volets-fct .btn-outline-secondary:hover {
color: #fff;
}
 
#volets-fct #boutons-reseaux-sociaux {
display: flex;
justify-content: space-evenly;
}
 
#volets-fct #boutons-reseaux-sociaux a {
border: none;
}
 
#volets-fct #boutons-reseaux-sociaux a:not(:last-child) {
margin-right: 5px;
}
 
#tags-pf-supp {
min-height: 5rem;
}
 
#volets-fct #bloc-tags .tag {
color: #606060;
border: 1px solid transparent;
border-radius: 2rem;
-moz-box-shadow: 0.5px 1.5px 1.5px #606060;
-webkit-box-shadow: 0.5px 1.5px 1.5px #606060;
box-shadow: 0.5px 1.5px 1.5px #606060;
-webkit-transition: all 0.2s ease-in-out 0s;
-moz-transition: all 0.2s ease-in-out 0s;
-o-transition: all 0.2s ease-in-out 0s;
-ms-transition: all 0.2s ease-in-out 0s;
transition: all 0.2s ease-in-out 0s;
margin-right: 5px;
}
 
#volets-fct #bloc-tags .tag:hover,
#volets-fct #bloc-tags .tag:active,
#volets-fct #bloc-tags .tag:focus,
#volets-fct #bloc-tags .tag.actif {
color: #92ad27;
border:1px solid #d9d9d9;
-moz-box-shadow: 0 0 0 transparent;
-webkit-box-shadow: 0 0 0 transparent;
box-shadow: 0 0 0 transparent;
}
 
#volets-fct #bloc-tags .tag.actif {
color: #fff;
background-color: #c3d45d;
}
 
#volets-fct #bloc-tags .tag.actif:hover,
#volets-fct #bloc-tags .tag.actif:active,
#volets-fct #bloc-tags .tag.actif:focus {
background-color: #92ad27;
-moz-box-shadow: 0;
-webkit-box-shadow: 0;
box-shadow: 0;
}
 
#volets-fct #bloc-tags .tag:not(.actif) .fermer {
color: transparent;
display: none;
}
 
#volets-fct #bloc-tags .tag.actif .fermer {
color:#fff;
display: inline;
}
 
#volets-fct #bloc-tags .tag.actif:hover .fermer,
#volets-fct #bloc-tags .tag.actif:active .fermer,
#volets-fct #bloc-tags .tag.actif:focus .fermer {
color: #c3d45d;
}
 
#tags-auteur {
min-height: 3rem;
border:1px dotted #606060;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0.2rem
}
 
.nettoyage-volet {
padding: 1.5rem;
width: 100%;
opacity: 0;
text-align: center;
font-weight: 400;
}
 
.nettoyage-volet.bas {
margin-top: 1rem;
}
 
/************************************************************************************************************/
 
#localisation-map-container {
position: absolute;
z-index: 100;
top: 30px;
right: 5%;
left: 5%;
height: 302px;
border: 1px solid #606060;
overflow: hidden;
}
 
#localisation-map {
width: 100%;
height: 300px;
background-color: #fff;
}
 
#map-close {
z-index: 10000;
}
 
/*----------------------------------------------------------------------------------------------------------*/
@media screen and ( max-width: 991px ) {
#bloc-infos-img {
top: 0;
width: 100vw;
bottom: unset;
}
 
#boutons-footer {
width: 100vw;
right: unset;
}
 
#boutons-footer .bouton-fct {
font-size: 0.8rem;
}
 
.nettoyage-volet.bas {
min-height: 5.5rem;
}
#bloc-fct {
padding: 0.5rem;
}
}
 
 
@media screen and ( max-width: 768px ) {
#info-img-galerie a {
font-size: 0.8rem;
}
}
/branches/v3.01-serpe/widget/modules/photo/squelettes/css/photoCommun.css
New file
0,0 → 1,109
@CHARSET "UTF-8";
 
*,
*:active,
*:focus {
outline:none !important;
}
 
html {
font-size: 100%;
}
 
body {
font-family: Muli,sans-serif;
font-size: 0.8rem;
font-weight: 300;
color: #606060;
}
 
.h2, h2 {
font-size: 1.15rem;
}
 
.h3, h3 {
font-size: 1.05rem;
}
 
.label, label, .list-label {
font-weight: 700;
}
 
.list label, .list .label {
font-weight: 400;
}
 
ul {
padding: 0;
}
 
.hidden {
display: none !important;
}
 
.btn {
margin: 1rem 0;
}
 
.btn:not(.btn-outline-secondary),
.btn-outline-secondary:hover {
color:#fff;
}
 
.btn.btn-warning {
background-color: #e16e38;
}
 
.btn.btn-warning:hover {
background-color: #e6885b;
}
 
.btn.btn-success {
background-color: #a2b93b;
}
 
.btn.btn-success:hover {
background-color: #b3c954;
}
 
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #606060;
}
 
.cel-photo-source a {
color: #006979;
font-weight: 400;
}
 
.cel-infos a,
.cel-photo-source a,
#bloc-infos-img a {
border-bottom: 1px solid;
border-bottom: .1rem solid;
text-decoration: none !important;
-webkit-transition: background .2s ease;
-o-transition: background .2s ease;
transition: background .2s ease;
cursor: pointer;
}
 
.cel-infos a:hover,
.cel-photo-source a:hover {
background-color: rgba(0,105,121,.1);
}
 
.modal-header,
.modal-footer {
border : none;
}
 
/*.todo {
display: none !important;
}*/
 
@media screen and ( max-width: 340px ) {
html {
font-size: 80%;
}
}
/branches/v3.01-serpe/widget/modules/photo/squelettes/css/photo.css
New file
0,0 → 1,190
@charset "UTF-8";
 
.grid {
max-width: 100vw;
}
 
/* clearfix */
.grid:after {
content: '';
display: block;
clear: both;
}
 
.grid-item {
float: left;
position: relative;
margin: 0.5vw;
}
 
.cel-photo .cel-infos {
position: absolute;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 1rem;
background: rgba(255,255,255,0.5);
text-align: center;
font-weight: 400 !important;
font-size: 0.5rem;
}
 
.cel-infos,
.cel-infos a {
color: #606060;
}
 
.cel-photo-contenu h1 {
text-align: center;
padding: 15px;
}
 
.cel-photo a,
.cel-photo a img {
height: 100%;
width: 100%;
}
 
.cel-photo-contenu {
margin: 0 auto;
max-width: 100%;
}
 
.cel-photo-contenu .discretion {
color: grey;
font-size: 0.8rem;
font-weight: 700;
}
 
.cel-photo-contenu .nettoyage {
clear: both;
}
 
.cel-photo-pieds {
padding: 1rem;
}
 
.cel-photo-contenu .cel-photo .cel-infos .close,
.cel-photo .bouton-afficher-infos {
position: absolute;
top: 3px;
right: 3px;
height: initial;
width: initial;
padding: 0.1rem 0.2rem;
}
 
.cel-photo-contenu .cel-photo .cel-infos .close,
.cel-photo-contenu .cel-photo .cel-infos .close:hover {
font-size: 0.5rem;
text-decoration: none;
border: none;
color: #606060;
}
 
.cel-photo .bouton-afficher-infos {
font-size: 1rem;
}
 
.cel-photo .bouton-afficher-infos i {
color:#ffc107;
}
 
.cel-photo .bouton-afficher-infos:hover i {
background-color: #ffc107;
color: #fff;
}
 
/*---------------------------------------------*/
 
.form-recherche {
position: relative;
}
 
.form-recherche .bloc-recherche .recherche {
width: auto;
display: inline-block;
}
 
.form-recherche .bloc-recherche .bouton-rechercher,
.form-recherche .bloc-recherche .bouton-plus-filtres,
#bouton-photos-precedentes,
#bouton-photos-precedentes:hover,
#bouton-photos-suivantes,
#bouton-photos-suivantes:hover {
border: 0 none;
}
 
.form-recherche .bloc-recherche .bouton-rechercher,
.form-recherche .bloc-recherche .bouton-rechercher:hover,
.form-recherche .bloc-recherche .bouton-plus-filtres:hover,
#bouton-photos-precedentes,
#bouton-photos-precedentes:hover,
#bouton-photos-suivantes,
#bouton-photos-suivantes:hover {
color: #fff;
}
 
#bouton-photos-precedentes,
#bouton-photos-precedentes:hover,
#bouton-photos-suivantes,
#bouton-photos-suivantes:hover {
margin: 5px auto;
}
 
 
.form-recherche .autres-filtres {
position: absolute;
padding: 0.5rem;
margin: 0.5rem 0;
background-color: rgba(0, 0, 0, 0.8);
border-radius: 0.25rem;
top: 80%;
z-index: 9;
}
 
.form-recherche .autres-filtres .bloc-filtre {
padding: 0.5rem;
margin: 0.5rem;
color: #fff;
}
 
.form-recherche .autres-filtres .btn.bouton-fermer-filtres {
position: absolute;
top: 0;
right: 0;
margin: 0;
color: #fff;
cursor: pointer;
z-index: 10;
}
 
@media screen and ( max-width: 991px ) {
.form-recherche .autres-filtres {
position: fixed;
border-radius: 0;
margin: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9;
overflow: scroll;
}
 
.form-recherche .bloc-recherche .recherche {
width: 100vw;
}
 
.form-recherche .bouton-plus-filtres .moins {
display: none;
}
}
 
@media screen and ( max-width: 768px ) {
.cel-photo .cel-infos {
display: none;
}
}
/branches/v3.01-serpe/widget/modules/photo/squelettes/photo.tpl.html
New file
0,0 → 1,320
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Photographies publiques du CEL - Tela Botanica</title>
 
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-style-type" content="text/css" />
<meta http-equiv="Content-script-type" content="text/javascript" />
<meta http-equiv="Content-language" content="fr" />
 
<meta name="revisit-after" content="15 days" />
<meta name="robots" content="index,follow" />
<meta name="author" content="Tela Botanica" />
<meta name="keywords" content="Tela Botanica, photographie, CEL" />
<meta name="description" content="Widget de présentation des dernières photo publiées sur le Carnet en Ligne de Tela Botanica" />
 
<!-- OpenGraph pour Facebook, Pinterest, Google+ -->
<meta property="og:type" content="website" />
<meta property="og:title" content="Widget photo du CeL" />
<meta property="og:site_name" content="Tela Botanica" />
<meta property="og:description" content="Mini-galerie photo des observations publiques du Carnet en Ligne" />
<?php if (isset($items[0])) : ?>
<meta property="og:image" content="<?php echo sprintf($items[0]['url_tpl'], 'CRS'); ?>" />
<?php else : ?>
<meta property="og:image" content="https://resources.tela-botanica.org/tb/img/256x256/carre_englobant.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="256" />
<meta property="og:image:height" content="256" />
<?php endif; ?>
<meta property="og:locale" content="fr_FR" />
 
<!-- Spécial mobile -->
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
 
<!-- Favicones -->
<link rel="icon" type="image/png" href="https://resources.tela-botanica.org/tb/img/16x16/favicon.png" />
<link rel="shortcut icon" type="image/x-icon" href="https://resources.tela-botanica.org/tb/img/16x16/favicon.ico" />
<!-- Jquery-ui custom css-->
<link href="https://www.tela-botanica.org/commun/jquery/jquery-ui/1.8.18/css/smoothness/jquery-ui-1.8.18.custom.css" rel="stylesheet" type="text/css" media="screen" />
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />
<!-- Fontawesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous" />
<!-- Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
 
<!-- Feuilles de styles -->
<link rel="stylesheet" type="text/css" href="<?php echo $url_css; ?>photo.css" media="screen" />
<link rel="stylesheet" type="text/css" href="<?php echo $url_css; ?>popup.css" media="screen" />
<link rel="stylesheet" type="text/css" href="<?php echo $url_css; ?>contact.css" media="screen" />
<link rel="stylesheet" type="text/css" href="<?php echo $url_css; ?>photoCommun.css" media="screen" />
<style type="text/css">
<?php $dimention_basique = floor(93/$colonne);?>
#cel-photo-contenu<?php echo $id; ?> .grid-sizer,
#cel-photo-contenu<?php echo $id; ?> .grid-item {
width: <?php echo $dimention_basique; ?>vw;
}
 
#cel-photo-contenu<?php echo $id; ?> .grid-item {
height: <?php echo $dimention_basique; ?>vw;
}
 
#cel-photo-contenu<?php echo $id; ?> .grid-item--width2 {
width: <?php echo ($dimention_basique*2)+1; ?>vw;
}
 
#cel-photo-contenu<?php echo $id; ?> .grid-item--height2 {
height: <?php echo number_format((($dimention_basique*2)+0.99),2); ?>vw;
}
</style>
<!-- Javascript : bibliothèques -->
<!-- Jquery -->
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/1.11.1/jquery-1.11.1.min.js"></script>
 
<!-- Jquery UI : nécessaire pour le minicalendrier et l'auto-complétion -->
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/jquery-ui/1.11.0/js/jquery-ui.min.js"></script>
<!-- Jquery Plugins -->
<!-- Jquery Validate : nécessaire pour la validation des formulaires -->
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/validate/1.11.1/jquery.validate.min.js"></script>
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/validate/1.11.1/additional-methods.min.js"></script>
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/validate/1.11.1/messages_fr.js"></script>
<!-- Jquery Form :nécessaire pour l'upload des images -->
<script type="text/javascript" src="https://resources.tela-botanica.org/jquery/form/3.51/jquery.form.min.js"></script>
<!-- Bootstrap -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<!-- Masonry -->
<script src="<?php echo $url_js; ?>masonry.pkgd.js"></script>
<!-- Leaflet -->
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
 
<!-- Script WidgetPhoto -->
<script type="text/Javascript" src="<?php echo $url_js; ?>WidgetPhotoCommun.js"></script>
<script type="text/Javascript" src="<?php echo $url_js; ?>WidgetPhoto.js"></script>
<script type="text/javascript" src="<?php echo $url_js; ?>WidgetPhotoPopup.js"></script>
<script type="text/javascript" src="<?php echo $url_js; ?>WidgetPhotoContact.js"></script>
 
<!-- Google Analytics -->
<?php if($prod): ?>
<?php include "analytics.html"; ?>
<?php endif; ?>
</head>
<body style="margin: 0">
<!-- WIDGET:CEL:PHOTO - DEBUT -->
<div id="cel-photo-contenu<?php echo $id; ?>" class="cel-photo-contenu">
<?php if (isset($erreurs) || isset($informations)) : ?>
<h1>Erreur &amp; informations</h1>
<p>Impossible d'afficher le flux.</p>
<!-- Affichage des erreurs et messages d'information : -->
<?php if ($erreurs) : ?>
<?php foreach ($erreurs as $erreur) : ?>
<p class="erreur"><?php echo $erreur; ?></p>
<?php endforeach; ?>
<?php endif; ?>
 
<?php if ($informations) : ?>
<?php foreach ($informations as $information) : ?>
<p class="info"><?php echo $information; ?></p>
<?php endforeach; ?>
<?php endif; ?>
<?php else : ?>
<h1>
<?php if (!empty($titre)) : ?>
<?php echo $titre; ?>
<?php endif ; ?>
<?php if($icone_rss) : ?>
<a href="<?php echo $flux_rss_url; ?>"
class="cel-photo-flux"
title="Suivre les images"
onclick="window.open(this.href);return false;">
<img src="https://www.tela-botanica.org/sites/commun/generique/images/rss.png" alt="Suivre les images" />
</a>
<?php endif; ?>
</h1>
<?php if (!empty($champ_recherche)) : ?>
<form id="form-recherche<?php echo $id; ?>" class="form-recherche container" action="">
<div id="bloc-recherche<?php echo $id; ?>" class="bloc-recherche form-inline d-flex justify-content-center w-100">
<input type="text" id="champ-recherche<?php echo $id; ?>" name="champ-recherche<?php echo $id; ?>" class="recherche form-control mr-1" placeholder="Votre recherche">
<input type="hidden" id="filtres<?php echo $id; ?>" name="filtres<?php echo $id; ?>">
<a id="bouton-rechercher<?php echo $id; ?>" class="btn btn-success bouton-rechercher mr-1"><i class="fas fa-search"></i>&nbsp;Rechercher</a>
<a id="bouton-plus-filtres<?php echo $id; ?>" class="btn btn-outline-secondary bouton-plus-filtres">
<span class="plus">
<i class="fas fa-chevron-down"></i>&nbsp;Plus&nbsp;de&nbsp;filtres
</span>
<span class="moins hidden">
<i class="fas fa-chevron-up"></i>&nbsp;Fermer&nbsp;les&nbsp;filtres
</span>
</a>
</div>
<div id="autres-filtres<?php echo $id; ?>" class="autres-filtres row hidden">
<a id="bouton-fermer-filtres<?php echo $id; ?>" class="btn bouton-fermer-filtres"><i class="fas fa-times"></i></a>
<div id="bloc-filtres-gauche" class="bloc-filtres bloc-filtres-gauche col-lg-6">
<div class="row bloc-taxon bloc-filtre">
<label for="taxon">Taxon</label>
<input type="text" id="taxon" name="taxon" class="form-control">
</div>
<div class="row bloc-referentiel bloc-filtre">
<label for="referentiel">Référentiel</label>
<select name="referentiel" id="referentiel" class="custom-select form-control referentiel">
<option value="bdtfxr" selected="selected" title="Trachéophytes de France métropolitaine">Métropole (index réduit)</option>
<option value="bdtfx" title="Trachéophytes de France métropolitaine">Métropole (BDTFX)</option>
<option value="bdtxa" title="Trachéophytes des Antilles">Antilles françaises (BDTXA)</option>
<option value="bdtre" title="Trachéophytes de La Réunion">Réunion (BDTRE)</option>
<option value="aublet" title="Guyane">Guyane (AUBLET2)</option>
<option value="florical" title="Nouvelle-Calédonie">Nouvelle-Calédonie (FLORICAL)</option>
<option value="isfan" title="Afrique du Nord">Afrique du Nord (ISFAN)</option>
<option value="apd" title="Afrique de l'Ouest et du Centre">Afrique de l'Ouest et du Centre (APD)</option>
<option value="lbf" title="Liban">Liban (LBF)</option>
<option value="autre" title="Autre/Inconnu">Autre/Inconnu</option>
</select>
</div>
<div class="bloc-periode bloc-filtre">
<label for="periode" class="d-block">Date (début-fin)</label>
<div class="form-row">
<div class="form-group mb-lg-0 mb-1 col">
<input type="date" id="periode-debut" name="periode-debut" class="form-control">
</div>
<div class="form-group mb-0 col">
<input type="date" id="periode-fin" name="periode-fin" class="form-control">
</div>
</div>
<input type="hidden" id="periode" name="periode">
</div>
<div class="row bloc-localite bloc-filtre">
<label for="localite">Localité</label>
<input type="text" id="localite" name="localite" class="form-control">
</div>
<div class="row bloc- bloc-filtre">
<label for="departement">Département</label>
<input type="text" id="departement" name="departement" class="form-control" placeholder="Numéros (séparés par des virgules)">
</div>
<div class="row bloc- bloc-filtre">
<label for="pays">Pays</label>
<input type="text" id="pays" name="pays" class="form-control">
</div>
</div>
<div id="bloc-filtres-droite" class="bloc-filtres bloc-filtres-droite col-lg-6">
<div class="row bloc- bloc-filtre">
<label for="auteur">Auteur</label>
<input type="text" id="auteur" name="auteur" class="form-control" placeholder="Nom, email">
</div>
<div class="row bloc- bloc-filtre">
<label for="programme">Programme</label>
<input type="text" id="programme" name="programme" class="form-control">
</div>
<div class="row bloc- bloc-filtre">
<label for="tags">Tags (tous)</label>
<input type="text" id="tags" name="tags" class="form-control">
</div>
<div class="list bloc-photos-affichees bloc-filtre mt-3">
<div class="form-check mt-3">
<input type="checkbox" id="non-standards" name="photos-affichees" class="non-standards form-check-input" value="non-standards">
<label for="non-standards" class="non-standards form-check-label">Afficher les photos des observations non "standards"</label>
</div>
<div class="form-check mt-3">
<input type="checkbox" id="indesirables" name="photos-affichees" class="indesirables form-check-input" value="indesirables">
<label for="indesirables" class="indesirables form-check-label">Afficher les photos signalées comme indésirables</label>
</div>
<div class="form-check mt-3">
<input type="checkbox" id="smartphone-anonyme" name="photos-affichees" class="smartphone-anonyme form-check-input" value="smartphone-anonyme">
<label for="smartphone-anonyme" class="smartphone-anonyme form-check-label">Afficher les photos des observations smartphone anonyme</label>
</div>
</div>
</div>
</div>
</form>
<?php endif ; ?>
<div id="cel-galerie-photo<?php echo $id; ?>" class="cel-galerie-photo">
<div class="grid-sizer"></div>
<?php foreach ($items as $i => $item) : ?>
<?php
$dimention_img = 'CRS';
$class_extra = '';
?>
<?php if ( $i === 0 && $extra_actif ) : ?>
<?php
$dimention_img = 'CRL';
$class_extra = ' grid-item--width2 grid-item--height2';
?>
<?php endif; ?>
<div class="cel-photo grid-item <?php echo $class_extra; ?>">
<a href="<?php echo sprintf($item['url_tpl'], 'O'); ?>" class="cel-img" title="<?php echo $item['titre']; ?> - Publiée le <?php echo $item['date_redige']; ?> - GUID : <?php echo $item['id_photo_formate']; ?>" rel="galerie-princ<?php echo $id; ?>">
<img src="<?php echo sprintf($item['url_tpl'], $dimention_img); ?>" alt="<?php echo $item['titre']; ?>">
</a>
<div id="cel-info-<?php echo $item['id_photo_formate']; ?>" class="cel-infos">
<strong>
<?php if (!empty($item['lien'])) : ?>
<a class="cel-img-titre" href="<?php echo $item['lien']; ?>"
onclick="window.open(this.href);return false;"
title="Cliquez pour accéder à la fiche eFlore">
<?php echo $item['obs']['nom_sel']; ?>
</a><br />
par
<a class="cel-img-contact"
href="?mode=contact&nn=<?php echo urlencode($item['obs']['nom_sel_nn']); ?>&nom_sci=<?php echo urlencode($item['obs']['nom_sel']); ?>&date=<?php echo urlencode($item['date']); ?>&id_image=<?php echo $item['id_photo_formate']; ?>&auteur=<?php echo $item['utilisateur']['nom_utilisateur']; ?>"
title="Cliquez pour contacter l'auteur de la photo">
<?php echo $item['utilisateur']['nom_utilisateur']; ?>
</a>
<?php else : ?>
<?php echo $item['titre']; ?>
<?php endif; ?>
</strong>
</div>
</div>
<?php endforeach; ?>
<div id="next-previous-buttons">
<?php if (0 < $start): ?>
<a id="bouton-photos-precedentes" href="<?php echo $url_widget_photos_precedente;?>" class="btn btn-success"><i class="fas fa-backward"></i>&nbsp;Photos precedentes</a>
<?php endif;?>
 
<?php if ($total > ($start + $limit)): ?>
<a id="bouton-photos-suivantes" href="<?php echo $url_widget_photos_suivantes;?>" class="btn btn-success"><i class="fas fa-forward"></i>&nbsp;Photos suivantes</a>
<?php else :?>
<div class="alert alert-secondary mt-0 ml-1" role="alert" style="display: inline-block;">Toutes les photos disponibles, correspondant à vos critères, ont été affichées</div>
<?php endif;?>
</div>
</div>
<p class="cel-photo-pieds discretion nettoyage">
<span class="cel-photo-source">
Source :
<a href="http://www.tela-botanica.org/page:cel" title="Carnet en Ligne" onclick="window.open(this.href);return false;">
CEL
</a>
</span>
<span class="cel-photo-date-generation">Au <?php echo strftime('%A %d %B %Y à %H:%M:%S'); ?></span>
</p>
 
<?php endif; ?>
</div>
<!-- modale -->
<div id="fenetre-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="fenetre-modal-label" style="display: none;" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="fenetre-modal-label"></h5>
<button type="button" class="close btn btn-sm btn-secondary" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body row" id="print_content"></div>
<div class="modal-footer hidden"></div>
</div>
</div>
</div>
<!-- WIDGET:CEL:PHOTO - FIN -->
<script type="text/Javascript">
//<![CDATA[
var widgetProp = {
'id' : "<?php echo $id; ?>",
'galerieId' : "<?php echo $galerie_id; ?>"
};
 
$( document ).ready( function() {
photo = new WidgetPhoto( widgetProp );
photo.init();
});
//]]>
</script>
</body>
</html>
/branches/v3.01-serpe/widget/modules/photo/Photo.php
New file
0,0 → 1,360
<?php
// declare(encoding='UTF-8');
/**
* Service affichant les dernières photo publiques du CEL ouvrable sous forme de diaporama.
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* Cas d'utilisation et documentation :
* @link http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=AideCELWidgetPhoto
*
* Paramètres :
* ===> extra = booléen (1 ou 0) [par défaut : 1]
* Affiche / Cache la vignette en taille plus importante au bas du widget.
* ===> vignette = [0-9]+,[0-9]+ [par défaut : 4,3]
* Indique le nombre de vignette par ligne et le nombre de ligne.
*
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @version $Id$
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
*/
class Photo extends WidgetCommun {
 
const DS = DIRECTORY_SEPARATOR;
const SERVICE_DEFAUT = 'photo';
const VIGNETTE_DEFAULT = '4,3';
const WS_IMG_LIST = 'celImage';
const IMAGE_FORMATS = [
'CRX2S' => '63px (Carrée, rognée)',
'CRXS' => '100px (Carrée, rognée)',
'CXS' => '100px (Carrée)',
'CS' => '300px (Carrée)',
'CRS' => '300px (Carrée, rognée)',
'XS' => '150px',
'S' => '400px',
'M' => '600px',
'L' => '800px',
'CRL' => '600px (Carrée, rognée)',
'XL' => '1024px',
'X2L' => '1280px',
'X3L' => '1600px',
'O' => 'Format original (Taille inconnue)'
];
const START_DEFAUT = 0;
const LIMIT_DEFAUT = 100;
private $url_widget = null;
private $eflore_url_tpl = null;
private $service_images_url = null;
private $flux_rss_url = null;
 
// Suffixe de template pour la langue (vide par défaut, correspond à "fr" au français)
private $suffixeLangue = '';
 
/**
* Méthode appelée par défaut pour charger ce widget.
*/
public function executer() {
$retour = null;
// Pour la création de l'id du cache nous ne tenons pas compte du paramètre de l'url callback
unset($this->parametres['callback']);
extract($this->parametres);
 
if (!isset($mode)) {
$mode = self::SERVICE_DEFAUT;
}
$this->url_widget = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'photo');
$this->eflore_url_tpl = $this->config['photo']['efloreUrlTpl'];
$this->service_images_url = $this->config['photo']['celUrlImages'];
$this->flux_rss_url = $this->config['photo']['fluxRssUrl'];
 
$cache_activation = $this->config['photo.cache']['activation'];
$cache_stockage = $this->config['photo.cache']['stockageDossier'];
$ddv = $this->config['photo.cache']['dureeDeVie'];
$cache = new Cache($cache_stockage, $ddv, $cache_activation);
$id_cache = 'photo-'.hash('adler32', print_r($this->parametres, true));
$contenu = $cache->charger($id_cache);
 
if (!$contenu) {
$methode = $this->traiterNomMethodeExecuter($mode);
 
if (method_exists($this, $methode)) {
$retour = $this->$methode();
 
} else {
$this->messages[] = "Ce type de service '$methode' n'est pas disponible.";
 
}
// Suffixe de template pour la langue - fr par défaut @TODO configurer ça un jour
if (isset($this->parametres['lang']) && $this->parametres['lang'] !== 'fr') {
$this->suffixeLangue = '_' . $this->parametres['lang'];
 
}
 
$contenu = '';
 
if (is_null($retour)) {
$this->messages[] = 'Aucune image';
 
} else {
 
if (isset($retour['donnees'])) {
$squelette = dirname(__FILE__) .self::DS. 'squelettes' .self::DS. $retour['squelette'].$this->suffixeLangue.'.tpl.html';
$contenu = $this->traiterSquelettePhp($squelette, $retour['donnees']);
$cache->sauver($id_cache, $contenu);
 
} else {
$this->messages[] = 'Les données à transmettre au squelette sont nulles.';
 
}
}
}
if (isset($_GET['callback'])) {
$this->envoyerJsonp(['contenu' => $contenu]);
 
} else {
$this->envoyer($contenu);
 
}
}
 
// maintenir la retrocompatibilité avec l'ancien mode ajax
private function executerAjax() {
unset($this->parametres['mode']);
 
$chaineRequete = http_build_query($this->parametres);
$chaineRequete = $chaineRequete ? '?'.$chaineRequete : '';
$widget['donnees']['url_widget'] = $this->url_widget.$chaineRequete;
 
$id = '-'.(isset($this->parametres['id']) ? $this->parametres['id'] : '1');
$widget['donnees']['id'] = $id;
 
$widget['squelette'] = 'photo_retrocompatibilite_ajax';
 
return $widget;
}
 
private function executerPopup() {
session_start();
 
$galerie_id = $_GET['galerie_id'];
$widget['donnees']['url_image'] = $_GET['url_image'];
$widget['donnees']['infos_images'] = $_SESSION[$galerie_id]['infos_images'];
$widget['donnees']['url_widget'] = $this->url_widget;
$widget['donnees']['url_css'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/css/');
$widget['donnees']['url_js'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/js/');
$widget['donnees']['max_photo'] = $_SESSION[$galerie_id]['max_photo'];
$widget['donnees']['start'] = $_SESSION[$galerie_id]['start'];
$widget['donnees']['url_ws_regenerer_img'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_IMG_LIST) . '/regenerer-miniatures?ids-img=';
$widget['donnees']['popup_url'] = isset( $_GET['popup_url'] ) ? $_GET['popup_url'] : null;
$widget['donnees']['url_base_telechargement'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], 'CelImageFormat/');
$widget['donnees']['formats_description'] = self::IMAGE_FORMATS;
 
$widget['squelette'] = 'popup' . $this->suffixeLangue;
 
return $widget;
}
 
private function executerContact() {
session_start();
 
$widget['donnees']['url_widget'] = $this->url_widget;
$widget['donnees']['id_image'] = $_GET['id_image'];
$widget['donnees']['nom_sci'] = $_GET['nom_sci'];
$widget['donnees']['nn'] = $_GET['nn'];
$widget['donnees']['date'] = $_GET['date'];
$widget['donnees']['auteur'] = $_GET['auteur'];
$widget['donnees']['popup_url'] = isset( $_GET['popup_url'] ) ? $_GET['popup_url'] : null;
 
if (isset($_GET['lang']) && 'nl' === $_GET['lang']) {
$widget['donnees']['sujet'] = "Afbeelding #".$_GET['id_image']." op ".$_GET['nom_sci'];
$widget['donnees']['message'] = "\n\n\n\n\n\n\n\n--\nBetreft de foto \"".$_GET['nom_sci'].'" van "'.$_GET['date'];
 
} else {
$widget['donnees']['sujet'] = "Image #".$_GET['id_image']." de ".$_GET['nom_sci'];
$widget['donnees']['message'] = "\n\n\n\n\n\n\n\n--\nConcerne l'image de \"".$_GET['nom_sci'].'" du "'.$_GET['date'];
 
}
 
$widget['donnees']['url_css'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/css/');
$widget['donnees']['url_js'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/js/');
$widget['squelette'] = 'contact';
 
return $widget;
}
 
 
private function executerPhoto() {
$widget = null;
 
$this->parametres['start'] = $this->parametres['start'] ?? self::START_DEFAUT;
$this->parametres['limit'] = $this->parametres['limit'] ?? self::LIMIT_DEFAUT;
 
extract($this->parametres);
 
$hasTriedValueInConfig = false;
while (!isset($vignette) || !preg_match('/^[0-9]+,[0-9]+$/', $vignette)) {
$vignette = (!$hasTriedValueInConfig) ? $this->config['photo']['vignette'] : self::VIGNETTE_DEFAULT;
$hasTriedValueInConfig = true;
}
$id = '-'.(isset($id) ? $id : '1');
$titre = isset($titre) ? htmlentities(rawurldecode($titre)) : '';
 
$icone_rss = (isset($_GET['rss']) && $_GET['rss'] != 1) ? false : true;
$utilise_fancybox = (isset($_GET['mode_zoom']) && $_GET['mode_zoom'] != 'fancybox') ? false : true;
 
list($colonne, $ligne) = explode(',', $vignette);
$extra = (isset($extra) && $extra == 0) ? false : (!$this->config['photo']['extraActif'] ? false : ($colonne == 1 || $ligne == 1 ? false : true));
 
$champ_recherche = $champ_recherche ? $this->obtenirBooleen($champ_recherche) : ($this->config['photo']['champRecherche'] ? $this->obtenirBooleen($this->config['photo']['champRecherche']) : false) ;
$max_photo = $colonne * $ligne;
if ( $extra && 2 == $colonne ) {
$max_photo = $max_photo - 1;
} elseif ( $extra && 2 < $colonne ) {
$max_photo = $max_photo - 3;
}
$limit = $limit < $max_photo ? $limit : $max_photo;
$this->parametres['limit'] = $limit;
$parametresTraites = $this->traiterParametres();
$this->flux_rss_url .= $parametresTraites;
$url = $this->service_images_url.(!empty($parametresTraites) ? $parametresTraites.'&' : '?');
$json = $this->getDao()->consulter($url);
 
 
if (empty($json) || !strpos($json,'images') ) {
$this->messages[] = "L'URI suivante est invalide : $this->service_images_url.\n".
"Veuillez vérifier les paramêtres indiqués et la présence d'images associées.";
 
} else {
$tableau = json_decode($json, true);
 
if (empty($tableau['total']) || empty($tableau['images'])) {
$this->messages[] = 'Aucune photo ne correspond à vos critères';
} else {
 
$parametres_photo_suivante = $parametres_photo_precedente = $this->parametres;
$parametres_photo_suivante['start'] = $start + $limit;
$parametres_photo_precedente['start'] = 0 < $start - $limit ? $start - $limit : 0;
 
$widget['donnees']['total'] = $tableau['total'];
$widget['donnees']['id'] = $id;
$widget['donnees']['titre'] = $titre;
$widget['donnees']['flux_rss_url'] = $this->flux_rss_url;
$widget['donnees']['url_widget'] = $this->url_widget;
$widget['donnees']['url_widget_photos_suivantes'] = $this->url_widget.'?'.http_build_query($parametres_photo_suivante);
$widget['donnees']['url_widget_photos_precedente'] = $this->url_widget.'?'.http_build_query($parametres_photo_precedente);
$widget['donnees']['url_css'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/css/');
$widget['donnees']['url_js'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], 'modules/photo/squelettes/js/');
$widget['donnees']['colonne'] = $colonne;
$widget['donnees']['ligne'] = $ligne;
$widget['donnees']['extra_actif'] = $extra;
$widget['donnees']['icone_rss'] = $icone_rss;
$widget['donnees']['champ_recherche'] = $champ_recherche;
$widget['donnees']['start'] = $start;
$widget['donnees']['limit'] = $limit;
$widget['donnees']['utilise_fancybox'] = $utilise_fancybox;
$widget['donnees']['prod'] = ($this->config['parametres']['modeServeur'] === 'prod');
 
$num = 0;
$galerie_id = md5(http_build_query($_GET));
$widget['donnees']['galerie_id'] = $galerie_id;
 
session_start();
$_SESSION[$galerie_id]['max_photo'] = $max_photo;
$_SESSION[$galerie_id]['start'] = $start;
 
foreach ($tableau['images'] as $key => $image) {
if ($key == $max_photo) {
break;
}
$item = $image;
// Formatage date
$item['date_photo'] = $image['date_photo'] ?? $image['obs']['date_obs'];
$item['date_redige'] = strftime('%A %d %B %Y', $item['date_photo']);
$item['date'] = date_format(date_create($item['date_photo']),"d/m/Y");
$item['lien'] = sprintf($this->eflore_url_tpl, $image['obs']['nom_referentiel'], $image['obs']['nom_sel_nn']);
$item['url_tpl'] = preg_replace('/(O|XS|[SML]|X(?:[23]|)L|CR(?:|X2)S|C(?:|X)S)$/', '%s.jpg', $image['url_photo']);
// Formatage titre
$item['titre'] = $image['obs']['nom_sel'].' [nn'.$image['obs']['nom_sel_nn'].'] par '.$image['utilisateur']['nom_utilisateur'].' le '.date_format(date_create($image['obs']['date_obs']),"d/m/Y").' - '.$image['obs']['localisation'];
$item['id_photo_formate'] = sprintf('%09d', $image['id_photo']);
$item['urlProfil'] = sprintf($this->config['photo']['tbProfilUrlTpl'], $image['utilisateur']['id_utilisateur'] );
// Ajout aux items et si première photo à extra
if ($key == 0) {
$widget['donnees']['extra'] = $item;
 
}
 
$widget['donnees']['items'][$num++] = $item;
$url_galerie_popup = sprintf($item['url_tpl'],'O');
$image_size = getimagesize($url_galerie_popup);
$item['width'] = $image_size[0];
$item['height'] = $image_size[1];
 
$_SESSION[$galerie_id]['infos_images'][$url_galerie_popup] = $item;
}
 
$widget['squelette'] = 'photo';
}
}
 
return $widget;
}
 
private function traiterParametres() {
$parametres_flux = '?';
$criteres = [
'taxon',
'referentiel',
'date_deb',
'date_fin',
'commune',
'dept',
'pays',
'auteur',
'programme',
'tag',
'non_standard',
'indesirable',
//on dégage smartphone anonyme PN
'recherche',
'date',
'motcle',
'projet',
'num_taxon',
'num_nom',
'start',
'limit'
];
 
foreach($this->parametres as $nom_critere => $valeur_critere) {
if (in_array($nom_critere, $criteres)) {
$valeur_critere = str_replace(' ', '%20', $valeur_critere);
$parametres_flux .= $nom_critere.'='.$valeur_critere.'&';
 
}
}
if ($parametres_flux === '?') {
$parametres_flux = '';
 
} else {
$parametres_flux = rtrim($parametres_flux, '&');
 
}
 
return $parametres_flux;
}
 
private function obtenirBooleen($var) {
switch ($var) {
case 'false' :
case 'null' :
case 'non' :
case 'no' :
return false;
default:
return boolval($var);
}
}
}
?>
/branches/v3.01-serpe/widget/modules/photo
New file
Property changes:
Added: svn:ignore
+config.ini