aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-06-05 21:52:48 +0200
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-06-05 21:52:48 +0200
commit92993b26a88f5433fee746c1a6097566b8a3f367 (patch)
tree6e3e4991ee84238cfa51fa672d36fb5475704374
parent9b3673f945ba61059c4444a623ec16229d942fdc (diff)
parent9d4269ddcbac7b2c4efed6e8a572cfb1c0ba8f65 (diff)
Merge branch 'dev' into 320-template
-rw-r--r--CHANGELOG4
-rw-r--r--app/Models/EntryDAO.php72
-rw-r--r--app/Models/Feed.php4
-rw-r--r--app/Models/Themes.php3
-rw-r--r--app/layout/nav_menu.phtml55
-rw-r--r--app/views/configure/categorize.phtml10
-rw-r--r--app/views/configure/feed.phtml15
-rw-r--r--app/views/configure/sharing.phtml30
-rw-r--r--app/views/configure/users.phtml14
-rw-r--r--lib/SimplePie/SimplePie.php4
-rw-r--r--lib/lib_date.php131
-rw-r--r--p/scripts/main.js5
-rw-r--r--p/themes/icons/view-global.svg1
-rw-r--r--p/themes/icons/view-normal.svg1
-rw-r--r--p/themes/icons/view-reader.svg1
15 files changed, 251 insertions, 99 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0893283a5..ea9386f2c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,10 @@
* FreshRSS can now be used from e.g.:
* (Android) News+ https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader
* (Android) EasyRSS https://github.com/Alkarex/EasyRSS
+* Basic support for audio and video podcasts
+* Searching
+ * New search filters date: and pubdate: accepting ISO 8601 date intervals such as `date:2013-2014` or `pubdate:P1W`
+ * Possibility to combine search filters, e.g. `date:2014-05 intitle:FreshRSS intitle:Open great reader #Internet`
## 2014-02-19 FreshRSS 0.7.1
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 73893a88d..4e24541dc 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -478,48 +478,50 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
}
$search = '';
if ($filter !== '') {
+ require_once(LIB_PATH . '/lib_date.php');
$filter = trim($filter);
$filter = addcslashes($filter, '\\%_');
- if (stripos($filter, 'intitle:') === 0) {
- $filter = substr($filter, strlen('intitle:'));
- $intitle = true;
- } else {
- $intitle = false;
- }
- if (stripos($filter, 'inurl:') === 0) {
- $filter = substr($filter, strlen('inurl:'));
- $inurl = true;
- } else {
- $inurl = false;
- }
- if (stripos($filter, 'author:') === 0) {
- $filter = substr($filter, strlen('author:'));
- $author = true;
- } else {
- $author = false;
- }
$terms = array_unique(explode(' ', $filter));
- sort($terms); //Put #tags first
+ //sort($terms); //Put #tags first //TODO: Put the cheapest filters first
foreach ($terms as $word) {
$word = trim($word);
- if (strlen($word) > 0) {
- if ($intitle) {
- $search .= 'AND e1.title LIKE ? ';
- $values[] = '%' . $word .'%';
- } elseif ($inurl) {
- $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
- $values[] = '%' . $word .'%';
- } elseif ($author) {
- $search .= 'AND e1.author LIKE ? ';
+ if (stripos($word, 'intitle:') === 0) {
+ $word = substr($word, strlen('intitle:'));
+ $search .= 'AND e1.title LIKE ? ';
+ $values[] = '%' . $word .'%';
+ } elseif (stripos($word, 'inurl:') === 0) {
+ $word = substr($word, strlen('inurl:'));
+ $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
+ $values[] = '%' . $word .'%';
+ } elseif (stripos($word, 'author:') === 0) {
+ $word = substr($word, strlen('author:'));
+ $search .= 'AND e1.author LIKE ? ';
+ $values[] = '%' . $word .'%';
+ } elseif (stripos($word, 'date:') === 0) {
+ $word = substr($word, strlen('date:'));
+ list($minDate, $maxDate) = parseDateInterval($word);
+ if ($minDate) {
+ $search .= 'AND e1.id >= ' . $minDate . '000000 ';
+ }
+ if ($maxDate) {
+ $search .= 'AND e1.id <= ' . $maxDate . '000000 ';
+ }
+ } elseif (stripos($word, 'pubdate:') === 0) {
+ $word = substr($word, strlen('pubdate:'));
+ list($minDate, $maxDate) = parseDateInterval($word);
+ if ($minDate) {
+ $search .= 'AND e1.date >= ' . $minDate . ' ';
+ }
+ if ($maxDate) {
+ $search .= 'AND e1.date <= ' . $maxDate . ' ';
+ }
+ } else {
+ if ($word[0] === '#' && isset($word[1])) {
+ $search .= 'AND e1.tags LIKE ? ';
$values[] = '%' . $word .'%';
} else {
- if ($word[0] === '#' && isset($word[1])) {
- $search .= 'AND e1.tags LIKE ? ';
- $values[] = '%' . $word .'%';
- } else {
- $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
- $values[] = '%' . $word .'%';
- }
+ $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
+ $values[] = '%' . $word .'%';
}
}
}
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index 13d3dfe88..757eacd59 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -259,6 +259,10 @@ class FreshRSS_Feed extends Minz_Model {
$mime = strtolower($enclosure->get_type());
if (strpos($mime, 'image/') === 0) {
$content .= '<br /><img src="' . $elink . '" alt="" />';
+ } elseif (strpos($mime, 'audio/') === 0) {
+ $content .= '<br /><audio src="' . $elink . '" controls="controls" />';
+ } elseif (strpos($mime, 'video/') === 0) {
+ $content .= '<br /><video src="' . $elink . '" controls="controls" />';
}
}
}
diff --git a/app/Models/Themes.php b/app/Models/Themes.php
index 17b95bb9e..620149934 100644
--- a/app/Models/Themes.php
+++ b/app/Models/Themes.php
@@ -93,6 +93,9 @@ class FreshRSS_Themes extends Minz_Model {
'starred' => '★',
'tag' => '⚐',
'up' => '△',
+ 'view-normal' => '☰',
+ 'view-global' => '☷',
+ 'view-reader' => '☕',
);
if (!isset($alts[$name])) {
return '';
diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml
index 9990448ba..1114d0060 100644
--- a/app/layout/nav_menu.phtml
+++ b/app/layout/nav_menu.phtml
@@ -169,37 +169,27 @@
</div>
<?php } ?>
- <div class="dropdown" id="nav_menu_views">
- <div id="dropdown-views" class="dropdown-target"></div>
- <a class="dropdown-toggle btn" href="#dropdown-views"><?php echo Minz_Translate::t ('display'); ?> <?php echo FreshRSS_Themes::icon('down'); ?></a>
- <ul class="dropdown-menu">
- <li class="dropdown-close"><a href="#close">❌</a></li>
+ <?php $url_output = $this->url; ?>
+ <div class="stick" id="nav_menu_views">
+ <?php $url_output['params']['output'] = 'normal'; ?>
+ <a class="view_normal btn <?php echo $actual_view == 'normal'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('normal_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+ <?php echo FreshRSS_Themes::icon("view-normal"); ?>
+ </a>
- <?php
- $url_output = $this->url;
- if ($actual_view !== 'normal') { ?>
- <li class="item">
- <?php $url_output['params']['output'] = 'normal'; ?>
- <a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
- <?php echo Minz_Translate::t ('normal_view'); ?>
- </a>
- </li>
- <?php } if($actual_view !== 'reader') { ?>
- <li class="item">
- <?php $url_output['params']['output'] = 'reader'; ?>
- <a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
- <?php echo Minz_Translate::t ('reader_view'); ?>
- </a>
- </li>
- <?php } if($actual_view !== 'global') { ?>
- <li class="item">
- <?php $url_output['params']['output'] = 'global'; ?>
- <a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
- <?php echo Minz_Translate::t ('global_view'); ?>
- </a>
- </li>
- <?php } ?>
- </ul>
+ <?php $url_output['params']['output'] = 'global'; ?>
+ <a class="view_global btn <?php echo $actual_view == 'global'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('global_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+ <?php echo FreshRSS_Themes::icon("view-global"); ?>
+ </a>
+
+ <?php $url_output['params']['output'] = 'reader'; ?>
+ <a class="view_reader btn <?php echo $actual_view == 'reader'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('reader_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+ <?php echo FreshRSS_Themes::icon("view-reader"); ?>
+ </a>
+
+ <?php $url_output['params']['output'] = 'rss'; ?>
+ <a class="view_rss btn" target="_blank" title="<?php echo Minz_Translate::t ('rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+ <?php echo FreshRSS_Themes::icon('rss'); ?>
+ </a>
</div>
<div class="item search">
@@ -240,11 +230,6 @@
<a class="btn" href="<?php echo Minz_Url::display ($url_order); ?>" title="<?php echo Minz_Translate::t ($title); ?>">
<?php echo FreshRSS_Themes::icon($icon); ?>
</a>
-
- <?php $url_output['params']['output'] = 'rss'; ?>
- <a class="btn view_rss" target="_blank" href="<?php echo Minz_Url::display ($url_output); ?>" title="<?php echo Minz_Translate::t ('rss_view'); ?>">
- <?php echo FreshRSS_Themes::icon('rss'); ?>
- </a>
<?php if ($this->loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?>
<a id="actualize" class="btn" href="<?php echo _url ('feed', 'actualize'); ?>"><?php echo FreshRSS_Themes::icon('refresh'); ?></a>
diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml
index c0171d2dc..9bae99b39 100644
--- a/app/views/configure/categorize.phtml
+++ b/app/views/configure/categorize.phtml
@@ -14,11 +14,13 @@
<?php echo Minz_Translate::t ('category_number', $i); ?>
</label>
<div class="group-controls">
- <input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
+ <div class="stick">
+ <input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
- <?php if ($cat->nbFeed () > 0) { ?>
- <button type="submit" class="btn btn-attention confirm" formaction="<?php echo _url ('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"><?php echo Minz_Translate::t ('ask_empty'); ?></button>
- <?php } ?>
+ <?php if ($cat->nbFeed () > 0) { ?>
+ <button type="submit" class="btn btn-attention confirm" formaction="<?php echo _url ('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"><?php echo Minz_Translate::t ('ask_empty'); ?></button>
+ <?php } ?>
+ </div>
(<?php echo Minz_Translate::t ('number_feeds', $cat->nbFeed ()); ?>)
<?php if ($cat->id () === $this->defaultCategory->id ()) { ?>
diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml
index 2da04ac2d..27b0990ff 100644
--- a/app/views/configure/feed.phtml
+++ b/app/views/configure/feed.phtml
@@ -32,16 +32,21 @@
<div class="form-group">
<label class="group-name" for="website"><?php echo Minz_Translate::t ('website_url'); ?></label>
<div class="group-controls">
- <input type="text" name="website" id="website" class="extend" value="<?php echo $this->flux->website (); ?>" />
- <a target="_blank" href="<?php echo $this->flux->website (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
+ <div class="stick">
+ <input type="text" name="website" id="website" class="extend" value="<?php echo $this->flux->website (); ?>" />
+ <a class="btn" target="_blank" href="<?php echo $this->flux->website (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
+ </div>
</div>
</div>
<div class="form-group">
<label class="group-name" for="url"><?php echo Minz_Translate::t ('feed_url'); ?></label>
<div class="group-controls">
- <input type="text" name="url" id="url" class="extend" value="<?php echo $this->flux->url (); ?>" />
- <a target="_blank" href="<?php echo $this->flux->url (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
-   <a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->flux->url (); ?>"><?php echo Minz_Translate::t ('feed_validator'); ?></a>
+ <div class="stick">
+ <input type="text" name="url" id="url" class="extend" value="<?php echo $this->flux->url (); ?>" />
+ <a class="btn" target="_blank" href="<?php echo $this->flux->url (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
+ </div>
+
+ <a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->flux->url (); ?>"><?php echo Minz_Translate::t ('feed_validator'); ?></a>
</div>
</div>
<div class="form-group">
diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml
index ddb404ef5..a952bc3b4 100644
--- a/app/views/configure/sharing.phtml
+++ b/app/views/configure/sharing.phtml
@@ -4,13 +4,16 @@
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
<form method="post" action="<?php echo _url ('configure', 'sharing'); ?>"
- data-simple='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls"><a href="#" class="share remove"><?php echo FreshRSS_Themes::icon('close'); ?></a>
+ data-simple='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls"><a href="#" class="share remove btn btn-attention"><?php echo FreshRSS_Themes::icon('close'); ?></a>
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /></div></div>'
- data-advanced='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls"><a href="#" class="share remove"><?php echo FreshRSS_Themes::icon('close'); ?></a>
+ data-advanced='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls">
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" />
+ <div class="stick">
<input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="" placeholder="<?php echo Minz_Translate::t ('share_name'); ?>" size="64" />
<input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?php echo Minz_Translate::t ('share_url'); ?>" size="64" />
- <?php echo FreshRSS_Themes::icon('help'); ?> <a target="_blank" href="##help##"><?php echo Minz_Translate::t ('more_information'); ?></a></div></div>'>
+ <a href="#" class="share remove btn btn-attention"><?php echo FreshRSS_Themes::icon('close'); ?></a></div>
+ <a target="_blank" class="btn" title="<?php echo Minz_Translate::t('more_information'); ?>" href="##help##"><?php echo FreshRSS_Themes::icon('help'); ?></a>
+ </div></div>'>
<legend><?php echo Minz_Translate::t ('sharing'); ?></legend>
<?php foreach ($this->conf->sharing as $key => $sharing): ?>
<?php $share = $this->conf->shares[$sharing['type']]; ?>
@@ -19,25 +22,30 @@
<?php echo Minz_Translate::t ($sharing['type']); ?>
</label>
<div class="group-controls">
- <a href='#' class='share remove'><?php echo FreshRSS_Themes::icon('close'); ?></a>
<input type='hidden' id='share_<?php echo $key;?>_type' name="share[<?php echo $key;?>][type]" value='<?php echo $sharing['type']?>' />
- <?php if ($share['form'] === 'advanced'):?>
- <input type="text" id="share_<?php echo $key;?>_name" name="share[<?php echo $key;?>][name]" class="extend" value="<?php echo $sharing['name']?>" placeholder="<?php echo Minz_Translate::t ('share_name'); ?>" size="64" />
- <input type="url" id="share_<?php echo $key;?>_url" name="share[<?php echo $key;?>][url]" class="extend" value="<?php echo $sharing['url']?>" placeholder="<?php echo Minz_Translate::t ('share_url'); ?>" size="64" />
- <?php echo FreshRSS_Themes::icon('help'); ?> <a target="_blank" href="<?php echo $share['help']?>"><?php echo Minz_Translate::t ('more_information'); ?></a>
- <?php endif;?>
+ <?php if ($share['form'] === 'advanced'){ ?>
+ <div class="stick">
+ <input type="text" id="share_<?php echo $key;?>_name" name="share[<?php echo $key;?>][name]" class="extend" value="<?php echo $sharing['name']?>" placeholder="<?php echo Minz_Translate::t ('share_name'); ?>" size="64" />
+ <input type="url" id="share_<?php echo $key;?>_url" name="share[<?php echo $key;?>][url]" class="extend" value="<?php echo $sharing['url']?>" placeholder="<?php echo Minz_Translate::t ('share_url'); ?>" size="64" />
+ <a href='#' class='share remove btn btn-attention'><?php echo FreshRSS_Themes::icon('close'); ?></a>
+ </div>
+
+ <a target="_blank" class="btn" title="<?php echo Minz_Translate::t('more_information'); ?>" href="<?php echo $share['help']?>"><?php echo FreshRSS_Themes::icon('help'); ?></a>
+ <?php } else { ?>
+ <a href='#' class='share remove btn btn-attention'><?php echo FreshRSS_Themes::icon('close'); ?></a>
+ <?php } ?>
</div>
</div>
<?php endforeach;?>
- <div class="form-group form-actions">
+ <div class="form-group">
<div class="group-controls">
- <a href='#' class='share add'><?php echo FreshRSS_Themes::icon('add'); ?></a>
<select>
<?php foreach($this->conf->shares as $key => $params):?>
<option value='<?php echo $key?>' data-form='<?php echo $params['form']?>' data-help='<?php if (!empty($params['help'])) {echo $params['help'];}?>'><?php echo Minz_Translate::t($key) ?></option>
<?php endforeach; ?>
</select>
+ <a href='#' class='share add btn'><?php echo FreshRSS_Themes::icon('add'); ?></a>
</div>
</div>
diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml
index fdc94cd18..c199ad53d 100644
--- a/app/views/configure/users.phtml
+++ b/app/views/configure/users.phtml
@@ -20,8 +20,10 @@
<div class="form-group">
<label class="group-name" for="passwordPlain"><?php echo Minz_Translate::t('password_form'); ?></label>
<div class="group-controls">
- <input type="password" id="passwordPlain" name="passwordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
- <a class="btn toggle-password"/><?php echo FreshRSS_Themes::icon('key'); ?></a>
+ <div class="stick">
+ <input type="password" id="passwordPlain" name="passwordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
+ <a class="btn toggle-password"/><?php echo FreshRSS_Themes::icon('key'); ?></a>
+ </div>
<noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
</div>
</div>
@@ -31,7 +33,7 @@
<label class="group-name" for="apiPasswordPlain"><?php echo Minz_Translate::t('password_api'); ?></label>
<div class="group-controls">
<input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
- <noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
+ <a class="btn toggle-password"/><?php echo FreshRSS_Themes::icon('key'); ?></a>
</div>
</div>
<?php } ?>
@@ -178,8 +180,10 @@
<div class="form-group">
<label class="group-name" for="new_user_passwordPlain"><?php echo Minz_Translate::t('password_form'); ?></label>
<div class="group-controls">
- <input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" autocomplete="off" pattern=".{7,}" />
- <a class="btn toggle-password"/><?php echo FreshRSS_Themes::icon('key'); ?></a>
+ <div class="stick">
+ <input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" autocomplete="off" pattern=".{7,}" />
+ <a class="btn toggle-password"/><?php echo FreshRSS_Themes::icon('key'); ?></a>
+ </div>
<noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
</div>
</div>
diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php
index d7aaeb0c5..685fe1cc0 100644
--- a/lib/SimplePie/SimplePie.php
+++ b/lib/SimplePie/SimplePie.php
@@ -1331,7 +1331,7 @@ class SimplePie
// First check to see if input has been overridden.
if ($this->input_encoding !== false)
{
- $encodings[] = strtoupper($this->input_encoding); //FreshRSS
+ $encodings[] = strtoupper($this->input_encoding);
}
$application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
@@ -1355,7 +1355,7 @@ class SimplePie
{
if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
{
- $encodings[] = strtoupper($charset[1]); //FreshRSS
+ $encodings[] = strtoupper($charset[1]);
}
else
{
diff --git a/lib/lib_date.php b/lib/lib_date.php
new file mode 100644
index 000000000..9533711e3
--- /dev/null
+++ b/lib/lib_date.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Author: Alexandre Alapetite http://alexandre.alapetite.fr
+ * 2014-06-01
+ * License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
+ * Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
+ */
+
+/*
+example('2014-03');
+example('201403');
+example('2014-03-30');
+example('2014-05-30T13');
+example('2014-05-30T13:30');
+example('2014-02/2014-04');
+example('2014-02--2014-04');
+example('2014-02/04');
+example('2014-02-03/05');
+example('2014-02-03T22:00/22:15');
+example('2014-02-03T22:00/15');
+example('2014-03/');
+example('/2014-03');
+example('2014-03/P1W');
+example('P1W/2014-05-25T23:59:59');
+example('P1Y/');
+example('P1Y');
+example('P2M/');
+example('P3W/');
+example('P4D/');
+example('PT5H/');
+example('PT6M/');
+example('PT7S/');
+example('P1DT1H/');
+
+function example($dateInterval) {
+ $dateIntervalArray = parseDateInterval($dateInterval);
+ echo $dateInterval, "\t=>\t",
+ $dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
+ $dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
+}
+*/
+
+function _dateFloor($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
+ return str_pad($x[0], 8, '01') . 'T' . $t;
+}
+
+function _dateCeiling($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
+ switch (strlen($x[0])) {
+ case 4:
+ return $x[0] . '1231T' . $t;
+ case 6:
+ $d = @strtotime($x[0] . '01');
+ return $x[0] . date('t', $d) . 'T' . $t;
+ default:
+ return $x[0] . 'T' . $t;
+ }
+}
+
+function _noDelimit($isoDate) {
+ return $isoDate === null || $isoDate === '' ? null :
+ str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
+}
+
+function _dateRelative($d1, $d2) {
+ if ($d2 === null) {
+ return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
+ } elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
+ $y2 = substr($d2, 0, 4);
+ if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
+ $d2 = _noDelimit($d2);
+ return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
+ }
+ }
+ return _noDelimit($d2);
+}
+
+/**
+ * Parameter $dateInterval is a string containing an ISO 8601 time interval.
+ * Returns an array with the minimum and maximum Unix timestamp of this interval,
+ * or null if open interval, or false if error.
+ */
+function parseDateInterval($dateInterval) {
+ $dateInterval = trim($dateInterval);
+ $dateInterval = str_replace('--', '/', $dateInterval);
+ $dateInterval = strtoupper($dateInterval);
+ $min = null;
+ $max = null;
+ $x = explode('/', $dateInterval, 2);
+ $d1 = _noDelimit($x[0]);
+ $d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
+ if ($d1 !== null && $d1[0] !== 'P') {
+ $min = @strtotime(_dateFloor($d1));
+ }
+ if ($d2 !== null) {
+ if ($d2[0] === 'P') {
+ try {
+ $di2 = new DateInterval($d2);
+ $dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
+ if ($min !== null && $min !== false) {
+ $dt1->setTimestamp($min);
+ }
+ $max = $dt1->add($di2)->getTimestamp() - 1;
+ } catch (Exception $e) {
+ $max = false;
+ }
+ } elseif ($d1 === null || $d1[0] !== 'P') {
+ $max = @strtotime(_dateCeiling($d2));
+ } else {
+ $max = @strtotime($d2);
+ }
+ }
+ if ($d1 !== null && $d1[0] === 'P') {
+ try {
+ $di1 = new DateInterval($d1);
+ $dt2 = @date_create();
+ if ($max !== null && $max !== false) {
+ $dt2->setTimestamp($max);
+ }
+ $min = $dt2->sub($di1)->getTimestamp() + 1;
+ } catch (Exception $e) {
+ $min = false;
+ }
+ }
+ return array($min, $max);
+}
diff --git a/p/scripts/main.js b/p/scripts/main.js
index c422f8b7c..e1a19d6ac 100644
--- a/p/scripts/main.js
+++ b/p/scripts/main.js
@@ -981,15 +981,16 @@ function init_share_observers() {
});
$('.share.add').on('click', function(e) {
- e.preventDefault();
var opt = $(this).siblings('select').find(':selected');
var row = $(this).parents('form').data(opt.data('form'));
row = row.replace('##label##', opt.html(), 'g');
row = row.replace('##type##', opt.val(), 'g');
row = row.replace('##help##', opt.data('help'), 'g');
row = row.replace('##key##', shares, 'g');
- $(this).parents('.form-actions').before(row);
+ $(this).parents('.form-group').before(row);
shares++;
+
+ return false;
});
}
diff --git a/p/themes/icons/view-global.svg b/p/themes/icons/view-global.svg
new file mode 100644
index 000000000..d81e79790
--- /dev/null
+++ b/p/themes/icons/view-global.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g transform="translate(-61-867)" fill="#666" color="#000"><rect height="2" rx=".385" ry=".379" width="2" x="64" y="870"/><rect height="2" rx=".385" ry=".379" width="2" x="68" y="870"/><rect height="2" rx=".385" ry=".379" width="2" x="72" y="870"/><rect height="2" rx=".385" ry=".379" width="2" x="64" y="874.02"/><rect height="2" rx=".385" ry=".379" width="2" x="68" y="874.02"/><rect height="2" rx=".385" ry=".379" width="2" x="72" y="874.02"/><rect height="2" rx=".385" ry=".379" width="2" x="64" y="878"/><rect height="2" rx=".385" ry=".379" width="2" x="68" y="878"/><rect height="2" rx=".385" ry=".379" width="2" x="72" y="878"/></g></svg> \ No newline at end of file
diff --git a/p/themes/icons/view-normal.svg b/p/themes/icons/view-normal.svg
new file mode 100644
index 000000000..c35b101df
--- /dev/null
+++ b/p/themes/icons/view-normal.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g transform="translate(-40-746)" fill="#666" color="#666"><path d="m43 749h10v2h-10z"/><path d="m43 753h10v2h-10z"/><path d="m43 757h10v2h-10z"/></g></svg> \ No newline at end of file
diff --git a/p/themes/icons/view-reader.svg b/p/themes/icons/view-reader.svg
new file mode 100644
index 000000000..3243aed6e
--- /dev/null
+++ b/p/themes/icons/view-reader.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g transform="translate(-181-867)" fill="#666" color="#666"><path d="m 181,868 0,1 0,11 0,1 1,0 5,0 c 0.1754,0 0.52538,0.15166 0.8125,0.34375 0.28712,0.19209 0.46875,0.375 0.46875,0.375 L 189,882.4375 l 0.71875,-0.75 c 0,0 0.8963,-0.6875 1.28125,-0.6875 l 5,0 1,0 0,-1 0,-11 0,-1 -1,0 -5,0 c -0.87652,0 -1.56017,0.34756 -2.03125,0.6875 -0.0301,-0.0207 -0.031,-0.0105 -0.0625,-0.0312 C 188.44557,868.35254 187.82811,868 187,868 l -5,0 -1,0 z m 2,2 4,0 c 0.13821,0 0.51476,0.14746 0.8125,0.34375 0.29774,0.19629 0.5,0.375 0.5,0.375 l 0.71875,0.6875 0.6875,-0.71875 c 0,0 0.89975,-0.6875 1.28125,-0.6875 l 4,0 0,9 -4,0 c -0.87693,0 -1.56008,0.34735 -2.03125,0.6875 -0.0196,-0.0135 -0.011,-0.0177 -0.0312,-0.0312 C 188.47725,879.34834 187.83512,879 187,879 l -4,0 0,-9 z"/><g transform="scale(-1 1)"><rect height="2" rx=".375" width="3" x="-187" y="872"/><rect height="2" rx=".375" width="3" x="-187" y="875"/><rect height="2" rx=".375" width="3" x="-194" y="872"/><rect height="2" rx=".375" width="3" x="-194" y="875"/></g></g></svg> \ No newline at end of file