php_code_sniffer: true
php_pdepend: true
sensiolabs_security_checker: true
- external_code_coverage:
- timeout: 1800
+ #external_code_coverage:
+ # timeout: 3600
php_code_coverage: true
php_sim: false
php_cpd: false
To fix the bug quickly, we need some infos:
* your wallabag version (on top of the ./index.php file, and also on config page)
* your webserver installation :
- * type of hosting (shared or dedicaced)
- * in case of a dedicaced server, the server and OS used
+ * type of hosting (shared or dedicated)
+ * in case of a dedicated server, the server and OS used
* the php version used, eventually `phpinfo()`
* which storage system you choose at install (SQLite, MySQL/MariaDB or PostgreSQL)
* any problem on the `wallabag_compatibility_test.php` page
## You want to fix a bug or to add a feature
Please fork wallabag and work with **the dev branch** only. **Do not work on master branch**.
-[Don't forget to read our guidelines](https://github.com/wallabag/wallabag/blob/dev/GUIDELINES.md).
\ No newline at end of file
+[Don't forget to read our guidelines](https://github.com/wallabag/wallabag/blob/dev/GUIDELINES.md).
-Copyright (c) 2013-2014 Nicolas Lœuillet\r
+Copyright (c) 2013-2015 Nicolas Lœuillet\r
\r
Permission is hereby granted, free of charge, to any person obtaining a copy\r
of this software and associated documentation files (the "Software"), to deal\r
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.
\ No newline at end of file
+THE SOFTWARE.\r
-wallabag is based on :
-* PHP Readability https://bitbucket.org/fivefilters/php-readability
-* Full Text RSS http://code.fivefilters.org/full-text-rss/src
-* logo by Maylis Agniel https://github.com/wallabag/logo
-* icons http://icomoon.io
-* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/
-* Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php
-* Twig http://twig.sensiolabs.org
-* Flash messages https://github.com/plasticbrain/PHP-Flash-Messages
-* Pagination https://github.com/daveismyname/pagination
-* PHPePub https://github.com/Grandt/PHPePub/
+wallabag is mainly developed by [Nicolas Lœuillet](https://github.com/nicosomb) under the MIT License.
-wallabag is mainly developed by Nicolas Lœuillet under the MIT License
+Thank you so much to [@tcitworld](https://github.com/tcitworld) and [@j0k3r](https://github.com/j0k3r).
-Thank you so much to @tcitworld and @mariroz.
-
-Contributors : https://github.com/wallabag/wallabag/graphs/contributors
+Thank you [to others contributors](https://github.com/wallabag/wallabag/graphs/contributors
+).
"name": "Thomas Citharel",
"homepage": "http://tcit.fr",
"role": "Developer"
+ },
+ {
+ "name": "Jérémy Benoist",
+ "role": "Developer"
}
],
"support": {
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
- $builder->add('readingTime', 'filter_number_range');
+ $builder
+ ->add('readingTime', 'filter_number_range')
+ ->add('createdAt', 'filter_date_range', array(
+ 'left_date_options' => array(
+ 'attr' => array(
+ 'placeholder' => 'dd/mm/yyyy'),
+ 'format' => 'dd/MM/yyyy',
+ 'widget' => 'single_text'
+ ),
+ 'right_date_options' => array(
+ 'attr' => array(
+ 'placeholder' => 'dd/mm/yyyy'),
+ 'format' => 'dd/MM/yyyy',
+ 'widget' => 'single_text'
+ )));
}
public function getName()
<div class="pagination">
{% for p in range(1, entries.nbPages) if entries.nbPages > 1 %}
<li>
- <a href="{{ path(app.request.attributes.get('_route'), {'page': p}) }}" class="{{ currentPage == p ? 'current':''}}" >{{ p }}</a>
+ <a href="{{ path(app.request.attributes.get('_route'), app.request.query.all|merge({'page': p})) }}" class="{{ currentPage == p ? 'current':''}}" >{{ p }}</a>
</li>
{% endfor %}
</div>
{% block content %}
{% block pager %}
- {% if entries is not empty %}
- <div class="results clearfix">
- <div class="nb-results left">{{ entries.count }} {% trans %}entries{% endtrans %}</div>
- <div class="left"><form>{{ form_rest(form) }}<button class="btn waves-effect waves-light" type="submit" id="submit-filter" value="filter">Filter</button></form></div>
- <ul class="pagination right">
- {% for p in range(1, entries.nbPages) if entries.nbPages > 1 %}
- <li class="{{ currentPage == p ? 'active':'waves-effect'}}">
- <a href="{{ path(app.request.attributes.get('_route'), {'page': p}) }}" >{{ p }}</a>
- </li>
- {% endfor %}
- </div>
+ <div class="results clearfix">
+ <div class="nb-results left">{% transchoice entries.count %}{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.{% endtranschoice %}</div>
+ <ul class="pagination right">
+ {% for p in range(1, entries.nbPages) if entries.nbPages > 1 %}
+ <li class="{{ currentPage == p ? 'active':'waves-effect'}}">
+ <a href="{{ path(app.request.attributes.get('_route'), app.request.query.all|merge({'page': p})) }}">{{ p }}</a>
+ </li>
+ {% endfor %}
</div>
- {% endif %}
+ </div>
{% endblock %}
-<br>
- {% if entries is empty %}
- <div class="messages warning"><p>{% trans %}No articles found.{% endtrans %}</p></div>
- {% else %}
- <ul class="row data">
- {% for entry in entries %}
- <li id="entry-{{ entry.id|e }}" class="col l4 m6 s12">
- <div class="card">
- <div class="card-content">
- <span class="card-title"><a href="{{ path('view', { 'id': entry.id }) }}">{{ entry.title|raw }}</a></span>
- {% if entry.readingTime > 0 %}
- <div class="estimatedTime grey-text"><span class="tool reading-time">{% trans %}estimated reading time: {% endtrans %} {{ entry.readingTime }} min</span></div>
- {% else %}
- <div class="estimatedTime grey-text"><span class="tool reading-time">{% trans %}estimated reading time: {% endtrans %} <small class="inferieur"><</small> 1 min</span></div>
- {% endif %}
- <p>{{ entry.content|striptags|slice(0, 300) }}...</p>
- </div>
- <div class="card-action">
- <span class="bold"><a href="{{ entry.url|e }}" target="_blank" title="{% trans %}original{% endtrans %}: {{ entry.title|e }}" class="tool original grey-text"><span>{{ entry.domainName }}</span></a></bold>
+ <br />
+ <ul class="row data">
+ {% for entry in entries %}
+ <li id="entry-{{ entry.id|e }}" class="col l4 m6 s12">
+ <div class="card">
+ <div class="card-content">
+ <span class="card-title"><a href="{{ path('view', { 'id': entry.id }) }}">{{ entry.title|raw }}</a></span>
+ {% if entry.readingTime > 0 %}
+ <div class="estimatedTime grey-text"><span class="tool reading-time">{% trans %}estimated reading time: {% endtrans %} {{ entry.readingTime }} min</span></div>
+ {% else %}
+ <div class="estimatedTime grey-text"><span class="tool reading-time">{% trans %}estimated reading time: {% endtrans %} <small class="inferieur"><</small> 1 min</span></div>
+ {% endif %}
+ <p>{{ entry.content|striptags|slice(0, 300) }}...</p>
+ </div>
+ <div class="card-action">
+ <span class="bold"><a href="{{ entry.url|e }}" target="_blank" title="{% trans %}original{% endtrans %}: {{ entry.title|e }}" class="tool original grey-text"><span>{{ entry.domainName }}</span></a></bold>
- <ul class="tools links right">
- <li>
- <a title="{% trans %}Toggle mark as read{% endtrans %}" class="tool grey-text {% if entry.isArchived == 0 %}mdi-action-done{% else %}mdi-content-redo{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"></a>
- <a title="{% trans %}toggle favorite{% endtrans %}" class="tool grey-text {% if entry.isStarred == 0 %}mdi-action-favorite-outline{% else %}mdi-action-favorite{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"></a>
- <a title="{% trans %}delete{% endtrans %}" class="tool grey-text delete mdi-action-delete " href="{{ path('delete_entry', { 'id': entry.id }) }}"></a>
- </li>
- </ul>
- </div>
+ <ul class="tools links right">
+ <li>
+ <a title="{% trans %}Toggle mark as read{% endtrans %}" class="tool grey-text {% if entry.isArchived == 0 %}mdi-action-done{% else %}mdi-content-redo{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"></a>
+ <a title="{% trans %}toggle favorite{% endtrans %}" class="tool grey-text {% if entry.isStarred == 0 %}mdi-action-favorite-outline{% else %}mdi-action-favorite{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"></a>
+ <a title="{% trans %}delete{% endtrans %}" class="tool grey-text delete mdi-action-delete " href="{{ path('delete_entry', { 'id': entry.id }) }}"></a>
+ </li>
+ </ul>
</div>
- </li>
- {% endfor %}
- </ul>
- {% endif %}
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+
+
+ <!-- Filters -->
+ <div id="filters" class="side-nav fixed right-aligned">
+ <form>
+
+ <h4 class="center">{% trans %}Filters{% endtrans %}</h1>
+
+ <div class="row">
+
+ <div class="col s12">
+ <label>{% trans %}Reading time in minutes{% endtrans %}</label>
+ </div>
+ <div class="input-field col s6">
+ {{ form_widget(form.readingTime.left_number, {'type': 'number'}) }}
+ <label for="entry_filter_readingTime_left_number">{% trans %}from{% endtrans %}</label>
+ </div>
+ <div class="input-field col s6">
+ {{ form_widget(form.readingTime.right_number, {'type': 'number'}) }}
+ <label for="entry_filter_readingTime_right_number">{% trans %}to{% endtrans %}</label>
+ </div>
+
+ <div class="col s12">
+ <label>{% trans %}Create at{% endtrans %}</label>
+ </div>
+
+ <div class="col s6">
+ <a href="#!" class="center waves-effect waves-green btn-flat" id="clear_form_filters">{% trans %}Clear{% endtrans %}</a>
+ </div>
+
+ <div class="col s6">
+ <button class="btn waves-effect waves-light" type="submit" id="submit-filter" value="filter">{% trans %}Filter{% endtrans %}</button>
+ </div>
+
+ </div>
+
+ </form>
+ </div>
{% endblock %}
{% block title %}{{ entry.title|raw }} ({{ entry.domainName }}){% endblock %}
{% block menu %}
+ <div class="progress">
+ <div class="determinate"></div>
+ </div>
<nav class="hide-on-large-only">
<div class="nav-wrapper cyan darken-1">
<ul>
<div class="collapsible-body"></div>
</li>
+ <li class="bold border-bottom hide-on-med-and-down">
+ <a class="waves-effect collapsible-header" href="{{ entry.url|e }}">
+ <i class="mdi-content-link small"></i>
+ <span>{% trans %}original article{% endtrans %}</span>
+ </a>
+ <div class="collapsible-body"></div>
+ </li>
+
<li class="bold hide-on-med-and-down">
<a class="waves-effect collapsible-header" title="{% trans %}Mark as read{% endtrans %}" href="{{ path('archive_entry', { 'id': entry.id }) }}" id="markAsRead">
<i class="{% if entry.isArchived == 0 %}mdi-action-done{% else %}mdi-content-redo{% endif %} small"></i>
<span class="black-text">{{ form_errors(form.url) }}</span>
{% endif %}
- {{ form_widget(form.url) }}
+ {{ form_widget(form.url, { 'attr': {'autocomplete': 'off'} }) }}
<div class="hidden">{{ form_rest(form) }}</div>
</form>
<span class="black-text"><p>{{ flashMessage }}</p></span>
{% endfor %}
- <div class="input-field s12">
- <label for="username">{% trans %}Username{% endtrans %}</label>
- <input type="text" id="username" name="_username" value="{{ last_username }}" />
- </div>
+ <div class="row">
- <div class="input-field s12">
- <label for="password">{% trans %}Password{% endtrans %}</label>
- <input type="password" id="password" name="_password" />
- </div>
+ <div class="input-field col s12">
+ <label for="username">{% trans %}Username{% endtrans %}</label>
+ <input type="text" id="username" name="_username" value="{{ last_username }}" />
+ </div>
+
+ <div class="input-field col s12">
+ <label for="password">{% trans %}Password{% endtrans %}</label>
+ <input type="password" id="password" name="_password" />
+ </div>
+
+ <div class="input-field col s12">
+ <input type="checkbox" id="remember_me" name="_remember_me" checked />
+ <label for="remember_me">{% trans %}Keep me logged in{% endtrans %}</label>
+ </div>
- <div class="input-field s12">
- <input type="checkbox" id="remember_me" name="_remember_me" checked />
- <label for="remember_me">{% trans %}Keep me logged in{% endtrans %}</label>
</div>
</div>
<ul>
<li class="bold"><a class="waves-effect" href="{{ path('new') }}" id="nav-btn-add"><i class="mdi-content-add"></i></a></li>
<li><a class="waves-effect" href="javascript: void(null);" id="nav-btn-search"><i class="mdi-action-search"></i></a>
+ <li id="button_filters"><a href="#" data-activates="filters" class="nav-panel-menu button-collapse-right"><i class="mdi-content-filter-list"></i></a></li>
</ul>
</div>
<form method="get" action="index.php">
</form>
<div class="input-field nav-panel-add" style="display: none">
{{ render(controller( "WallabagCoreBundle:Entry:addEntryForm" )) }}
- <label for="add"><i class="mdi-content-add"></i></label>
+ <label for="add" class="active"><i class="mdi-content-add"></i></label>
<i class="mdi-navigation-close"></i>
</div>
- <!--<form name="entry" method="post" action="{{ path('new_entry') }}">
- <div class="input-field nav-panel-add" style="display: none">
- <input id="add entry_url" name="entry[url]" type="search" required placeholder="{% trans %}Enter your link here{% endtrans %}">
- <label for="add"><i class="mdi-content-add"></i></label>
- <i class="mdi-navigation-close"></i>
- </div>
- </form>-->
</div>
</nav>
{% endblock %}
margin-bottom: 0;
}
+.pagination li {
+ padding: 0;
+}
+
+.pagination a {
+ padding: 0px 10px;
+ height: 30px;
+ display: block;
+}
+
.page-footer .footer-copyright p {
display: inline;
}
display: none;
}
+.picker__date-display {
+ display: none;
+}
+
/* ==========================================================================
1 = Nav
========================================================================== */
+nav input {
+ color: #aaa;
+}
+
.nav-wrapper .button-collapse {
padding: 0px 15px;
}
white-space: nowrap;
}
+.nav-panels .input-field input {
+ display: block;
+ line-height: inherit;
+ padding-left: 4rem !important;
+ width: calc(100% - 8rem);
+}
+
+.nav-panels .input-field input:focus {
+ background-color: #fff;
+ border: 0;
+ box-shadow: none;
+ color: #444;
+}
+
+.input-field.nav-panel-add label {
+ left: 1rem;
+}
+
+.input-field.nav-panel-add .mdi-navigation-close {
+ position: absolute;
+ top: 0;
+ right: 1rem;
+ color: transparent;
+ cursor: pointer;
+ font-size: 2rem;
+ transition: .3s color;
+}
+
+#button_filters {
+ display: none;
+}
+
/* ==========================================================================
2 = Side-nav
========================================================================== */
margin: 0px 1rem;
}
+/* ==========================================================================
+ * 3 = Filters slider
+ * ========================================================================== */
+
+#filters button {
+ padding: 0px;
+ width: 100%;
+}
+
+.side-nav.fixed.right-aligned {
+ right: -250px;
+ left: auto !important;
+ overflow-y: visible;
+}
+
/* ==========================================================================
3 = Cards
========================================================================== */
width: 240px !important;
}
+.reader-mode .collapsible-body {
+ height: 0;
+ overflow: hidden;
+}
+
+.reader-mode:hover .collapsible-body {
+ height: auto;
+}
+
.reader-mode span {
opacity: 0;
transition: opacity 0.2s ease;
opacity: 1;
}
+.progress {
+ position:fixed;
+ top:0px;
+ width: 100%;
+ height: 3px;
+ margin: 0;
+ z-index: 9999;
+}
/* ==========================================================================
6 = Media queries
========================================================================== */
+function init_filters() {
+ // no display if filters not aviable
+ if ($("div").is("#filters")) {
+ $('#button_filters').show();
+ $('.button-collapse-right').sideNav({ edge: 'right' });
+ $('#clear_form_filters').on('click', function(){
+ $('#filters input').val('');
+ return false;
+ });
+ }
+}
+
$(document).ready(function(){
// sideNav
$('.button-collapse').sideNav();
$('.collapsible').collapsible({
accordion : false
});
+ $('.datepicker').pickadate({
+ selectMonths: true,
+ selectYears: 15,
+ formatSubmit: 'dd/mm/yyyy',
+ hiddenName: true,
+ format: 'dd/mm/yyyy',
+ });
+ init_filters();
- $('#nav-btn-add').click(function(){
+ $('#nav-btn-add').on('click', function(){
$(".nav-panel-buttom").hide(100);
$(".nav-panel-add").show(100);
- $(".nav-panel-menu").hide(100);
$(".nav-panels .action").hide(100);
$(".nav-panel-menu").addClass('hidden');
$(".nav-panels").css('background', 'white');
$("#entry_url").focus();
return false;
});
- $('#nav-btn-search').click(function(){
+ $('#nav-btn-search').on('click', function(){
$(".nav-panel-buttom").hide(100);
$(".nav-panel-search").show(100);
$(".nav-panels .action").hide(100);
$("#searchfield").focus();
return false;
});
- $('.mdi-navigation-close').click(function(){
+ $('.mdi-navigation-close').on('click', function(){
$(".nav-panel-add").hide(100);
$(".nav-panel-search").hide(100);
$(".nav-panel-buttom").show(100);
$(".nav-panels").css('background', 'transparent');
return false;
});
+ $(window).scroll(function () {
+ var s = $(window).scrollTop(),
+ d = $(document).height(),
+ c = $(window).height();
+ var scrollPercent = (s / (d-c)) * 100;
+ $(".progress .determinate").css('width', scrollPercent+'%');
+ });
});
$this->assertCount(1, $crawler->filter('div[class=entry]'));
}
+
+ public function testPaginationWithFilter()
+ {
+ $this->logInAs('admin');
+ $client = $this->getClient();
+
+ $crawler = $client->request('GET', '/config');
+
+ $form = $crawler->filter('button[id=config_save]')->form();
+
+ $data = array(
+ 'config[items_per_page]' => '1',
+ );
+
+ $client->submit($form, $data);
+
+ $parameters = '?entry_filter%5BreadingTime%5D%5Bleft_number%5D=&entry_filter%5BreadingTime%5D%5Bright_number%5D=';
+
+ $crawler = $client->request('GET', 'unread/list'.$parameters);
+
+ $this->assertContains($parameters, $client->getResponse()->getContent());
+ }
}