From 8326ed6dfb839f3aa64f2f46db5dbe7031c552e9 Mon Sep 17 00:00:00 2001
From: vinot <g.vinot@ville-montrouge.fr>
Date: Fri, 26 Jun 2015 15:01:53 +0200
Subject: [PATCH] =?UTF-8?q?Premier=20Chapitre=20V1.1=20configuration=20:?=
 =?UTF-8?q?=20/admin/premier-chapitre/=20*=20proc=C3=A9dure=20complete=20d?=
 =?UTF-8?q?e=20r=C3=A9cup=C3=A9ration=20des=20donn=C3=A9es=20premier-chapi?=
 =?UTF-8?q?tre=20usage=20/premier-chapitre/=20*=20pr=C3=A9sentation=20du?=
 =?UTF-8?q?=20service=20*selection=20al=C3=A9atoire=20/premier-chapitre/al?=
 =?UTF-8?q?eatoire/=20=3D=3D=20/premier-chapitre/aleatoire/nb/8=20*=20list?=
 =?UTF-8?q?e=20complete=20/premier-chapitre/liste-complete/?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controllers/PremierChapitreController.php | 281 ++++++++++++++++++
 .../scripts/premier-chapitre/index.phtml      |  13 +
 .../controllers/PremierChapitreController.php | 127 ++++++++
 .../scripts/premier-chapitre/common.phtml     |  13 +
 .../scripts/premier-chapitre/inactive.phtml   |   1 +
 .../scripts/premier-chapitre/index.phtml      |  18 ++
 .../views/scripts/recherche/viewnotice.phtml  |   6 +-
 cosmogramme/sql/patch/patch_260.php           |  13 +
 library/Class/Batch/PremierChapitre.php       |  28 ++
 library/Class/PremierChapitre.php             | 123 ++++++++
 library/Class/WebService/PremierChapitre.php  | 257 ++++++++++++++++
 .../View/Helper/ListeNotices/Vignettes.php    |   7 +-
 .../View/Helper/PremierChapitre/Abstract.php  |  31 ++
 .../View/Helper/PremierChapitre/Frame.php     |  43 +++
 .../View/Helper/PremierChapitre/Lien.php      |  53 ++++
 .../View/Helper/PremierChapitre/Vignettes.php |  72 +++++
 .../opac/images/lireavecpremierchapitre.png   | Bin 0 -> 9853 bytes
 17 files changed, 1082 insertions(+), 4 deletions(-)
 create mode 100644 application/modules/admin/controllers/PremierChapitreController.php
 create mode 100644 application/modules/admin/views/scripts/premier-chapitre/index.phtml
 create mode 100644 application/modules/opac/controllers/PremierChapitreController.php
 create mode 100644 application/modules/opac/views/scripts/premier-chapitre/common.phtml
 create mode 100644 application/modules/opac/views/scripts/premier-chapitre/inactive.phtml
 create mode 100644 application/modules/opac/views/scripts/premier-chapitre/index.phtml
 create mode 100644 cosmogramme/sql/patch/patch_260.php
 create mode 100644 library/Class/Batch/PremierChapitre.php
 create mode 100644 library/Class/PremierChapitre.php
 create mode 100644 library/Class/WebService/PremierChapitre.php
 create mode 100644 library/ZendAfi/View/Helper/PremierChapitre/Abstract.php
 create mode 100644 library/ZendAfi/View/Helper/PremierChapitre/Frame.php
 create mode 100644 library/ZendAfi/View/Helper/PremierChapitre/Lien.php
 create mode 100644 library/ZendAfi/View/Helper/PremierChapitre/Vignettes.php
 create mode 100644 public/opac/images/lireavecpremierchapitre.png

diff --git a/application/modules/admin/controllers/PremierChapitreController.php b/application/modules/admin/controllers/PremierChapitreController.php
new file mode 100644
index 00000000000..b8e835a8c65
--- /dev/null
+++ b/application/modules/admin/controllers/PremierChapitreController.php
@@ -0,0 +1,281 @@
+<?php
+/**
+ * Copyright (c) 2015, Gael VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+class Admin_PremierChapitreController extends ZendAfi_Controller_Action {
+	use Trait_Translator;
+	protected $_baseUrlOptions = ['module' => 'admin', 'controller' => 'premier-chapitre'];
+
+	private $active;
+	private $pc_bib_id;
+	private	$pc_bmid;
+	private	$pc_bmkey;
+
+	private function objectsIntoArray($arrObjData, $arrSkipIndices = array()) {
+		$arrData = array();
+		// if input is object, convert into array
+		if (is_object($arrObjData)) {
+			$arrObjData = get_object_vars($arrObjData);
+		}
+		if (is_array($arrObjData)) {
+			foreach ($arrObjData as $index => $value) {
+				if (is_object($value) || is_array($value)) {
+					$value = self::objectsIntoArray($value, $arrSkipIndices); // recursive call
+				}
+				if (in_array($index, $arrSkipIndices)) {
+					continue;
+				}
+				$arrData[$index] = $value;
+			}
+		}
+		return $arrData;
+	}
+
+	public function init() {
+		parent::init();
+		$this->view->titre = 'Premier Chapitre';
+		$this->pc_bib_id = Class_AdminVar::get('PREMIERCHAPITRE_BIB_ID');
+		$this->pc_bmid = Class_AdminVar::get('PREMIERCHAPITRE_BMID');
+		$this->pc_bmkey = Class_AdminVar::get('PREMIERCHAPITRE_BMKEY');
+		$this->active = (!empty($this->pc_bib_id) && !empty($this->pc_bmid) && !empty($this->pc_bmkey));
+	}
+
+	public function preDispatch() {
+		$no_front_actions = array();
+		$request = $this->_request;
+		$action = $request->getActionName();
+		if (!$this->active && $action != 'configure' && $action != 'adminvaredit') {
+			$request->setActionName('configure');
+			$request->setDispatched(false);
+		}
+		else 
+			// Desactiver le view renderer normal
+			if (in_array($this->_request->getParam("action"),$no_front_actions)) {
+				$viewRenderer = $this->getHelper('ViewRenderer');
+				$viewRenderer->setNoRender();
+			}
+	}
+	
+	public function indexAction() {
+		$contenu .= '<ul>';
+		$contenu .= '<li><a href="/admin/premier-chapitre/configure/">Configuration</a></li>';
+		//tant que le service n'est pas configuré on n'autorise pas les actions de mise en œuvre
+		if ($this->active) {
+			$contenu .= '<li><a href="/admin/premier-chapitre/maj-ref/">Mise à jour du référentiel</a></li>';
+			$contenu .= '<li><a href="/admin/premier-chapitre/download-ref/">Téléchargement du référentiel</a></li>';
+			$contenu .= '<li><a href="/admin/premier-chapitre/maj-db/">Mise à jour de la base</a></li>';
+			$contenu .= '<li><a href="/admin/premier-chapitre/link-notices/">Lier les notices</a></li>';
+		}
+		$contenu .= '</ul>';
+		$this->view->titre .= ' :: Index des fonctions';
+		$this->view->contenu = $contenu;
+	}
+
+	function majRefAction() {
+		$data = false;
+		$pc_ws = new Class_WebService_PremierChapitre();
+		$data = $pc_ws->generate();
+		if ($data) {
+			$contenu = date('H:i:s')." Le référentiel a bien été mise à jour\n";
+			$contenu .= '<a href="/admin/premier-chapitre/download-ref/">Téléchargement du référentiel</a>';
+		}
+		else $contenu = "Une erreur est survenue\nle référentiel n'a pas pu être mis a jour\nVeuillez réessayer ultérieurement";
+		$this->view->contenu = '<pre>'.$contenu.'</pre>';
+		$this->view->contenu .= "<br/><a href='/admin/premier-chapitre/'>Retour à l'index du service Premier-chapitre</a>";
+		$this->view->titre .= ' :: Mise à jour du référentiel';
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+	function downloadRefAction() {
+		$data = false;
+		$pc_ws = new Class_WebService_PremierChapitre();
+		$data = $pc_ws->getDatafile();
+		if ($data){
+			$contenu = date('H:i:s')." Le référentiel a bien été téléchargé sur le serveur\nIl est possible de procéder à la mise à jour de la base\n";
+			$contenu .= '<a href="/admin/premier-chapitre/maj-db/">Mise à jour de la base</a>';
+		}
+		else $contenu = "Une erreur est survenue\nle référentiel n'a pas pu être téléchargé\nVeuillez réessayer ultérieurement";
+		$this->view->contenu = '<pre>'.$contenu.'</pre>';
+		$this->view->contenu .= "<br/><a href='/admin/premier-chapitre/'>Retour à l'index du service Premier-chapitre</a>";
+		$this->view->titre .= ' :: Téléchargement du référentiel';
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+
+	function majDbAction() {
+		$data = false;
+		$pc_ws = new Class_WebService_PremierChapitre();
+		$data = $pc_ws->updateDatabase();
+		if ($data) {
+			$contenu = date('H:i:s')." La base a bien été mise à jour\n";
+			$contenu .= '* '.$data['total']." oeuvres ont été lues\n";
+			if ($data['new']) $contenu .= '* '.$data['new'].(($data['new']>1)?" ont été ajoutées":" a été ajoutée")."\n";
+			if ($data['maj']) $contenu .= '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
+			if ($data['err']) $contenu .= '* '.$data['err'].(($data['err']>1)?" erreurs n'ont pas été traitées":" erreur n'a pas été traitée")."\n";
+			$contenu .= '<a href="/admin/premier-chapitre/link-notices/">Lier les notices</a>';
+		}
+		else $contenu = "Une erreur est survenue\nLa base n'a pu être mise à jour\nVeuillez réessayer ultérieurement";
+		$this->view->contenu = '<pre>'.$contenu.'</pre>';
+		$this->view->contenu .= "<br/><a href='/admin/premier-chapitre/'>Retour à l'index du service Premier-chapitre</a>";
+		$this->view->titre .= ' :: Mise à jour de la base';
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+
+	function linkNoticesAction() {
+		$data = false;
+		$pc_ws = new Class_WebService_PremierChapitre();
+		$data = $pc_ws->linkToNotices();
+		if ($data) {
+			$contenu = date('H:i:s')." Les premiers-chapitres ont bien été liés aux notices\n";
+			$contenu .= '* '.$data['total']." oeuvres ont été traités\n";
+			$contenu .= '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
+		}
+		else $contenu = "Une erreur est survenue\nLes liaisons n'ont pu être faites\nVeuillez réessayer ultérieurement";
+		$this->view->contenu = '<pre>'.$contenu.'</pre>';
+		$this->view->contenu .= "<br/><a href='/admin/premier-chapitre/'>Retour à l'index du service Premier-chapitre</a>";
+		$this->view->titre .= ' :: Liaison aux notices';
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+
+	public function configureAction() {
+		$this->view->titre .= ' :: Configuration du service';
+	Class_ScriptLoader::getInstance()
+	->loadDataTables()
+	->addJQueryReady("$('#adminvars').dataTable({ 'iDisplayLength': -1, 'bPaginate': false, 'columnDefs' : [{'orderable': false, 'targets': 2}] })")
+	->loadJQueryUI()
+	->addJQueryReady('$(document).tooltip({
+	items: "[data-tooltip]",
+	content: function() {
+		var element = $(this);
+		var html = element.find("span").html();
+	  return (html.trim() != "") ? html : "Description non disponible";
+	},
+	position: { my: "left top+30", at: "left top"},
+	hide: {duration: 1000}
+	})');
+
+		$var_connues = array('PREMIERCHAPITRE_BIB_ID', 'PREMIERCHAPITRE_BMID', 'PREMIERCHAPITRE_BMKEY');
+		$existing_variables = Class_AdminVar::findAllBy(['where'=> "CLEF like 'PREMIERCHAPITRE%'",'order' => 'CLEF']);
+		$existing_clefs = [];
+		foreach ($existing_variables as $var)
+			$existing_clefs[] = $var->getId();
+		
+		// creer les variables manquantes
+		foreach ($var_connues as $name)
+			if (!in_array($name, $existing_clefs))
+				$existing_variables[] = Class_AdminVar::set($name, '');
+
+		$table = '<table id="adminvars">
+		<thead>
+		<tr class="soustitre">
+		  <th>'.$this->traduire('Clef').'</th>
+		  <th>'.$this->traduire('Valeur').'</th>
+		  <th>'.$this->traduire('action').'</th>
+		</tr>
+		</thead>
+		<tbody>';
+		$ligne = 0;
+		foreach($existing_variables as $var) {
+			if(preg_match('^%0D%0A^',$var->getValeur()))
+				$value = urldecode(str_replace('%0D%0A','<br />',$var->getValeur()));
+			else
+				$value = urldecode($var->getValeur());
+			$ligne ++ ;
+			$table .= '<tr class="'.(($ligne & 1) ? "first" : "second").'" data-tooltip="">
+				<td style="vertical-align:top;" >'.$var->getClef().'
+					<span style="display:none;">
+						'.Class_AdminVar::helpFor($var->getClef()).'
+					</span>
+				</td>
+				<td>';
+			$table .= wordwrap($value, 35, "<br />", 1);
+			$table .='	</td>
+				<td style="width:2%;text-align:center">
+					<a data-popup="true" href="'.$this->view->url(['action' => 'adminvaredit', 'cle' => $var->getClef()]).'">'.$this->view->boutonIco("type=edit").'</a>
+				</td>
+			</tr>';
+		}
+		$table .= '</tbody></table>';
+		$this->view->contenu = $table;
+		$this->view->contenu .= "<br/><a href='/admin/premier-chapitre/'>Retour à l'index du service Premier-chapitre</a>";
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+
+	public function adminvareditAction() {
+		$id = $this->_getParam('cle');
+                $cle = Class_AdminVar::find($id);
+
+                if ($this->_request->isPost())  {
+                        $filter = new Zend_Filter_StripTags();
+                        $new_valeur = $this->_request->getPost('valeur');
+                        $cle->setValeur(trim($filter->filter($new_valeur)));
+                        $cle->save();
+                        $this->_helper->notify('Variable '.$id.' sauvegardée');
+                        $this->_redirect('admin/premier-chapitre/adminvaredit/cle/'.$id);
+                        return;
+                }
+
+                $var_valeur = $cle->getValeur();
+
+                $var_cle = $cle->getId();
+                $tuto = Class_AdminVar::helpFor($cle->getId());
+		$contenu = '<center>
+<div class="form" align="center">
+<form name="form" action="'.BASE_URL.'/admin/premier-chapitre/adminvaredit" method="post">
+<fieldset>
+<legend>'.$this->view->traduire('Variable').'</legend>
+<br />
+<div class="formTable">
+<table cellspacing="2">
+  <tr>
+    <td class="droite">'.$var_cle.'</td>
+    <td class="gauche">'.$tuto.'</td>
+  </tr>
+   <tr>
+    <td class="droite">Nouvelle valeur</td>
+    <td class="gauche"><textarea rows="10" cols="60" name="valeur">'.$var_valeur.'</textarea></td>
+  </tr>
+</table><br />
+</div>
+<input type="hidden" name="cle" value="'.$var_cle.'"/>
+</fieldset><br>
+
+<table>
+<tr>
+    <td align="right" style="padding-right:5px;">'.$this->view->bouton('type=V').' </td>
+    <td align="left" style="padding-left:5px;"> '.$this->view->bouton('id=29','picto=back.gif','texte=Retour','url='.BASE_URL.'/admin/premier-chapitre/configure','largeur=120px').'</td>
+</tr>
+</table>
+</form>
+</div>
+</center>';
+		$this->view->titre .= ' :: Modifier la variable: ' . $cle->getId();
+		$this->view->contenu = $contenu;
+		$this->renderScript('premier-chapitre/index.phtml');
+	}
+
+        public function __call($method, $args) {
+                if ('Action' == substr($method, -6)) {
+                        // Si une méthode d'action n'est pas trouvée,
+                        // rediriger vers l'action
+                        return $this->_forward('index');
+                }
+                // pour tout autre méthode, levée d'une exception
+                throw new Exception('Méthode invalide "' . $method . '" appelée',500);
+        }
+}
+?>
diff --git a/application/modules/admin/views/scripts/premier-chapitre/index.phtml b/application/modules/admin/views/scripts/premier-chapitre/index.phtml
new file mode 100644
index 00000000000..984b2f459d8
--- /dev/null
+++ b/application/modules/admin/views/scripts/premier-chapitre/index.phtml
@@ -0,0 +1,13 @@
+<div class="titre">
+	<div class="titreInner">
+		<h1><?php echo $this->escape($this->title);?></h1>
+		<div class="rss"></div>
+	</div>
+</div>
+<div class="contenu">
+  	<div class="contenuInner">
+		<div class="news-3 news">
+<?php echo $this->contenu;?>
+		</div>
+	</div>
+</div>
\ No newline at end of file
diff --git a/application/modules/opac/controllers/PremierChapitreController.php b/application/modules/opac/controllers/PremierChapitreController.php
new file mode 100644
index 00000000000..29b9eedfa82
--- /dev/null
+++ b/application/modules/opac/controllers/PremierChapitreController.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Copyright (c) 2015, Gael VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class PremierChapitreController extends Zend_Controller_Action {
+
+	private $active;
+	public function init() {
+		$pc_bib_id = Class_AdminVar::get('PREMIERCHAPITRE_BIB_ID');
+		$pc_bmid = Class_AdminVar::get('PREMIERCHAPITRE_BMID');
+		$pc_bmkey = Class_AdminVar::get('PREMIERCHAPITRE_BMKEY');
+		$this->active = (!empty($pc_bib_id) && !empty($pc_bmid) && !empty($pc_bmkey));
+	}
+
+	public function preDispatch() {
+		$no_front_actions = array("aleatoire", "ajout-frame");
+		$request = $this->_request;
+		$action = $request->getActionName();
+		if (!$this->active && $action != 'inactive') {
+			$request->setActionName('inactive');
+			$request->setDispatched(false); //force le rechargement du controller avec la nouvelle action
+		}
+		else {
+			// Désactiver le view renderer normal pour les éléments type blocs
+			if (in_array($this->_request->getParam("action"),$no_front_actions)) {
+				$viewRenderer = $this->getHelper('ViewRenderer');
+				$viewRenderer->setNoRender();
+			}
+		}
+	}
+
+	function inactiveAction() {
+		$this->render('inactive');
+	}
+
+	function indexAction() {
+		$html = "";
+		$this->title = "";
+		$this->view->pc_ids = Class_PremierChapitre::getAleatoire(14);
+	}
+
+	function listeCompleteAction() {
+		$pcs =  Class_PremierChapitre::getAll();
+		$html = $this->view->premierChapitre_Vignettes($pcs);
+		$this->view->title = "liste des Premiers Chapitres";
+		$this->view->contenu = $html;
+		$this->renderScript('premier-chapitre/common.phtml');
+	}
+
+	function noticeAction() {
+		$ean = $this->_request->getParam('ean');
+		$ean = Class_PremierChapitre::correct_ean($ean);
+		if ($ean) {
+			$pc = Class_PremierChapitre::findFirstBy(['ean' => $ean]);
+			if ($pc) {
+				$ntc = $pc->getNotice();
+				$url_notice = ZendAfi_View_Helper_UrlNotice::urlNotice($ntc);
+				$this->_redirect($url_notice);
+			}
+			else 
+				$this->_redirect('/');
+		}
+		else 
+			$this->_redirect('/');
+	}
+
+	function ajoutFrameAction() {
+		$params = $this->_request->getParams();
+		if (!empty($params['id_notice'])) {
+			$notice = Class_Notice::find($params['id_notice']);
+			$ean = $notice->getIsbnOrEan();
+		}
+		else {
+			$ean = (!empty($params['ean']))?$params['ean']:((!empty($params['id']))?$params['id']:"");
+		}
+		$ean = Class_PremierChapitre::getLoader()->correct_ean($ean);
+		$html = "";
+		if ($ean) {
+			$pc = Class_PremierChapitre::findFirstBy(['ean' => $ean]);
+			if (!empty($pc)) {
+				$html = $this->view->premierChapitre_Frame($pc);
+			}
+		}
+		$this->getResponse()->setHeader('Content-Type', 'text/html;charset=utf-8');
+		$this->getResponse()->setBody($html . Class_ScriptLoader::getInstance()->html());
+	}
+
+	function aleatoireAction() {
+		$nb = $this->_request->getParam('nb');
+		if (!preg_match('@^\d+$@',$nb))
+			$pcs =  Class_PremierChapitre::getAleatoire();
+		else 
+			$pcs =  Class_PremierChapitre::getAleatoire($nb);
+		$html = $this->view->premierChapitre_Vignettes($pcs);
+		$this->getResponse()->setHeader('Content-Type', 'text/html;charset=utf-8');
+		$this->getResponse()->setHeader('Pragma', 'no-cache', true);
+		$this->getResponse()->setBody($html . Class_ScriptLoader::getInstance()->html());
+	}
+
+	public function __call($method, $args) {
+		if ('Action' == substr($method, -6)) {
+			// Si une méthode d'action n'est pas trouvée,
+			// rediriger vers l'action
+			return $this->_forward('index');
+		}
+		// pour tout autre méthode, levée d'une exception
+		throw new Exception('Méthode invalide "' . $method . '" appelée',500);
+	}
+}
+?>
diff --git a/application/modules/opac/views/scripts/premier-chapitre/common.phtml b/application/modules/opac/views/scripts/premier-chapitre/common.phtml
new file mode 100644
index 00000000000..2bfe9708e94
--- /dev/null
+++ b/application/modules/opac/views/scripts/premier-chapitre/common.phtml
@@ -0,0 +1,13 @@
+<div class="titre">
+	<div class="titreInner">
+		<h1><?php echo $this->escape($this->title);?></h1>
+		<div class="rss"></div>
+	</div>
+</div>
+<div class="contenu">
+  	<div class="contenuInner">
+		<div class="news-3 news">
+<?php echo $this->contenu;?>
+		</div>
+	</div>
+</div>
diff --git a/application/modules/opac/views/scripts/premier-chapitre/inactive.phtml b/application/modules/opac/views/scripts/premier-chapitre/inactive.phtml
new file mode 100644
index 00000000000..c15b626f412
--- /dev/null
+++ b/application/modules/opac/views/scripts/premier-chapitre/inactive.phtml
@@ -0,0 +1 @@
+Service inactif
diff --git a/application/modules/opac/views/scripts/premier-chapitre/index.phtml b/application/modules/opac/views/scripts/premier-chapitre/index.phtml
new file mode 100644
index 00000000000..f1e43c1af94
--- /dev/null
+++ b/application/modules/opac/views/scripts/premier-chapitre/index.phtml
@@ -0,0 +1,18 @@
+<div class="titre">
+	<div class="titreInner">
+		<h1><?php echo $this->escape($this->title);?></h1>
+		<div class="rss"></div>
+	</div>
+</div>
+<div class="contenu">
+  	<div class="contenuInner">
+		<div class="news-3 news">
+		<div>
+			<p><img src="/public/opac/images/lireavecpremierchapitre.png" alt="premierchapitre" style="position:relative;top:-5px;"></p>
+			<p><span style="font-size:12px">Cliquez sur une couverture pour lire un extrait. Vous pouvez ensuite récupérer le livre à la bibliothèque.</span></p>
+			<p><span style="font-size:12px"><a href="/premier-chapitre/liste-complete/">Cliquez ici Pour voir la liste complète <img src="/public/opac/images/buttons/2rightarrow.png"></a></span></p>
+		</div>
+<?php echo $this->premierChapitre_Vignettes($this->pc_ids,['target' => 'frame', 'linkNotice' => 1]); ?>
+		</div>
+	</div>
+</div>
diff --git a/application/modules/opac/views/scripts/recherche/viewnotice.phtml b/application/modules/opac/views/scripts/recherche/viewnotice.phtml
index 83c3650763e..a7fda1b98e3 100644
--- a/application/modules/opac/views/scripts/recherche/viewnotice.phtml
+++ b/application/modules/opac/views/scripts/recherche/viewnotice.phtml
@@ -95,8 +95,9 @@ $script_loader = Class_ScriptLoader::getInstance()
     </div>
   </div>
 </div>
-
 <?php
+//picto premier-chapitre
+echo $this->premierChapitre_Lien($this->notice,['targetLink'=>'ancre']);
 // Entete Notice
 echo sprintf('<div class="entete_notice">%s</div>'.
 						 '<div class="flags_notice">%s</div>'.
@@ -106,6 +107,7 @@ echo sprintf('<div class="entete_notice">%s</div>'.
 						 $this->notice_Flags($this->notice, $this->preferences),
 						 $this->notice_Blocs($this->notice, $this->preferences)."<div class='clear'></div>",
 						 $this->notice_Onglets($this->notice, $this->preferences));
-
+//frame premier-chapitre
+echo '<a name="pc_ancre"></a>'.$this->premierChapitre_Frame($this->notice);
 $this->closeBoite();
 ?>
diff --git a/cosmogramme/sql/patch/patch_260.php b/cosmogramme/sql/patch/patch_260.php
new file mode 100644
index 00000000000..d4938cdb2ed
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_260.php
@@ -0,0 +1,13 @@
+<?php
+$adapter = Zend_Registry::get('sql');
+$adapter->query('CREATE TABLE IF NOT EXISTS `pc_database` ( '
+			.'`ean` varchar(17) NOT NULL, '
+			.'`url` varchar(250) NOT NULL, '
+			.'`titre` text NOT NULL, '
+			.'`auteur` text NOT NULL, '
+			.'`couverture` varchar(250) NOT NULL, '
+			.'`couverture_mini` varchar(250) NOT NULL, '
+			.'`clef_oeuvre` varchar(200) NOT NULL '
+			.') engine=MyISAM default charset=utf8;');
+$adapter->query('ALTER TABLE `pc_database` ADD PRIMARY KEY (`ean`), ADD UNIQUE KEY `ean` (`ean`);');
+?>
\ No newline at end of file
diff --git a/library/Class/Batch/PremierChapitre.php b/library/Class/Batch/PremierChapitre.php
new file mode 100644
index 00000000000..cbfc2bc81b3
--- /dev/null
+++ b/library/Class/Batch/PremierChapitre.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_Batch_PremierChapitre extends Class_Batch_RessourceNumerique{
+	protected function _getService() {
+		return new Class_WebService_PremierChapitre();
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/PremierChapitre.php b/library/Class/PremierChapitre.php
new file mode 100644
index 00000000000..b4b73109d51
--- /dev/null
+++ b/library/Class/PremierChapitre.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+class PremierChapitreLoader extends Storm_Model_Loader {
+	//nettoyage de l'entrée isbn/ean
+	public function correct_ean($isbn) {
+		$elem = new Class_Isbn($isbn);
+		$ean = $elem->getAll();
+		if ($ean['statut'] != 2) return false;
+		if (!empty($ean['ean'])) return $ean['ean'];
+		if (!empty($ean['isbn13']))	return str_replace('-','',$ean['isbn13']);
+		return false;
+	}
+	
+	public function getPremierChapitreIdsByRequete($req) {
+		if (!$req)
+			return [];
+
+		$closure = function() use ($req) {
+			return Zend_Registry::get('sql')->fetchAllByColumn($req);
+		};
+		return (new Storm_Cache())
+			->useImplodeExplodeSerialization()
+			->memoize([$req, __CLASS__, __FUNCTION__],
+								$closure);
+	}
+
+	public function findAllByRequete($req, $nb_par_page, $page_no=1 ) {
+		if (!$page_no) $page_no=1;
+		$ids = $this->getPremierChapitreIdsByRequete($req);
+		if ($nb_par_page)
+			$ids = array_slice($ids,
+					 ($page_no-1) * $nb_par_page,
+					 $nb_par_page);
+		if (empty($ids))
+			return [];
+		return $this->findAllBy(['ean' => $ids, 'order' => 'titre ASC']);
+	}
+	
+	public function getAll($nb_par_page, $page_no=1) {
+		$req = "select t.`ean` from pc_database t left join notices n on replace(n.`isbn`,'-','') = t.`ean` or n.`clef_oeuvre` = t.`clef_oeuvre` where n.`id_notice` is not null";
+		if ($nb_par_page) return $this->findAllByRequete($req,$nb_par_page,$page_no);
+		else return $this->findAllByRequete($req);
+	}
+	
+	public function getAleatoire($nb_aff) {
+		if (!$nb_aff) $nb_aff = 8;
+		$req = "select t.`ean` from pc_database t\n";
+		$req .="left join notices n on replace(n.`isbn`,'-','') = t.`ean`\n";
+		$req .= "where n.`id_notice` is not null ORDER BY RAND() LIMIT 0,".$nb_aff;
+		return $this->findAllByRequete($req);
+	}
+	
+	public function getByClef($clef) {
+		return $this->findFirstBy(['clef_oeuvre' => $clef]);
+	}
+	
+	public function getByNotice($ntc) {
+		$pc = $this->getByClef($ntc->getClefOeuvre());
+		if (!$pc) {
+			$ean = $this->correct_ean($ntc->getIsbn());
+			if ($ean) {
+				$pc = $this->findFirstBy(['ean' =>$ean]);
+				if($pc) $pc->setClefOeuvre($ntc->getClefOeuvre())->save();
+			}
+		}
+		return $pc;
+	}
+}
+
+class Class_PremierChapitre extends Storm_Model_Abstract {
+	protected $_loader_class = 'PremierChapitreLoader';
+	protected $_table_name = 'pc_database';
+	protected $_table_primary = 'ean';
+	
+	protected $_default_attribute_values = [
+		'ean' => '',
+		'url' => '',
+		'titre' => '',
+		'auteur' => '',
+		'couverture' => '',
+		'couverture_mini' => '',
+		'clef_oeuvre' => ''];
+	protected $_belongs_to = ['notice' => ['model' => 'Class_Notice', 'referenced_in' => 'clef_oeuvre']];
+	
+	public function getMiniature() {
+		return $this->getCouvertureMini();
+	}
+
+	public function getNotice() {
+		$cle = $this->getClefOeuvre();
+		if (!empty($cle)) {
+			$ntc = Class_Notice::findFirstBy(['clef_oeuvre' => $cle]);
+		}
+		else {
+			//on fait une recherche simple de la notice
+			$ntc = Class_Notice::findFirstBy(['where' => "replace(`isbn`,'-','') = '".$this->getId()."'"]);
+			if ($ntc) {
+				//on met à jour l'enregistrement premier-chapitre
+				$this->setClefOeuvre($ntc->getClefOeuvre())->save();
+			}
+		}
+		return $ntc;
+	}
+}
+?>
diff --git a/library/Class/WebService/PremierChapitre.php b/library/Class/WebService/PremierChapitre.php
new file mode 100644
index 00000000000..963b8d0f8f2
--- /dev/null
+++ b/library/Class/WebService/PremierChapitre.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+ 
+class Class_WebService_PremierChapitre {// extends Class_WebService_Abstract { - on redefini l'ensemble du modele a l'identique 
+	protected $_message;
+	protected static $_http_client;
+	protected static $_auth = false;
+	protected static $_baseurl = 'http://www.premierchapitre.fr/client/';
+	protected static $_datafile = "liste_livre.xml";
+
+	private $pc_bib_id;
+	private	$pc_bmid;
+	private	$pc_bmkey;
+	
+	public function __construct() {
+		$this->pc_bib_id = Class_AdminVar::get('PREMIERCHAPITRE_BIB_ID');
+		$this->pc_bmid = Class_AdminVar::get('PREMIERCHAPITRE_BMID');
+		$this->pc_bmkey = Class_AdminVar::get('PREMIERCHAPITRE_BMKEY');
+	}
+
+	public static function setDefaultHttpClient($http_client) {
+		static::$_http_client = $http_client;
+	}
+
+	public static function getHttpClient() {
+		if (static::$_http_client==null ||  !isset(static::$_http_client)) {
+			static::$_http_client = new Zend_Http_Client(static::$_baseurl, array('keepalive' => true));
+			static::$_http_client->setCookieJar();
+		}
+		return	static::$_http_client;
+	}
+	public static function resetHttpClient() {
+		static::$_http_client = null;
+		static::$_auth = false;
+	}
+
+	public function authentify() {
+		$access_url = static::$_baseurl.'connexion/connexion.php';
+		$access_params = ["rep" => $this->pc_bib_id, "email" => $this->pc_bmid, "mdp" => $this->pc_bmkey];
+		$admin_url = static::$_baseurl.$this->pc_bib_id.'/';
+
+		if(static::$_auth == true) {
+			$data = $this->httpGet($admin_url);
+			if (preg_match('@body data-client="([^"]*)"@Usi',$data->getBody(),$m)) {
+				return static::$_auth;
+			}
+			static::$_auth = false;
+		}
+		$this->httpPost($access_url,$access_params);
+		$data = $this->httpGet($admin_url);
+		if (preg_match('@body data-client="([^"]*)"@Usi',$data->getBody(),$m)) {
+			static::$_auth = true;
+		}
+		return static::$_auth;
+	}
+	
+	public function generate() {
+		if (!$this->authentify()) {
+			throw new Exception("PremierChapitre : Erreur d'identification au service",500);
+			return false;
+		}
+		$admin_url = static::$_baseurl.$this->pc_bib_id.'/';
+		$data = $this->httpGet($admin_url);
+		if (!preg_match('@body data-client="([^"]*)"@Usi',$data->getBody(),$m)) {
+			static::$_auth = false;
+			throw new Exception("PremierChapitre : Erreur d'identification au service",500);
+			return false;
+		}
+		$clientId = $m[1];
+	        $generate_url = static::$_baseurl.'class/generation_xml.php';
+		$generate_params = ['clientId'=>$clientId,'clientRep'=>$this->pc_bib_id];
+		$data = $this->httpPost($generate_url,$generate_params);
+		//$this->setMessage("Mise à jour : ".date("d/m/Y à H:i:s"));
+		if ($data->getMessage() == "OK") return true;
+		return false;
+		//return $data;
+	}
+	public function getDatafile() {
+		if (!$this->authentify()) {
+			throw new Exception("PremierChapitre : Erreur d'identification au service",500);
+			return false;
+		}
+		$download_url = static::$_baseurl.'plugin/php_download/download.php?f=liste_livre.xml&r='.$this->pc_bib_id;
+		$data = $this->httpGet($download_url);
+		$ret = file_put_contents(static::$_datafile,$data->getBody());
+		if ($ret === false) {
+			throw new Exception("PremierChapitre : Erreur de récupération des données",500);
+			return false;
+		}
+		return true;
+	}
+	
+	public function updateDatabase() {
+		if (!file_exists(static::$_datafile)) {
+			$this->getDatafile();
+		}
+		$champs = array(
+			'ean' => '',
+			'url_reader' => 'url',
+			'titre' => '',
+			'auteur_nom' => 'auteur',
+			'url_couverture' => 'couverture',
+			'url_couverture_small' => 'couverture_mini',
+		);
+		$datas = file_get_contents(static::$_datafile);
+		$xmlObj = simplexml_load_string($datas);
+		$datas = $this->objectsIntoArray($xmlObj);
+		//on charge la base actuelle
+		$pc_all = Class_PremierChapitre::findAll();
+		$pc_db = array();
+		foreach ($pc_all as $ch) {
+			$pc_db[$ch->getId()] = $ch;
+		}
+		//on procède à la moisson : mise a jour des données existantes et ajout des nouveaux enregistrements
+		$cpt = ['maj' => 0, 'new' => 0, 'err' =>0, 'total' => count($datas['livre'])];
+		foreach ($datas['livre'] as $key => $item) {
+			//on nettoie l'ean/isbn 
+			$id = Class_PremierChapitre::correct_ean($item['ean']);
+			if ($id) {
+				$item['ean'] = $id;
+				//le document existe deja dans la base
+				if (!empty($pc_db[$id])) {
+					$m = false;
+					foreach ($champs as $k => $v) {
+						$f = $k;
+						$tmp = (!empty($item[$f]))?trim($item[$f]):'';
+						if (!empty($v)) $f = $v;
+						if ($pc_db[$id]->callGetterByAttributeName($f) != $tmp) {
+							$pc_db[$id]->callSetterByAttributeName($f,$tmp);
+							$m = true;
+						}
+					}
+					if($m) {
+						$pc_db[$id]->save();
+						$cpt['maj']++;
+					}
+				}
+				else {
+					$chap = array();
+					foreach ($champs as $k => $v) {
+						$f = $k;
+						$tmp = (!empty($item[$f]))?trim($item[$f]):'';
+						if (!empty($v)) $f = $v;
+						$chap[$f] = $tmp;
+					}
+					$cur_pc = Class_PremierChapitre::newInstance($chap);
+					$cur_pc->save();
+					$pc_db[$id] = $cur_pc;
+					$cpt['new']++;
+				}
+			}
+			else {
+				//ean incorrect on ignore
+				$cpt['err']++;
+			}
+		}
+		return $cpt;
+	}
+	
+	public function linkToNotices() {
+		$data = fetchAll("select t.`ean`, n.`clef_oeuvre` from pc_database t left join notices n on replace(n.`isbn`,'-','') = t.`ean` where n.`clef_oeuvre` is not null");
+		if (!$data)	return false;
+		$pc_all = Class_PremierChapitre::findAll();
+		$pc_db = array();
+		foreach ($pc_all as $ch) {
+			$pc_db[$ch->getId()] = $ch;
+		}
+		$cpt = ['maj' => 0, 'total' => count($data)];
+		foreach ($data as $enreg) {
+			$f = "clef_oeuvre";
+			if (!$enreg[$f]) continue;
+			$id = $enreg["ean"]; $tmp = $enreg[$f];
+			if (!empty($pc_db[$id])) {
+				if ($pc_db[$id]->callGetterByAttributeName($f) != $tmp) {
+					$pc_db[$id]->callSetterByAttributeName($f,$tmp);
+					$pc_db[$id]->save();
+					$cpt['maj']++;
+				}
+			}
+		}
+		return $cpt;
+	}
+
+	function setMessage($message) {
+		$this->_message=$message;
+	}
+	function getMessage() {
+		return $this->_message;
+	}
+
+	public function httpGet($url) {
+		$client = $this->getHttpClient();
+		$client->resetParameters();
+		$client->setUri($url);
+		return $client->request(Zend_Http_Client::GET);
+	}
+	public function httpPost($url,$params) {
+		$client = $this->getHttpClient();
+		$client->resetParameters();
+		$client->setUri($url);
+		$client->setParameterPost($params);
+		return $client->request(Zend_Http_Client::POST);
+	}
+	
+	public function isEnabled() {
+		 return ('' != trim(Class_AdminVar::get('PREMIERCHAPITRE_BIB_ID')));
+	}
+	public function getName() {
+		return 'Premier-Chapitre';
+	}
+	protected function _deleteNonHarvested() {
+		return $this;
+	}
+	private function objectsIntoArray($arrObjData, $arrSkipIndices = array()) {
+		$arrData = array();
+		// if input is object, convert into array
+		if (is_object($arrObjData)) {
+			$arrObjData = get_object_vars($arrObjData);
+		}
+		if (is_array($arrObjData)) {
+			foreach ($arrObjData as $index => $value) {
+				if (is_object($value) || is_array($value)) {
+					$value = $this->objectsIntoArray($value, $arrSkipIndices); // recursive call
+				}
+				if (in_array($index, $arrSkipIndices)) {
+					continue;
+				}
+				$arrData[$index] = $value;
+			}
+		}
+		return $arrData;
+	}
+	
+	public function update() {
+	}
+	public function harvest() {
+	}
+}
+?>
diff --git a/library/ZendAfi/View/Helper/ListeNotices/Vignettes.php b/library/ZendAfi/View/Helper/ListeNotices/Vignettes.php
index 957571966f2..287af74c6e4 100644
--- a/library/ZendAfi/View/Helper/ListeNotices/Vignettes.php
+++ b/library/ZendAfi/View/Helper/ListeNotices/Vignettes.php
@@ -46,7 +46,8 @@ class ZendAfi_View_Helper_ListeNotices_Vignettes extends ZendAfi_View_Helper_Lis
 			. $this->_author($notice, $url_notice)
 			. $this->_docType($notice)
 			. $this->_image($notice, $preferences)
-			. $this->_info($notice, $champs);
+			. $this->_info($notice, $champs)
+			. $this->_pcTag($notice);
 
 		return $this->_tag('div', $html, ['class' => 'vignette',
 																			'data-id' => $notice->getId()]);
@@ -106,7 +107,9 @@ class ZendAfi_View_Helper_ListeNotices_Vignettes extends ZendAfi_View_Helper_Lis
 																				['entete' => str_replace('T', '', $fields)]),
 						 ['class' => 'vignette_info']);
 	}
-
+	protected function _pcTag($record) {
+		return $this->_tag('div',$this->view->premierChapitre_Lien($record),['style' => 'margin-left:70px;']);
+	}
 
 	protected function _readSpeakerTagFor($record) {
 		if (!$this->_read_speaker)
diff --git a/library/ZendAfi/View/Helper/PremierChapitre/Abstract.php b/library/ZendAfi/View/Helper/PremierChapitre/Abstract.php
new file mode 100644
index 00000000000..cf264031769
--- /dev/null
+++ b/library/ZendAfi/View/Helper/PremierChapitre/Abstract.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+abstract class ZendAfi_View_Helper_PremierChapitre_Abstract extends ZendAfi_View_Helper_BaseHelper {
+	public function loadScript(){}
+	protected function _tag($name, $content=null, $attribs=[]) {
+		$html = '<' . $name . $this->_htmlAttribs($attribs);
+		if (null === $content)
+			return $html . $this->getClosingBracket();
+		return $html . '>' . $content . '</' . $name . '>';
+	}
+	
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/PremierChapitre/Frame.php b/library/ZendAfi/View/Helper/PremierChapitre/Frame.php
new file mode 100644
index 00000000000..69326253fa1
--- /dev/null
+++ b/library/ZendAfi/View/Helper/PremierChapitre/Frame.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_PremierChapitre_Frame extends ZendAfi_View_Helper_PremierChapitre_Abstract {
+	public function premierChapitre_Frame($data, $preferences=[]) {
+		$this->loadScript();
+		$html = '';
+		$pc_active = new Class_WebService_PremierChapitre();
+		if (!$pc_active->isEnabled()) return $html;
+		if ($data instanceOf Class_PremierChapitre) $pc = $data;
+		else if ($data instanceOf Class_Notice) {
+			$ntc = $data;
+			$pc = Class_PremierChapitre::getByNotice($ntc);
+			if (!$pc) return $html;
+		}
+		else return $html;
+		$frm_attribs = ['id' => 'pc_frame',
+						'class' => 'iframe_premierchapitre',
+						'style' => 'width:700px; height:700px; border:none;',
+						'src' => $pc->getUrl()];
+		return $this->_tag('iframe',null,$frm_attribs);
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/PremierChapitre/Lien.php b/library/ZendAfi/View/Helper/PremierChapitre/Lien.php
new file mode 100644
index 00000000000..804fd80f4d0
--- /dev/null
+++ b/library/ZendAfi/View/Helper/PremierChapitre/Lien.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_PremierChapitre_Lien extends ZendAfi_View_Helper_PremierChapitre_Abstract {
+	private $_img = '/public/opac/images/lireavecpremierchapitre.png';
+
+	public function premierChapitre_Lien($data, $preferences=[]) {
+		$this->loadScript();
+		$html = '';
+		$pc_active = new Class_WebService_PremierChapitre();
+		if (!$pc_active->isEnabled()) return $html;
+		if ($data instanceOf Class_PremierChapitre) $pc = $data;
+		else if ($data instanceOf Class_Notice) {
+			$ntc = $data;
+			$pc = Class_PremierChapitre::getByNotice($ntc);
+			if (!$pc) return $html;
+		}
+		else return $html;
+		$lnk_attribs = [ 'id' => 'pc_lienNotice',
+						'href' => $pc->getUrl()];
+		$contenu = $this->_tag('img',null,['src' => $this->_img,
+											'style' => 'height: 30px; margin-left: 30px;']);
+		if ($preferences['linkNotice']) {
+			$lnk_attribs['href'] = '/premier-chapitre/notice/ean/'.$pc->getId();
+			$contenu = 'Voir le document';
+		}
+		else if ($preferences['targetLink'] == 'ancre' ) {
+			$lnk_attribs['href'] = '#pc_ancre';
+		}
+		
+		return $this->_tag('a',$contenu,$lnk_attribs);
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/PremierChapitre/Vignettes.php b/library/ZendAfi/View/Helper/PremierChapitre/Vignettes.php
new file mode 100644
index 00000000000..8afecf9cae8
--- /dev/null
+++ b/library/ZendAfi/View/Helper/PremierChapitre/Vignettes.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright (c) 2015, Gaël VINOT (Ville de Montrouge). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_PremierChapitre_Vignettes extends ZendAfi_View_Helper_PremierChapitre_Abstract 	  {
+	private $_imgCss = 'margin: 5px;box-sizing: border-box;box-shadow: 0 1px 2px rgba(0,0,0,.075);padding: 4px;max-height: 122px; max-width: 200px;';
+
+	public function premierChapitre_Vignettes($data, $preferences=[]) {
+		$this->loadScript();
+		$html = '';
+		$pc_active = new Class_WebService_PremierChapitre();
+		if (!$pc_active->isEnabled()) return $html;
+		$bloc_vignettes = '';
+		foreach($data as $pc) {
+			if ($preferences['target'] == 'frame')
+				$bloc_vignettes .= $this->_vignetteFrame($pc,$preferences);
+			else 
+				$bloc_vignettes .= $this->_vignetteNotice($pc,$preferences);
+		}
+		$html .= $this->_tag('div',$bloc_vignettes);
+		if ($preferences['linkNotice']) {
+			$html .= $this->_tag('div','<p></p><p>'.$this->view->premierChapitre_Lien($data[0],$preferences).'</p>');
+		}
+		if ($preferences['target'] == 'frame') {
+			$html .= $this->view->premierChapitre_Frame($data[0],$preferences);
+		}
+		return $this->_tag('div', $html);
+	}
+	
+	protected function _vignetteFrame($pc, $preferences){
+		$onclick = "\$('#pc_frame')[0].src='".$pc->getUrl()."';";
+		if($preferences['linkNotice'])
+			$onclick .= "\$('#pc_lienNotice')[0].href='/premier-chapitre/notice/ean/".$pc->getId()."';";
+		
+		$lnk_attribs = ['onclick' => $onclick,'style'=>'cursor:pointer;'];
+		return $this->_tag('a',$this->_vignetteImg($pc),$lnk_attribs);
+	}
+	
+	protected function _vignetteNotice($pc, $preferences){
+		$lnk_attribs = ['href' => '/premier-chapitre/notice/ean/"'.$pc->getId()];
+						
+		return $this->_tag('a',$this->_vignetteImg($pc),$lnk_attribs);
+	}
+	
+	protected function _vignetteImg($pc){
+		$img_attribs = ['src' => $pc->getMiniature(),
+						'alt' => $pc->getTitre().' - '.$pc->getAuteur(),
+						'title' => $pc->getTitre().' - '.$pc->getAuteur(),
+						'style' => $this->_imgCss,
+						'data-toggwle'=>"tooltip"];
+		return $this->_tag('img',null,$img_attribs);
+	}
+}
+?>
\ No newline at end of file
diff --git a/public/opac/images/lireavecpremierchapitre.png b/public/opac/images/lireavecpremierchapitre.png
new file mode 100644
index 0000000000000000000000000000000000000000..6f476daa254509ae2d77129995f1f0fa59d038f6
GIT binary patch
literal 9853
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

literal 0
HcmV?d00001

-- 
GitLab