Merge pull request #634 from wallabag/dev

1.6.1
This commit is contained in:
Nicolas Lœuillet 2014-04-11 17:22:04 +02:00
commit 4a74d9857c
16 changed files with 779 additions and 714 deletions

View file

@ -4,7 +4,7 @@ wallabag is a self hostable application allowing you to not miss any content any
More informations on our website: [wallabag.org](http://wallabag.org) More informations on our website: [wallabag.org](http://wallabag.org)
## License ## License
Copyright © 2010-2013 Nicolas Lœuillet <nicolas@loeuillet.org> Copyright © 2010-2014 Nicolas Lœuillet <nicolas@loeuillet.org>
This work is free. You can redistribute it and/or modify it under the This work is free. You can redistribute it and/or modify it under the
terms of the Do What The Fuck You Want To Public License, Version 2, terms of the Do What The Fuck You Want To Public License, Version 2,
as published by Sam Hocevar. See the COPYING file for more details. as published by Sam Hocevar. See the COPYING file for more details.

View file

@ -10,177 +10,188 @@
*/ */
class FeedItem class FeedItem
{ {
private $elements = array(); //Collection of feed elements private $elements = array(); //Collection of feed elements
private $version; private $version;
/** /**
* Constructor * Constructor
* *
* @param contant (RSS1/RSS2/ATOM) RSS2 is default. * @param contant (RSS1/RSS2/ATOM) RSS2 is default.
*/ */
function __construct($version = RSS2) function __construct($version = RSS2)
{ {
$this->version = $version; $this->version = $version;
} }
/** /**
* Set element (overwrites existing elements with $elementName) * Set element (overwrites existing elements with $elementName)
* *
* @access public * @access public
* @param srting The tag name of an element * @param srting The tag name of an element
* @param srting The content of tag * @param srting The content of tag
* @param array Attributes(if any) in 'attrName' => 'attrValue' format * @param array Attributes(if any) in 'attrName' => 'attrValue' format
* @return void * @return void
*/ */
public function setElement($elementName, $content, $attributes = null) public function setElement($elementName, $content, $attributes = null)
{ {
if (isset($this->elements[$elementName])) { if (isset($this->elements[$elementName])) {
unset($this->elements[$elementName]); unset($this->elements[$elementName]);
} }
$this->addElement($elementName, $content, $attributes); $this->addElement($elementName, $content, $attributes);
} }
/** /**
* Add an element to elements array * Add an element to elements array
* *
* @access public * @access public
* @param srting The tag name of an element * @param srting The tag name of an element
* @param srting The content of tag * @param srting The content of tag
* @param array Attributes(if any) in 'attrName' => 'attrValue' format * @param array Attributes(if any) in 'attrName' => 'attrValue' format
* @return void * @return void
*/ */
public function addElement($elementName, $content, $attributes = null) public function addElement($elementName, $content, $attributes = null)
{ {
$i = 0; $i = 0;
if (isset($this->elements[$elementName])) { if (isset($this->elements[$elementName])) {
$i = count($this->elements[$elementName]); $i = count($this->elements[$elementName]);
} else { } else {
$this->elements[$elementName] = array(); $this->elements[$elementName] = array();
} }
$this->elements[$elementName][$i]['name'] = $elementName; $this->elements[$elementName][$i]['name'] = $elementName;
$this->elements[$elementName][$i]['content'] = $content; $this->elements[$elementName][$i]['content'] = $content;
$this->elements[$elementName][$i]['attributes'] = $attributes; $this->elements[$elementName][$i]['attributes'] = $attributes;
} }
/** /**
* Set multiple feed elements from an array. * Set multiple feed elements from an array.
* Elements which have attributes cannot be added by this method * Elements which have attributes cannot be added by this method
* *
* @access public * @access public
* @param array array of elements in 'tagName' => 'tagContent' format. * @param array array of elements in 'tagName' => 'tagContent' format.
* @return void * @return void
*/ */
public function addElementArray($elementArray) public function addElementArray($elementArray)
{ {
if(! is_array($elementArray)) return; if(! is_array($elementArray)) return;
foreach ($elementArray as $elementName => $content) foreach ($elementArray as $elementName => $content)
{ {
$this->addElement($elementName, $content); $this->addElement($elementName, $content);
} }
} }
/** /**
* Return the collection of elements in this feed item * Return the collection of elements in this feed item
* *
* @access public * @access public
* @return array * @return array
*/ */
public function getElements() public function getElements()
{ {
return $this->elements; return $this->elements;
} }
// Wrapper functions ------------------------------------------------------ // Wrapper functions ------------------------------------------------------
/** /**
* Set the 'dscription' element of feed item * Set the 'dscription' element of feed item
* *
* @access public * @access public
* @param string The content of 'description' element * @param string The content of 'description' element
* @return void * @return void
*/ */
public function setDescription($description) public function setDescription($description)
{ {
$tag = 'description'; $this->setElement('description', $description);
$this->setElement($tag, $description); }
}
/** /**
* @desc Set the 'title' element of feed item * @desc Set the 'title' element of feed item
* @access public * @access public
* @param string The content of 'title' element * @param string The content of 'title' element
* @return void * @return void
*/ */
public function setTitle($title) public function setTitle($title)
{ {
$this->setElement('title', $title); $this->setElement('title', $title);
} }
/** /**
* Set the 'date' element of feed item * Set the 'date' element of feed item
* *
* @access public * @access public
* @param string The content of 'date' element * @param string The content of 'date' element
* @return void * @return void
*/ */
public function setDate($date) public function setDate($date)
{ {
if(! is_numeric($date)) if(! is_numeric($date))
{ {
$date = strtotime($date); $date = strtotime($date);
} }
if($this->version == RSS2) if($this->version == RSS2)
{ {
$tag = 'pubDate'; $tag = 'pubDate';
$value = date(DATE_RSS, $date); $value = date(DATE_RSS, $date);
} }
else else
{ {
$tag = 'dc:date'; $tag = 'dc:date';
$value = date("Y-m-d", $date); $value = date("Y-m-d", $date);
} }
$this->setElement($tag, $value); $this->setElement($tag, $value);
} }
/** /**
* Set the 'link' element of feed item * Set the 'link' element of feed item
* *
* @access public * @access public
* @param string The content of 'link' element * @param string The content of 'link' element
* @return void * @return void
*/ */
public function setLink($link) public function setLink($link)
{ {
if($this->version == RSS2 || $this->version == RSS1) if($this->version == RSS2 || $this->version == RSS1)
{ {
$this->setElement('link', $link); $this->setElement('link', $link);
$this->setElement('guid', $link); $this->setElement('guid', $link);
} }
else else
{ {
$this->setElement('link','',array('href'=>$link)); $this->setElement('link','',array('href'=>$link));
$this->setElement('id', FeedWriter::uuid($link,'urn:uuid:')); $this->setElement('id', FeedWriter::uuid($link,'urn:uuid:'));
} }
} }
/** /**
* Set the 'encloser' element of feed item * Set the 'source' element of feed item
* For RSS 2.0 only *
* * @access public
* @access public * @param string The content of 'source' element
* @param string The url attribute of encloser tag * @return void
* @param string The length attribute of encloser tag */
* @param string The type attribute of encloser tag public function setSource($link)
* @return void {
*/ $this->setElement('source', $link);
public function setEncloser($url, $length, $type) }
{
$attributes = array('url'=>$url, 'length'=>$length, 'type'=>$type); /**
$this->setElement('enclosure','',$attributes); * Set the 'encloser' element of feed item
} * For RSS 2.0 only
*
* @access public
* @param string The url attribute of encloser tag
* @param string The length attribute of encloser tag
* @param string The type attribute of encloser tag
* @return void
*/
public function setEncloser($url, $length, $type)
{
$attributes = array('url'=>$url, 'length'=>$length, 'type'=>$type);
$this->setElement('enclosure','',$attributes);
}
} // end of class FeedItem } // end of class FeedItem
?> ?>

View file

@ -18,424 +18,423 @@ define('JSONP', 3, true);
*/ */
class FeedWriter class FeedWriter
{ {
private $self = null; // self URL - http://feed2.w3.org/docs/warning/MissingAtomSelfLink.html private $self = null; // self URL - http://feed2.w3.org/docs/warning/MissingAtomSelfLink.html
private $hubs = array(); // PubSubHubbub hubs private $hubs = array(); // PubSubHubbub hubs
private $channels = array(); // Collection of channel elements private $channels = array(); // Collection of channel elements
private $items = array(); // Collection of items as object of FeedItem class. private $items = array(); // Collection of items as object of FeedItem class.
private $data = array(); // Store some other version wise data private $data = array(); // Store some other version wise data
private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA
private $xsl = null; // stylesheet to render RSS (used by Chrome) private $xsl = null; // stylesheet to render RSS (used by Chrome)
private $json = null; // JSON object private $json = null; // JSON object
private $version = null; private $version = null;
/** /**
* Constructor * Constructor
* *
* @param constant the version constant (RSS2 or JSON). * @param constant the version constant (RSS2 or JSON).
*/ */
function __construct($version = RSS2) function __construct($version = RSS2)
{ {
$this->version = $version; $this->version = $version;
// Setting default value for assential channel elements // Setting default value for assential channel elements
$this->channels['title'] = $version . ' Feed'; $this->channels['title'] = $version . ' Feed';
$this->channels['link'] = 'http://www.ajaxray.com/blog'; $this->channels['link'] = 'http://www.ajaxray.com/blog';
//Tag names to encode in CDATA //Tag names to encode in CDATA
$this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary'); $this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary');
} }
public function setFormat($format) { public function setFormat($format) {
$this->version = $format; $this->version = $format;
} }
// Start # public functions --------------------------------------------- // Start # public functions ---------------------------------------------
/** /**
* Set a channel element * Set a channel element
* @access public * @access public
* @param srting name of the channel tag * @param srting name of the channel tag
* @param string content of the channel tag * @param string content of the channel tag
* @return void * @return void
*/ */
public function setChannelElement($elementName, $content) public function setChannelElement($elementName, $content)
{ {
$this->channels[$elementName] = $content ; $this->channels[$elementName] = $content ;
} }
/** /**
* Set multiple channel elements from an array. Array elements * Set multiple channel elements from an array. Array elements
* should be 'channelName' => 'channelContent' format. * should be 'channelName' => 'channelContent' format.
* *
* @access public * @access public
* @param array array of channels * @param array array of channels
* @return void * @return void
*/ */
public function setChannelElementsFromArray($elementArray) public function setChannelElementsFromArray($elementArray)
{ {
if(! is_array($elementArray)) return; if(! is_array($elementArray)) return;
foreach ($elementArray as $elementName => $content) foreach ($elementArray as $elementName => $content)
{ {
$this->setChannelElement($elementName, $content); $this->setChannelElement($elementName, $content);
} }
} }
/** /**
* Genarate the actual RSS/JSON file * Genarate the actual RSS/JSON file
* *
* @access public * @access public
* @return void * @return void
*/ */
public function genarateFeed() public function genarateFeed()
{ {
if ($this->version == RSS2) { if ($this->version == RSS2) {
// header('Content-type: text/xml; charset=UTF-8'); // header('Content-type: text/xml; charset=UTF-8');
// this line prevents Chrome 20 from prompting download // this line prevents Chrome 20 from prompting download
// used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss // used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss
// header('X-content-type-options: nosniff'); // header('X-content-type-options: nosniff');
} elseif ($this->version == JSON) { } elseif ($this->version == JSON) {
// header('Content-type: application/json; charset=UTF-8'); // header('Content-type: application/json; charset=UTF-8');
$this->json = new stdClass(); $this->json = new stdClass();
} elseif ($this->version == JSONP) { } elseif ($this->version == JSONP) {
// header('Content-type: application/javascript; charset=UTF-8'); // header('Content-type: application/javascript; charset=UTF-8');
$this->json = new stdClass(); $this->json = new stdClass();
} }
$this->printHead(); $this->printHead();
$this->printChannels(); $this->printChannels();
$this->printItems(); $this->printItems();
$this->printTale(); $this->printTale();
if ($this->version == JSON || $this->version == JSONP) { if ($this->version == JSON || $this->version == JSONP) {
echo json_encode($this->json); echo json_encode($this->json);
} }
} }
/** /**
* Create a new FeedItem. * Create a new FeedItem.
* *
* @access public * @access public
* @return object instance of FeedItem class * @return object instance of FeedItem class
*/ */
public function createNewItem() public function createNewItem()
{ {
$Item = new FeedItem($this->version); $Item = new FeedItem($this->version);
return $Item; return $Item;
} }
/** /**
* Add a FeedItem to the main class * Add a FeedItem to the main class
* *
* @access public * @access public
* @param object instance of FeedItem class * @param object instance of FeedItem class
* @return void * @return void
*/ */
public function addItem($feedItem) public function addItem($feedItem)
{ {
$this->items[] = $feedItem; $this->items[] = $feedItem;
} }
// Wrapper functions ------------------------------------------------------------------- // Wrapper functions -------------------------------------------------------------------
/** /**
* Set the 'title' channel element * Set the 'title' channel element
* *
* @access public * @access public
* @param srting value of 'title' channel tag * @param srting value of 'title' channel tag
* @return void * @return void
*/ */
public function setTitle($title) public function setTitle($title)
{ {
$this->setChannelElement('title', $title); $this->setChannelElement('title', $title);
} }
/** /**
* Add a hub to the channel element * Add a hub to the channel element
* *
* @access public * @access public
* @param string URL * @param string URL
* @return void * @return void
*/ */
public function addHub($hub) public function addHub($hub)
{ {
$this->hubs[] = $hub; $this->hubs[] = $hub;
} }
/** /**
* Set XSL URL * Set XSL URL
* *
* @access public * @access public
* @param string URL * @param string URL
* @return void * @return void
*/ */
public function setXsl($xsl) public function setXsl($xsl)
{ {
$this->xsl = $xsl; $this->xsl = $xsl;
} }
/** /**
* Set self URL * Set self URL
* *
* @access public * @access public
* @param string URL * @param string URL
* @return void * @return void
*/ */
public function setSelf($self) public function setSelf($self)
{ {
$this->self = $self; $this->self = $self;
} }
/** /**
* Set the 'description' channel element * Set the 'description' channel element
* *
* @access public * @access public
* @param srting value of 'description' channel tag * @param srting value of 'description' channel tag
* @return void * @return void
*/ */
public function setDescription($desciption) public function setDescription($description)
{ {
$tag = ($this->version == ATOM)? 'subtitle' : 'description'; $this->setChannelElement('description', $description);
$this->setChannelElement($tag, $desciption); }
}
/** /**
* Set the 'link' channel element * Set the 'link' channel element
* *
* @access public * @access public
* @param srting value of 'link' channel tag * @param srting value of 'link' channel tag
* @return void * @return void
*/ */
public function setLink($link) public function setLink($link)
{ {
$this->setChannelElement('link', $link); $this->setChannelElement('link', $link);
} }
/** /**
* Set the 'image' channel element * Set the 'image' channel element
* *
* @access public * @access public
* @param srting title of image * @param srting title of image
* @param srting link url of the imahe * @param srting link url of the imahe
* @param srting path url of the image * @param srting path url of the image
* @return void * @return void
*/ */
public function setImage($title, $link, $url) public function setImage($title, $link, $url)
{ {
$this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url)); $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url));
} }
// End # public functions ---------------------------------------------- // End # public functions ----------------------------------------------
// Start # private functions ---------------------------------------------- // Start # private functions ----------------------------------------------
/** /**
* Prints the xml and rss namespace * Prints the xml and rss namespace
* *
* @access private * @access private
* @return void * @return void
*/ */
private function printHead() private function printHead()
{ {
if ($this->version == RSS2) if ($this->version == RSS2)
{ {
$out = '<?xml version="1.0" encoding="utf-8"?>'."\n"; $out = '<?xml version="1.0" encoding="utf-8"?>'."\n";
if ($this->xsl) $out .= '<?xml-stylesheet type="text/xsl" href="'.htmlspecialchars($this->xsl).'"?>' . PHP_EOL; if ($this->xsl) $out .= '<?xml-stylesheet type="text/xsl" href="'.htmlspecialchars($this->xsl).'"?>' . PHP_EOL;
$out .= '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">' . PHP_EOL; $out .= '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">' . PHP_EOL;
echo $out; echo $out;
} }
elseif ($this->version == JSON || $this->version == JSONP) elseif ($this->version == JSON || $this->version == JSONP)
{ {
$this->json->rss = array('@attributes' => array('version' => '2.0')); $this->json->rss = array('@attributes' => array('version' => '2.0'));
} }
} }
/** /**
* Closes the open tags at the end of file * Closes the open tags at the end of file
* *
* @access private * @access private
* @return void * @return void
*/ */
private function printTale() private function printTale()
{ {
if ($this->version == RSS2) if ($this->version == RSS2)
{ {
echo '</channel>',PHP_EOL,'</rss>'; echo '</channel>',PHP_EOL,'</rss>';
} }
// do nothing for JSON // do nothing for JSON
} }
/** /**
* Creates a single node as xml format * Creates a single node as xml format
* *
* @access private * @access private
* @param string name of the tag * @param string name of the tag
* @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format
* @param array Attributes(if any) in 'attrName' => 'attrValue' format * @param array Attributes(if any) in 'attrName' => 'attrValue' format
* @return string formatted xml tag * @return string formatted xml tag
*/ */
private function makeNode($tagName, $tagContent, $attributes = null) private function makeNode($tagName, $tagContent, $attributes = null)
{ {
if ($this->version == RSS2) if ($this->version == RSS2)
{ {
$nodeText = ''; $nodeText = '';
$attrText = ''; $attrText = '';
if (is_array($attributes)) if (is_array($attributes))
{ {
foreach ($attributes as $key => $value) foreach ($attributes as $key => $value)
{ {
$attrText .= " $key=\"$value\" "; $attrText .= " $key=\"$value\" ";
} }
} }
$nodeText .= "<{$tagName}{$attrText}>"; $nodeText .= "<{$tagName}{$attrText}>";
if (is_array($tagContent)) if (is_array($tagContent))
{ {
foreach ($tagContent as $key => $value) foreach ($tagContent as $key => $value)
{ {
$nodeText .= $this->makeNode($key, $value); $nodeText .= $this->makeNode($key, $value);
} }
} }
else else
{ {
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent); //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);
$nodeText .= htmlspecialchars($tagContent); $nodeText .= htmlspecialchars($tagContent);
} }
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>"; //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";
$nodeText .= "</$tagName>"; $nodeText .= "</$tagName>";
return $nodeText . PHP_EOL; return $nodeText . PHP_EOL;
} }
elseif ($this->version == JSON || $this->version == JSONP) elseif ($this->version == JSON || $this->version == JSONP)
{ {
$tagName = (string)$tagName; $tagName = (string)$tagName;
$tagName = strtr($tagName, ':', '_'); $tagName = strtr($tagName, ':', '_');
$node = null; $node = null;
if (!$tagContent && is_array($attributes) && count($attributes)) if (!$tagContent && is_array($attributes) && count($attributes))
{ {
$node = array('@attributes' => $this->json_keys($attributes)); $node = array('@attributes' => $this->json_keys($attributes));
} else { } else {
if (is_array($tagContent)) { if (is_array($tagContent)) {
$node = $this->json_keys($tagContent); $node = $this->json_keys($tagContent);
} else { } else {
$node = $tagContent; $node = $tagContent;
} }
} }
return $node; return $node;
} }
return ''; // should not get here return ''; // should not get here
} }
private function json_keys(array $array) { private function json_keys(array $array) {
$new = array(); $new = array();
foreach ($array as $key => $val) { foreach ($array as $key => $val) {
if (is_string($key)) $key = strtr($key, ':', '_'); if (is_string($key)) $key = strtr($key, ':', '_');
if (is_array($val)) { if (is_array($val)) {
$new[$key] = $this->json_keys($val); $new[$key] = $this->json_keys($val);
} else { } else {
$new[$key] = $val; $new[$key] = $val;
} }
} }
return $new; return $new;
} }
/** /**
* @desc Print channels * @desc Print channels
* @access private * @access private
* @return void * @return void
*/ */
private function printChannels() private function printChannels()
{ {
//Start channel tag //Start channel tag
if ($this->version == RSS2) { if ($this->version == RSS2) {
echo '<channel>' . PHP_EOL; echo '<channel>' . PHP_EOL;
// add hubs // add hubs
foreach ($this->hubs as $hub) { foreach ($this->hubs as $hub) {
//echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom')); //echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom'));
echo '<link rel="hub" href="'.htmlspecialchars($hub).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL; echo '<link rel="hub" href="'.htmlspecialchars($hub).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
} }
// add self // add self
if (isset($this->self)) { if (isset($this->self)) {
//echo $this->makeNode('link', '', array('rel'=>'self', 'href'=>$this->self, 'xmlns'=>'http://www.w3.org/2005/Atom')); //echo $this->makeNode('link', '', array('rel'=>'self', 'href'=>$this->self, 'xmlns'=>'http://www.w3.org/2005/Atom'));
echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL; echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
} }
//Print Items of channel //Print Items of channel
foreach ($this->channels as $key => $value) foreach ($this->channels as $key => $value)
{ {
echo $this->makeNode($key, $value); echo $this->makeNode($key, $value);
} }
} elseif ($this->version == JSON || $this->version == JSONP) { } elseif ($this->version == JSON || $this->version == JSONP) {
$this->json->rss['channel'] = (object)$this->json_keys($this->channels); $this->json->rss['channel'] = (object)$this->json_keys($this->channels);
} }
} }
/** /**
* Prints formatted feed items * Prints formatted feed items
* *
* @access private * @access private
* @return void * @return void
*/ */
private function printItems() private function printItems()
{ {
foreach ($this->items as $item) { foreach ($this->items as $item) {
$itemElements = $item->getElements(); $itemElements = $item->getElements();
echo $this->startItem(); echo $this->startItem();
if ($this->version == JSON || $this->version == JSONP) { if ($this->version == JSON || $this->version == JSONP) {
$json_item = array(); $json_item = array();
} }
foreach ($itemElements as $thisElement) { foreach ($itemElements as $thisElement) {
foreach ($thisElement as $instance) { foreach ($thisElement as $instance) {
if ($this->version == RSS2) { if ($this->version == RSS2) {
echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']); echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']);
} elseif ($this->version == JSON || $this->version == JSONP) { } elseif ($this->version == JSON || $this->version == JSONP) {
$_json_node = $this->makeNode($instance['name'], $instance['content'], $instance['attributes']); $_json_node = $this->makeNode($instance['name'], $instance['content'], $instance['attributes']);
if (count($thisElement) > 1) { if (count($thisElement) > 1) {
$json_item[strtr($instance['name'], ':', '_')][] = $_json_node; $json_item[strtr($instance['name'], ':', '_')][] = $_json_node;
} else { } else {
$json_item[strtr($instance['name'], ':', '_')] = $_json_node; $json_item[strtr($instance['name'], ':', '_')] = $_json_node;
} }
} }
} }
} }
echo $this->endItem(); echo $this->endItem();
if ($this->version == JSON || $this->version == JSONP) { if ($this->version == JSON || $this->version == JSONP) {
if (count($this->items) > 1) { if (count($this->items) > 1) {
$this->json->rss['channel']->item[] = $json_item; $this->json->rss['channel']->item[] = $json_item;
} else { } else {
$this->json->rss['channel']->item = $json_item; $this->json->rss['channel']->item = $json_item;
} }
} }
} }
} }
/** /**
* Make the starting tag of channels * Make the starting tag of channels
* *
* @access private * @access private
* @return void * @return void
*/ */
private function startItem() private function startItem()
{ {
if ($this->version == RSS2) if ($this->version == RSS2)
{ {
echo '<item>' . PHP_EOL; echo '<item>' . PHP_EOL;
} }
// nothing for JSON // nothing for JSON
} }
/** /**
* Closes feed item tag * Closes feed item tag
* *
* @access private * @access private
* @return void * @return void
*/ */
private function endItem() private function endItem()
{ {
if ($this->version == RSS2) if ($this->version == RSS2)
{ {
echo '</item>' . PHP_EOL; echo '</item>' . PHP_EOL;
} }
// nothing for JSON // nothing for JSON
} }
// End # private functions ---------------------------------------------- // End # private functions ----------------------------------------------
} }

View file

@ -77,7 +77,7 @@ class Database {
} }
else { else {
$sql = ' $sql = '
CREATE TABLE tags ( CREATE TABLE IF NOT EXISTS tags (
id bigserial primary key, id bigserial primary key,
value varchar(255) NOT NULL value varchar(255) NOT NULL
); );
@ -110,7 +110,7 @@ class Database {
} }
else { else {
$sql = ' $sql = '
CREATE TABLE tags_entries ( CREATE TABLE IF NOT EXISTS tags_entries (
id bigserial primary key, id bigserial primary key,
entry_id integer NOT NULL, entry_id integer NOT NULL,
tag_id integer NOT NULL tag_id integer NOT NULL
@ -245,7 +245,7 @@ class Database {
$sql_limit = "LIMIT ".$limit." OFFSET 0"; $sql_limit = "LIMIT ".$limit." OFFSET 0";
} }
$sql = "SELECT * FROM entries WHERE (content = '' OR content IS NULL) AND user_id=? ORDER BY id " . $sql_limit; $sql = "SELECT * FROM entries WHERE (content = '' OR content IS NULL) AND title LIKE 'Untitled - Import%' AND user_id=? ORDER BY id " . $sql_limit;
$query = $this->executeQuery($sql, array($user_id)); $query = $this->executeQuery($sql, array($user_id));
$entries = $query->fetchAll(); $entries = $query->fetchAll();
@ -253,7 +253,7 @@ class Database {
} }
public function retrieveUnfetchedEntriesCount($user_id) { public function retrieveUnfetchedEntriesCount($user_id) {
$sql = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND user_id=?"; $sql = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND title LIKE 'Untitled - Import%' AND user_id=?";
$query = $this->executeQuery($sql, array($user_id)); $query = $this->executeQuery($sql, array($user_id));
list($count) = $query->fetch(); list($count) = $query->fetch();
@ -374,7 +374,7 @@ class Database {
$id = null; $id = null;
} }
else { else {
$id = intval($this->getLastId( (STORAGE == 'postgres') ? 'users_id_seq' : '' )); $id = intval($this->getLastId( (STORAGE == 'postgres') ? 'entries_id_seq' : '') );
} }
return $id; return $id;
} }

View file

@ -373,9 +373,7 @@ class Poche
$body = $content['rss']['channel']['item']['description']; $body = $content['rss']['channel']['item']['description'];
// clean content from prevent xss attack // clean content from prevent xss attack
$config = HTMLPurifier_Config::createDefault(); $purifier = $this->getPurifier();
$config->set('Cache.SerializerPath', CACHE);
$purifier = new HTMLPurifier($config);
$title = $purifier->purify($title); $title = $purifier->purify($title);
$body = $purifier->purify($body); $body = $purifier->purify($body);
@ -828,10 +826,12 @@ class Poche
define('IMPORT_LIMIT', 5); define('IMPORT_LIMIT', 5);
} }
if (!defined('IMPORT_DELAY')) { if (!defined('IMPORT_DELAY')) {
define('IMPORT_DELAY', 5); define('IMPORT_DELAY', 5);
} }
if ( isset($_FILES['file']) ) { if ( isset($_FILES['file']) ) {
Tools::logm('Import stated: parsing file');
// assume, that file is in json format // assume, that file is in json format
$str_data = file_get_contents($_FILES['file']['tmp_name']); $str_data = file_get_contents($_FILES['file']['tmp_name']);
$data = json_decode($str_data, true); $data = json_decode($str_data, true);
@ -844,18 +844,18 @@ class Poche
$read = 0; $read = 0;
foreach (array('ol','ul') as $list) { foreach (array('ol','ul') as $list) {
foreach ($html->find($list) as $ul) { foreach ($html->find($list) as $ul) {
foreach ($ul->find('li') as $li) { foreach ($ul->find('li') as $li) {
$tmpEntry = array(); $tmpEntry = array();
$a = $li->find('a'); $a = $li->find('a');
$tmpEntry['url'] = $a[0]->href; $tmpEntry['url'] = $a[0]->href;
$tmpEntry['tags'] = $a[0]->tags; $tmpEntry['tags'] = $a[0]->tags;
$tmpEntry['is_read'] = $read; $tmpEntry['is_read'] = $read;
if ($tmpEntry['url']) { if ($tmpEntry['url']) {
$data[] = $tmpEntry; $data[] = $tmpEntry;
} }
} }
# the second <ol/ul> is for read links # the second <ol/ul> is for read links
$read = ((sizeof($data) && $read)?0:1); $read = ((sizeof($data) && $read)?0:1);
} }
} }
} }
@ -866,16 +866,16 @@ class Poche
$data[] = $record; $data[] = $record;
foreach ($record as $record2) { foreach ($record as $record2) {
if (is_array($record2)) { if (is_array($record2)) {
$data[] = $record2; $data[] = $record2;
} }
} }
} }
} }
$i = 0; //counter for articles inserted $urlsInserted = array(); //urls of articles inserted
foreach ($data as $record) { foreach ($data as $record) {
$url = trim( isset($record['article__url']) ? $record['article__url'] : (isset($record['url']) ? $record['url'] : '') ); $url = trim( isset($record['article__url']) ? $record['article__url'] : (isset($record['url']) ? $record['url'] : '') );
if ( $url ) { if ( $url and !in_array($url, $urlsInserted) ) {
$title = (isset($record['title']) ? $record['title'] : _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>'); $title = (isset($record['title']) ? $record['title'] : _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>');
$body = (isset($record['content']) ? $record['content'] : ''); $body = (isset($record['content']) ? $record['content'] : '');
$isRead = (isset($record['is_read']) ? intval($record['is_read']) : (isset($record['archive'])?intval($record['archive']):0)); $isRead = (isset($record['is_read']) ? intval($record['is_read']) : (isset($record['archive'])?intval($record['archive']):0));
@ -883,19 +883,21 @@ class Poche
//insert new record //insert new record
$id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead); $id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead);
if ( $id ) { if ( $id ) {
//increment no of records inserted $urlsInserted[] = $url; //add
$i++;
if ( isset($record['tags']) && trim($record['tags']) ) { if ( isset($record['tags']) && trim($record['tags']) ) {
//@TODO: set tags //@TODO: set tags
} }
} }
} }
} }
$i = sizeof($urlsInserted);
if ( $i > 0 ) { if ( $i > 0 ) {
$this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".')); $this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".'));
} }
Tools::logm('Import of articles finished: '.$i.' articles added (w/o content if not provided).');
} }
//file parsing finished here //file parsing finished here
@ -906,30 +908,32 @@ class Poche
if ( $recordsDownloadRequired == 0 ) { if ( $recordsDownloadRequired == 0 ) {
//nothing to download //nothing to download
$this->messages->add('s', _('Import finished.')); $this->messages->add('s', _('Import finished.'));
Tools::logm('Import finished completely');
Tools::redirect(); Tools::redirect();
} }
else { else {
//if just inserted - don't download anything, download will start in next reload //if just inserted - don't download anything, download will start in next reload
if ( !isset($_FILES['file']) ) { if ( !isset($_FILES['file']) ) {
//download next batch //download next batch
Tools::logm('Fetching next batch of articles...');
$items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT); $items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT);
$config = HTMLPurifier_Config::createDefault(); $purifier = $this->getPurifier();
$config->set('Cache.SerializerPath', CACHE);
$purifier = new HTMLPurifier($config);
foreach ($items as $item) { foreach ($items as $item) {
$url = new Url(base64_encode($item['url'])); $url = new Url(base64_encode($item['url']));
$content = Tools::getPageContent($url); Tools::logm('Fetching article '.$item['id']);
$content = Tools::getPageContent($url);
$title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled')); $title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'));
$body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined')); $body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined'));
//clean content to prevent xss attack //clean content to prevent xss attack
$title = $purifier->purify($title); $title = $purifier->purify($title);
$body = $purifier->purify($body); $body = $purifier->purify($body);
$this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId()); $this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId());
Tools::logm('Article '.$item['id'].' updated.');
} }
} }
@ -942,16 +946,15 @@ class Poche
* export poche entries in json * export poche entries in json
* @return json all poche entries * @return json all poche entries
*/ */
public function export() public function export() {
{ $filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json";
$filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json"; header('Content-Disposition: attachment; filename='.$filename);
header('Content-Disposition: attachment; filename='.$filename);
$entries = $this->store->retrieveAll($this->user->getId()); $entries = $this->store->retrieveAll($this->user->getId());
echo $this->tpl->render('export.twig', array( echo $this->tpl->render('export.twig', array(
'export' => Tools::renderJson($entries), 'export' => Tools::renderJson($entries),
)); ));
Tools::logm('export view'); Tools::logm('export view');
} }
/** /**
@ -959,43 +962,42 @@ class Poche
* @param string $which 'prod' or 'dev' * @param string $which 'prod' or 'dev'
* @return string latest $which version * @return string latest $which version
*/ */
private function getPocheVersion($which = 'prod') private function getPocheVersion($which = 'prod') {
{ $cache_file = CACHE . '/' . $which;
$cache_file = CACHE . '/' . $which; $check_time = time();
$check_time = time();
# checks if the cached version file exists # checks if the cached version file exists
if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) {
$version = file_get_contents($cache_file); $version = file_get_contents($cache_file);
$check_time = filemtime($cache_file); $check_time = filemtime($cache_file);
} else { } else {
$version = file_get_contents('http://static.wallabag.org/versions/' . $which); $version = file_get_contents('http://static.wallabag.org/versions/' . $which);
file_put_contents($cache_file, $version, LOCK_EX); file_put_contents($cache_file, $version, LOCK_EX);
} }
return array($version, $check_time); return array($version, $check_time);
} }
public function generateToken() public function generateToken()
{ {
if (ini_get('open_basedir') === '') { if (ini_get('open_basedir') === '') {
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
echo 'This is a server using Windows!'; echo 'This is a server using Windows!';
// alternative to /dev/urandom for Windows // alternative to /dev/urandom for Windows
$token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20); $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
} else { } else {
$token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15); $token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15);
}
}
else {
$token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
} }
}
else {
$token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
}
$token = str_replace('+', '', $token); $token = str_replace('+', '', $token);
$this->store->updateUserConfig($this->user->getId(), 'token', $token); $this->store->updateUserConfig($this->user->getId(), 'token', $token);
$currentConfig = $_SESSION['poche_user']->config; $currentConfig = $_SESSION['poche_user']->config;
$currentConfig['token'] = $token; $currentConfig['token'] = $token;
$_SESSION['poche_user']->setConfig($currentConfig); $_SESSION['poche_user']->setConfig($currentConfig);
Tools::redirect(); Tools::redirect();
} }
public function generateFeeds($token, $user_id, $tag_id, $type = 'home') public function generateFeeds($token, $user_id, $tag_id, $type = 'home')
@ -1031,6 +1033,7 @@ class Poche
foreach ($entries as $entry) { foreach ($entries as $entry) {
$newItem = $feed->createNewItem(); $newItem = $feed->createNewItem();
$newItem->setTitle($entry['title']); $newItem->setTitle($entry['title']);
$newItem->setSource(Tools::getPocheUrl() . '?view=view&amp;id=' . $entry['id']);
$newItem->setLink($entry['url']); $newItem->setLink($entry['url']);
$newItem->setDate(time()); $newItem->setDate(time());
$newItem->setDescription($entry['content']); $newItem->setDescription($entry['content']);
@ -1057,4 +1060,16 @@ class Poche
$this->messages->add('s', _('Cache deleted.')); $this->messages->add('s', _('Cache deleted.'));
Tools::redirect(); Tools::redirect();
} }
/**
* return new purifier object with actual config
*/
protected function getPurifier() {
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.SerializerPath', CACHE);
$config->set('HTML.SafeIframe', true);
$config->set('URI.SafeIframeRegexp', '%^(https?:)?//(www\.youtube(?:-nocookie)?\.com/embed/|player\.vimeo\.com/video/)%'); //allow YouTube and Vimeo$purifier = new HTMLPurifier($config);
return new HTMLPurifier($config);
}
} }

View file

@ -59,8 +59,10 @@ class Tools
return $scriptname; return $scriptname;
} }
$host = (isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']));
return 'http' . ($https ? 's' : '') . '://' return 'http' . ($https ? 's' : '') . '://'
. $_SERVER["HTTP_HOST"] . $serverport . $scriptname; . $host . $serverport . $scriptname;
} }
public static function redirect($url = '') public static function redirect($url = '')

View file

@ -8,7 +8,7 @@
* @license http://www.wtfpl.net/ see COPYING file * @license http://www.wtfpl.net/ see COPYING file
*/ */
define ('POCHE', '1.6.0'); define ('POCHE', '1.6.1');
require 'check_setup.php'; require 'check_setup.php';
require_once 'inc/poche/global.inc.php'; require_once 'inc/poche/global.inc.php';

BIN
locale/fr_FR.utf8/LC_MESSAGES/fr_FR.utf8.mo Normal file → Executable file

Binary file not shown.

116
locale/fr_FR.utf8/LC_MESSAGES/fr_FR.utf8.po Normal file → Executable file
View file

@ -1,26 +1,25 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: wallabag 1.6.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-25 18:33+0300\n" "POT-Creation-Date: 2014-02-25 18:33+0300\n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
"Last-Translator: Maryana <mariroz@mr.lviv.ua>\n" "Last-Translator: Gilles WITTEZAELE <gilles.wittezaele@laposte.net>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n" "X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-SourceCharset: utf-8\n" "X-Generator: Poedit 1.6.4\n"
"X-Generator: Poedit 1.5.7\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-SearchPath-0: /home/mariroz/_DEV/web/wallabag/wallabag-master-testing\n" "Language: fr_FR\n"
msgid "wallabag, a read it later open source system" msgid "wallabag, a read it later open source system"
msgstr "wallabag, un système open source de lecture différé" msgstr "wallabag, un système open source de lecture différé"
msgid "login failed: user doesn't exist" msgid "login failed: user doesn't exist"
msgstr "identification échouée : l'utilisateur n'existe pas" msgstr "échec de l'identification : cet utilisateur n'existe pas"
msgid "return home" msgid "return home"
msgstr "retour à l'accueil" msgstr "retour à l'accueil"
@ -32,13 +31,13 @@ msgid "Saving articles"
msgstr "Sauvegarde des articles" msgstr "Sauvegarde des articles"
msgid "There are several ways to save an article:" msgid "There are several ways to save an article:"
msgstr "Il y a plusieurs façons de sauver un article :" msgstr "Il y a plusieurs façons d'enregistrer un article :"
msgid "read the documentation" msgid "read the documentation"
msgstr "lisez la documentation" msgstr "lisez la documentation"
msgid "download the extension" msgid "download the extension"
msgstr "télécharger l'extension" msgstr "téléchargez l'extension"
msgid "via F-Droid" msgid "via F-Droid"
msgstr "via F-Droid" msgstr "via F-Droid"
@ -50,7 +49,7 @@ msgid "via Google Play"
msgstr "via Google PlayStore" msgstr "via Google PlayStore"
msgid "download the application" msgid "download the application"
msgstr "télécharger l'application" msgstr "téléchargez l'application"
msgid "By filling this field" msgid "By filling this field"
msgstr "En remplissant ce champ" msgstr "En remplissant ce champ"
@ -85,8 +84,13 @@ msgstr "Une version de développement plus récente est disponible."
msgid "Feeds" msgid "Feeds"
msgstr "Flux" msgstr "Flux"
msgid "Your feed token is currently empty and must first be generated to enable feeds. Click <a href='?feed&amp;action=generate'>here to generate it</a>." msgid ""
msgstr "Votre jeton de flux est actuellement vide doit d'abord être généré pour activer les flux. Cliquez <a href='?feed&amp;action=generate'>ici</a> pour le générer." "Your feed token is currently empty and must first be generated to enable "
"feeds. Click <a href='?feed&amp;action=generate'>here to generate it</a>."
msgstr ""
"Votre jeton de flux est actuellement vide et doit d'abord être généré pour "
"activer les flux. Cliquez <a href='?feed&amp;action=generate'>ici</a> pour "
"le générer."
msgid "Unread feed" msgid "Unread feed"
msgstr "Flux des non lus" msgstr "Flux des non lus"
@ -103,8 +107,12 @@ msgstr "Votre jeton :"
msgid "Your user id:" msgid "Your user id:"
msgstr "Votre ID utilisateur :" msgstr "Votre ID utilisateur :"
msgid "You can regenerate your token: <a href='?feed&amp;action=generate'>generate!</a>." msgid ""
msgstr "Vous pouvez regénérer votre jeton : <a href='?feed&amp;action=generate'>génération !</a>." "You can regenerate your token: <a href='?feed&amp;action=generate'>generate!"
"</a>."
msgstr ""
"Vous pouvez regénérer votre jeton : <a href='?feed&amp;"
"action=generate'>génération !</a>."
msgid "Change your theme" msgid "Change your theme"
msgstr "Changer votre thème" msgstr "Changer votre thème"
@ -136,8 +144,11 @@ msgstr "Répétez votre nouveau mot de passe :"
msgid "Import" msgid "Import"
msgstr "Importer" msgstr "Importer"
msgid "Please execute the import script locally as it can take a very long time." msgid ""
msgstr "Merci d'exécuter l'import en local car cela peut prendre du temps." "Please execute the import script locally as it can take a very long time."
msgstr ""
"Merci d'exécuter le script d'importation en local car cela peut prendre du "
"temps."
msgid "More info in the official documentation:" msgid "More info in the official documentation:"
msgstr "Plus d'infos dans la documentation officielle :" msgstr "Plus d'infos dans la documentation officielle :"
@ -150,13 +161,13 @@ msgid "(you must have a %s file on your server)"
msgstr "(le fichier %s doit être présent sur le serveur)" msgstr "(le fichier %s doit être présent sur le serveur)"
msgid "Import from Readability" msgid "Import from Readability"
msgstr "Import depuis Readability" msgstr "Importer depuis Readability"
msgid "Import from Instapaper" msgid "Import from Instapaper"
msgstr "Import depuis Instapaper" msgstr "Importer depuis Instapaper"
msgid "Import from wallabag" msgid "Import from wallabag"
msgstr "Import depuis wallabag" msgstr "Importer depuis wallabag"
msgid "Export your wallabag data" msgid "Export your wallabag data"
msgstr "Exporter vos données de wallabag" msgstr "Exporter vos données de wallabag"
@ -185,8 +196,12 @@ msgstr "retourner à l'article"
msgid "plop" msgid "plop"
msgstr "plop" msgstr "plop"
msgid "You can <a href='wallabag_compatibility_test.php'>check your configuration here</a>." msgid ""
msgstr "Vous pouvez vérifier votre configuration <a href='wallabag_compatibility_test.php'>ici</a>." "You can <a href='wallabag_compatibility_test.php'>check your configuration "
"here</a>."
msgstr ""
"Vous pouvez vérifier votre configuration <a "
"href='wallabag_compatibility_test.php'>ici</a>."
msgid "favoris" msgid "favoris"
msgstr "favoris" msgstr "favoris"
@ -248,8 +263,14 @@ msgstr "installation"
msgid "install your wallabag" msgid "install your wallabag"
msgstr "installez votre wallabag" msgstr "installez votre wallabag"
msgid "wallabag is still not installed. Please fill the below form to install it. Don't hesitate to <a href='http://doc.wallabag.org/'>read the documentation on wallabag website</a>." msgid ""
msgstr "wallabag n'est pas encore installé. Merci de remplir le formulaire suivant pour l'installer. N'hésitez pas à <a href='http://doc.wallabag.org'>lire la documentation sur le site de wallabag</a>." "wallabag is still not installed. Please fill the below form to install it. "
"Don't hesitate to <a href='http://doc.wallabag.org/'>read the documentation "
"on wallabag website</a>."
msgstr ""
"wallabag n'est pas encore installé. Merci de remplir le formulaire suivant "
"pour l'installer. N'hésitez pas à <a href='http://doc.wallabag.org'>lire la "
"documentation sur le site de wallabag</a>."
msgid "Login" msgid "Login"
msgstr "Nom d'utilisateur" msgstr "Nom d'utilisateur"
@ -267,7 +288,8 @@ msgid "Login to wallabag"
msgstr "Se connecter à wallabag" msgstr "Se connecter à wallabag"
msgid "you are in demo mode, some features may be disabled." msgid "you are in demo mode, some features may be disabled."
msgstr "vous êtes en mode démo, certaines fonctionnalités peuvent être désactivées." msgstr ""
"vous êtes en mode démo, certaines fonctionnalités peuvent être désactivées."
msgid "Username" msgid "Username"
msgstr "Nom d'utilisateur" msgstr "Nom d'utilisateur"
@ -318,10 +340,10 @@ msgid "tags:"
msgstr "tags :" msgstr "tags :"
msgid "Edit tags" msgid "Edit tags"
msgstr "Editer les tags" msgstr "Modifier les tags"
msgid "save link!" msgid "save link!"
msgstr "sauver le lien !" msgstr "enregistrer le lien !"
msgid "powered by" msgid "powered by"
msgstr "propulsé par" msgstr "propulsé par"
@ -360,7 +382,7 @@ msgid "tweet"
msgstr "tweet" msgstr "tweet"
msgid "email" msgid "email"
msgstr "ee-mail" msgstr "e-mail"
msgid "this article appears wrong?" msgid "this article appears wrong?"
msgstr "cet article s'affiche mal ?" msgstr "cet article s'affiche mal ?"
@ -369,7 +391,7 @@ msgid "No link available here!"
msgstr "Aucun lien n'est disponible ici !" msgstr "Aucun lien n'est disponible ici !"
msgid "Poching a link" msgid "Poching a link"
msgstr "Sauver un lien" msgstr "Enregistrer un lien"
msgid "by filling this field" msgid "by filling this field"
msgstr "en remplissant ce champ" msgstr "en remplissant ce champ"
@ -396,19 +418,21 @@ msgid "a more recent development version is available."
msgstr "une version de développement plus récente est disponible." msgstr "une version de développement plus récente est disponible."
msgid "Please execute the import script locally, it can take a very long time." msgid "Please execute the import script locally, it can take a very long time."
msgstr "Merci d'exécuter l'import en local car cela peut prendre du temps." msgstr ""
"Merci d'exécuter le script d'importation en local car cela peut prendre du "
"temps."
msgid "More infos in the official doc:" msgid "More infos in the official doc:"
msgstr "Plus d'infos dans la documentation officielle :" msgstr "Plus d'infos dans la documentation officielle :"
msgid "import from Pocket" msgid "import from Pocket"
msgstr "import depuis Pocket" msgstr "importation depuis Pocket"
msgid "import from Readability" msgid "import from Readability"
msgstr "import depuis Readability" msgstr "importation depuis Readability"
msgid "import from Instapaper" msgid "import from Instapaper"
msgstr "import depuis Instapaper" msgstr "importation depuis Instapaper"
msgid "estimated reading time :" msgid "estimated reading time :"
msgstr "temps de lecture estimé :" msgstr "temps de lecture estimé :"
@ -449,8 +473,12 @@ msgstr "en mode démo, vous ne pouvez pas mettre à jour le mot de passe"
msgid "your password has been updated" msgid "your password has been updated"
msgstr "votre mot de passe a été mis à jour" msgstr "votre mot de passe a été mis à jour"
msgid "the two fields have to be filled & the password must be the same in the two fields" msgid ""
msgstr "les deux champs doivent être remplis & le mot de passe doit être le même dans les deux" "the two fields have to be filled & the password must be the same in the two "
"fields"
msgstr ""
"les deux champs doivent être remplis & le mot de passe doit être le même "
"dans les deux"
msgid "still using the \"" msgid "still using the \""
msgstr "utilise encore \"" msgstr "utilise encore \""
@ -459,7 +487,7 @@ msgid "that theme does not seem to be installed"
msgstr "ce thème ne semble pas installé" msgstr "ce thème ne semble pas installé"
msgid "you have changed your theme preferences" msgid "you have changed your theme preferences"
msgstr "vous avez changez vos préférences de thème" msgstr "vous avez changé vos préférences de thème"
msgid "that language does not seem to be installed" msgid "that language does not seem to be installed"
msgstr "cette langue ne semble pas être installée" msgstr "cette langue ne semble pas être installée"
@ -468,28 +496,28 @@ msgid "you have changed your language preferences"
msgstr "vous avez changé vos préférences de langue" msgstr "vous avez changé vos préférences de langue"
msgid "login failed: you have to fill all fields" msgid "login failed: you have to fill all fields"
msgstr "identification échouée : vous devez remplir tous les champs" msgstr "échec de l'identification : vous devez remplir tous les champs"
msgid "welcome to your wallabag" msgid "welcome to your wallabag"
msgstr "bienvenue dans votre wallabag" msgstr "bienvenue dans votre wallabag"
msgid "login failed: bad login or password" msgid "login failed: bad login or password"
msgstr "identification échouée : mauvais identifiant ou mot de passe" msgstr "échec de l'identification : mauvais identifiant ou mot de passe"
msgid "import from instapaper completed" msgid "import from instapaper completed"
msgstr "Import depuis Instapaper complété" msgstr "Importation depuis Instapaper complété"
msgid "import from pocket completed" msgid "import from pocket completed"
msgstr "Import depuis Pocket complété" msgstr "Importation depuis Pocket complété"
msgid "import from Readability completed. " msgid "import from Readability completed. "
msgstr "Import depuis Readability complété" msgstr "Importation depuis Readability complété"
msgid "import from Poche completed. " msgid "import from Poche completed. "
msgstr "Import depuis Pocket complété" msgstr "Importation depuis Pocket complété"
msgid "Unknown import provider." msgid "Unknown import provider."
msgstr "Fournisseur d'import inconnu." msgstr "Format d'importation inconnu."
msgid "Incomplete inc/poche/define.inc.php file, please define \"" msgid "Incomplete inc/poche/define.inc.php file, please define \""
msgstr "Fichier inc/poche/define.inc.php incomplet, merci de définir \"" msgstr "Fichier inc/poche/define.inc.php incomplet, merci de définir \""
@ -498,7 +526,7 @@ msgid "Could not find required \""
msgstr "Ne peut pas trouver \"" msgstr "Ne peut pas trouver \""
msgid "Uh, there is a problem while generating feeds." msgid "Uh, there is a problem while generating feeds."
msgstr "Ih, il y a un problème lors de la génération des flux." msgstr "Hum, il y a un problème lors de la génération des flux."
msgid "Cache deleted." msgid "Cache deleted."
msgstr "Cache effacé." msgstr "Cache effacé."

View file

@ -12,4 +12,5 @@
<script src="{{ poche_url }}themes/{{theme}}/js/jquery.cookie.js"></script> <script src="{{ poche_url }}themes/{{theme}}/js/jquery.cookie.js"></script>
<script src="{{ poche_url }}themes/{{theme}}/js/init.js"></script> <script src="{{ poche_url }}themes/{{theme}}/js/init.js"></script>
<script src="{{ poche_url }}themes/default/js/saveLink.js"></script> <script src="{{ poche_url }}themes/default/js/saveLink.js"></script>
<script src="{{ poche_url }}themes/default/js/popupForm.js"></script>
<script src="{{ poche_url }}themes/{{theme}}/js/closeMessage.js"></script> <script src="{{ poche_url }}themes/{{theme}}/js/closeMessage.js"></script>

View file

@ -1,21 +1,7 @@
<div id="search-form" class="messages info"> <div id="search-form" class="messages info">
<form method="get" action="index.php"> <form method="get" action="index.php">
<input type="hidden" name="view" value="search"></input> <input type="hidden" name="view" value="search"></input>
<label><a href="javascript: void(null);" id="search-form-close">X</a>{% trans "Search" %}</label> : <input type="text" name="search" /> <label><a href="javascript: void(null);" id="search-form-close">X</a>{% trans "Search" %}</label> : <input type="text" name="search" />
<input id="submit-search" type="submit" value="{% trans "Search" %} !"></input> <input id="submit-search" type="submit" value="{% trans "Search" %} !"></input>
</form> </form>
</div> </div>
<script type="text/javascript">
$(document).ready(function() {
$("#search-form").hide();
$("#search").click(function(){
$("#search-form").toggle();
$("#search").toggleClass("current");
$("#search-arrow").toggleClass("arrow-down");
});
});
</script>

View file

@ -352,10 +352,10 @@ footer a {
letter-spacing:normal; letter-spacing:normal;
box-shadow: 0 3px 7px rgba(0,0,0,0.3); box-shadow: 0 3px 7px rgba(0,0,0,0.3);
display: inline-block; display: inline-block;
width: 32%!important; width: 32%;
margin-bottom: 1.5em; margin-bottom: 1.5em;
vertical-align: top; vertical-align: top;
margin-left: 1.5%!important; margin-left: 1.5%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
padding: 1.5em 1.5em 3em 1.5em; padding: 1.5em 1.5em 3em 1.5em;
@ -492,7 +492,7 @@ footer a {
} }
.entrie:nth-child(3n+1) { .entrie:nth-child(3n+1) {
margin-left: 0!important; margin-left: 0;
} }
.results { .results {
@ -540,7 +540,7 @@ footer a {
2.1 = "save a link" popup div related styles 2.1 = "save a link" popup div related styles
========================================================================== */ ========================================================================== */
#bagit-form { #bagit-form, #search-form {
background: rgba(0,0,0,0.5); background: rgba(0,0,0,0.5);
position: absolute; position: absolute;
top: 0; top: 0;
@ -555,7 +555,7 @@ footer a {
border-left: 1px #EEE solid; border-left: 1px #EEE solid;
} }
#bagit-form form { #bagit-form form, #search-form form {
background: #FFF; background: #FFF;
position: absolute; position: absolute;
top: 0; top: 0;
@ -568,7 +568,7 @@ footer a {
padding: 2em; padding: 2em;
} }
a#bagit-form-close { a#bagit-form-close, a#search-form-close {
background: #000; background: #000;
color: #FFF; color: #FFF;
padding: 0.2em 0.5em; padding: 0.2em 0.5em;
@ -577,7 +577,7 @@ a#bagit-form-close {
float: right; float: right;
font-size: 0.6em; font-size: 0.6em;
} }
a#bagit-form-close:hover { a#bagit-form-close:hover, a#search-form-close:hover {
background: #999; background: #999;
color: #000; color: #000;
} }
@ -1028,7 +1028,7 @@ blockquote {
display: none; display: none;
} }
#bagit-form { #bagit-form, #search-form {
left: 0; left: 0;
} }
} }

View file

@ -9,9 +9,11 @@
<h2>{% trans "Poching a link" %}</h2> <h2>{% trans "Poching a link" %}</h2>
<p>{% trans "There are several ways to save an article:" %} (<a class="special" href="http://doc.wallabag.org" title="{% trans "read the documentation" %}">?</a>)</p> <p>{% trans "There are several ways to save an article:" %} (<a class="special" href="http://doc.wallabag.org" title="{% trans "read the documentation" %}">?</a>)</p>
<ul> <ul>
<li>firefox: <a href="https://bitbucket.org/jogaulupeau/poche/downloads/poche.xpi" title="download the firefox extension">{% trans "download the extension" %}</a></li> <li>Firefox: <a href="https://addons.mozilla.org/firefox/addon/wallabag/" title="download the firefox extension">{% trans "download the extension" %}</a></li>
<li>chrome: <a href="https://bitbucket.org/jogaulupeau/poche/downloads/poche.crx" title="download the chrome extension">{% trans "download the extension" %}</a></li> <li>Chrome: <a href="http://doc.wallabag.org/doku.php?id=users:chrome_extension" title="download the chrome extension">{% trans "download the extension" %}</a></li>
<li>android: <a href="https://bitbucket.org/jogaulupeau/poche/downloads/Poche.apk" title="download the application">{% trans "download the application" %}</a></li> <li>Android: <a href="https://f-droid.org/app/fr.gaulupeau.apps.InThePoche" title="download the application">{% trans "via F-Droid" %}</a> {% trans " or " %} <a href="https://play.google.com/store/apps/details?id=fr.gaulupeau.apps.InThePoche" title="download the application">{% trans "via Google Play" %}</a></li>
<li>iOS: <a href="https://itunes.apple.com/app/wallabag/id828331015?mt=8" title="download the iOS application">{% trans "download the application" %}</a></li>
<li>Windows Phone: <a href="http://www.windowsphone.com/en-us/store/app/wallabag/ff890514-348c-4d0b-9b43-153fff3f7450" title="download the window phone application">{% trans "download the application" %}</a></li>
<li> <li>
<form method="get" action="index.php"> <form method="get" action="index.php">
<label class="addurl" for="plainurl">{% trans "by filling this field" %}:</label> <label class="addurl" for="plainurl">{% trans "by filling this field" %}:</label>

View file

@ -11,3 +11,4 @@
<script src="{{ poche_url }}themes/default/js/autoClose.js"></script> <script src="{{ poche_url }}themes/default/js/autoClose.js"></script>
<script src="{{ poche_url }}themes/default/js/closeMessage.js"></script> <script src="{{ poche_url }}themes/default/js/closeMessage.js"></script>
<script src="{{ poche_url }}themes/default/js/saveLink.js"></script> <script src="{{ poche_url }}themes/default/js/saveLink.js"></script>
<script src="{{ poche_url }}themes/default/js/popupForm.js"></script>

View file

@ -0,0 +1,20 @@
$(document).ready(function() {
$("#search-form").hide();
function closeSearch() {
$("#search-form").toggle();
$("#search").toggleClass("current");
$("#search-arrow").toggleClass("arrow-down");
}
$("#search").click(function(){
closeSearch();
});
$("#search-form-close").click(function(){
closeSearch();
});
});

View file

@ -75,7 +75,7 @@ $.fn.ready(function() {
========================================================================== */ ========================================================================== */
$(window).keydown(function(e){ $(window).keydown(function(e){
if ( ( e.target.tagName.toLowerCase() !== 'input' && e.keyCode == 83 ) || e.keyCode == 27 ) { if ( ( e.target.tagName.toLowerCase() !== 'input' && e.keyCode == 83 ) || (e.keyCode == 27 && $bagitForm.is(':visible') ) ) {
$bagit.removeClass("current"); $bagit.removeClass("current");
$("#bagit-arrow").removeClass("arrow-down"); $("#bagit-arrow").removeClass("arrow-down");
toggleSaveLinkForm(); toggleSaveLinkForm();