aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag')
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php65
-rw-r--r--src/Wallabag/CoreBundle/Helper/EntriesExport.php263
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig18
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig9
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig1
-rwxr-xr-xsrc/Wallabag/CoreBundle/Resources/views/themes/material/public/js/init.js9
6 files changed, 361 insertions, 4 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php
new file mode 100644
index 00000000..123e491a
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Controller/ExportController.php
@@ -0,0 +1,65 @@
1<?php
2
3namespace Wallabag\CoreBundle\Controller;
4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\CoreBundle\Helper\EntriesExport;
9
10class ExportController extends Controller
11{
12 /**
13 * Gets all entries for current user.
14 *
15 * @Route("/export/{category}.{format}", name="ebook", requirements={
16 * "_format": "epub|mobi|pdf|json|xml|txt|csv"
17 * })
18 */
19 public function getEntriesAction($format, $category)
20 {
21 $repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
22 switch ($category) {
23 case 'all':
24 $method = 'All';
25 break;
26
27 case 'unread':
28 $method = 'Unread';
29 break;
30
31 case 'starred':
32 $method = 'Starred';
33 break;
34
35 case 'archive':
36 $method = 'Archive';
37 break;
38
39 default:
40 break;
41 }
42
43 $methodBuilder = 'getBuilderFor'.$method.'ByUser';
44 $qb = $repository->$methodBuilder($this->getUser()->getId());
45 $entries = $qb->getQuery()->getResult();
46
47 $export = new EntriesExport($entries);
48 $export->setMethod($method);
49 $export->exportAs($format);
50 }
51
52 /**
53 * Gets one entry content.
54 *
55 * @param Entry $entry
56 *
57 * @Route("/export/id/{id}.{format}", requirements={"id" = "\d+"}, name="ebook_entry")
58 */
59 public function getEntryAction(Entry $entry, $format)
60 {
61 $export = new EntriesExport(array($entry));
62 $export->setMethod('entry');
63 $export->exportAs($format);
64 }
65}
diff --git a/src/Wallabag/CoreBundle/Helper/EntriesExport.php b/src/Wallabag/CoreBundle/Helper/EntriesExport.php
new file mode 100644
index 00000000..fad0bb97
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Helper/EntriesExport.php
@@ -0,0 +1,263 @@
1<?php
2
3namespace Wallabag\CoreBundle\Helper;
4
5use PHPePub\Core\EPub;
6use PHPePub\Core\Structure\OPF\DublinCore;
7
8class EntriesExport
9{
10 private $format;
11 private $method;
12 private $title;
13 private $entries;
14 private $authors = array('wallabag');
15 private $language;
16 private $tags;
17
18 public function __construct($entries)
19 {
20 $this->entries = $entries;
21
22 foreach ($entries as $entry) {
23 $this->tags[] = $entry->getTags();
24 }
25 if (count($entries) === 1) {
26 $this->language = $entries[0]->getLanguage();
27 }
28 }
29
30 /**
31 * Sets the category of which we want to get articles, or just one entry.
32 *
33 * @param string $method Method to get articles
34 */
35 public function setMethod($method)
36 {
37 $this->method = $method;
38
39 switch ($this->method) {
40 case 'All':
41 $this->title = 'All Articles';
42 break;
43 case 'Unread':
44 $this->title = 'Unread articles';
45 break;
46 case 'Starred':
47 $this->title = 'Starred articles';
48 break;
49 case 'Archive':
50 $this->title = 'Archived articles';
51 break;
52 case 'entry':
53 $this->title = $this->entries[0]->getTitle();
54 break;
55 default:
56 break;
57 }
58 }
59
60 /**
61 * Sets the output format.
62 *
63 * @param string $format
64 */
65 public function exportAs($format)
66 {
67 $this->format = $format;
68
69 switch ($this->format) {
70 case 'epub':
71 $this->produceEpub();
72 break;
73
74 case 'mobi':
75 $this->produceMobi();
76 break;
77
78 case 'pdf':
79 $this->producePDF();
80 break;
81
82 case 'csv':
83 $this->produceCSV();
84 break;
85
86 default:
87 break;
88 }
89 }
90
91 private function produceEpub()
92 {
93 /*
94 * Start and End of the book
95 */
96 $content_start =
97 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
98 ."<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n"
99 .'<head>'
100 ."<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n"
101 .'<title>'._('wallabag articles book')."</title>\n"
102 ."</head>\n"
103 ."<body>\n";
104
105 $bookEnd = "</body>\n</html>\n";
106
107 $book = new EPub(EPub::BOOK_VERSION_EPUB3);
108
109 /*
110 * Book metadata
111 */
112
113 $book->setTitle($this->title);
114 $book->setIdentifier($this->title, EPub::IDENTIFIER_URI); // Could also be the ISBN number, prefered for published books, or a UUID.
115 $book->setLanguage($this->language); // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc.
116 $book->setDescription(_('Some articles saved on my wallabag'));
117
118 foreach ($this->authors as $author) {
119 $book->setAuthor($author, $author);
120 }
121
122 $book->setPublisher('wallabag', 'wallabag'); // I hope this is a non existant address :)
123 $book->setDate(time()); // Strictly not needed as the book date defaults to time().
124 $book->setSourceURL("http://$_SERVER[HTTP_HOST]");
125
126 $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP');
127 $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag');
128
129 /*
130 * Front page
131 */
132
133 $book->setCoverImage('Cover.png', file_get_contents('themes/_global/img/appicon/apple-touch-icon-152.png'), 'image/png');
134
135 $cover = $content_start.'<div style="text-align:center;"><p>'._('Produced by wallabag with PHPePub').'</p><p>'._('Please open <a href="https://github.com/wallabag/wallabag/issues" >an issue</a> if you have trouble with the display of this E-Book on your device.').'</p></div>'.$bookEnd;
136
137 $book->addChapter('Notices', 'Cover2.html', $cover);
138
139 $book->buildTOC();
140
141 /*
142 * Adding actual entries
143 */
144
145 foreach ($this->entries as $entry) { //set tags as subjects
146 foreach ($this->tags as $tag) {
147 $book->setSubject($tag['value']);
148 }
149
150 $chapter = $content_start.$entry->getContent().$bookEnd;
151 $book->addChapter($entry->getTitle(), htmlspecialchars($entry->getTitle()).'.html', $chapter, true, EPub::EXTERNAL_REF_ADD);
152 }
153 $book->finalize();
154 $book->sendBook($this->title);
155 }
156
157 private function produceMobi()
158 {
159 $mobi = new \MOBI();
160 $content = new \MOBIFile();
161
162 /*
163 * Book metadata
164 */
165
166 $content->set('title', $this->title);
167 $content->set('author', implode($this->authors));
168 $content->set('subject', $this->title);
169
170 /*
171 * Front page
172 */
173
174 $content->appendParagraph('<div style="text-align:center;" ><p>'._('Produced by wallabag with PHPMobi').'</p><p>'._('Please open <a href="https://github.com/wallabag/wallabag/issues" >an issue</a> if you have trouble with the display of this E-Book on your device.').'</p></div>');
175 $content->appendImage(imagecreatefrompng('themes/_global/img/appicon/apple-touch-icon-152.png'));
176 $content->appendPageBreak();
177
178 /*
179 * Adding actual entries
180 */
181
182 foreach ($this->entries as $entry) {
183 $content->appendChapterTitle($entry->getTitle());
184 $content->appendParagraph($entry->getContent());
185 $content->appendPageBreak();
186 }
187 $mobi->setContentProvider($content);
188
189 // the browser inside Kindle Devices doesn't likes special caracters either, we limit to A-z/0-9
190 $this->title = preg_replace('/[^A-Za-z0-9\-]/', '', $this->title);
191
192 // we offer file to download
193 $mobi->download($this->title.'.mobi');
194 }
195
196 private function producePDF()
197 {
198 $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
199
200 /*
201 * Book metadata
202 */
203
204 $pdf->SetCreator(PDF_CREATOR);
205 $pdf->SetAuthor('wallabag');
206 $pdf->SetTitle($this->title);
207 $pdf->SetSubject('Articles via wallabag');
208 $pdf->SetKeywords('wallabag');
209
210 /*
211 * Front page
212 */
213
214 $pdf->AddPage();
215 $intro = '<h1>'.$this->title.'</h1><div style="text-align:center;" >
216 <p>'._('Produced by wallabag with tcpdf').'</p>
217 <p>'._('Please open <a href="https://github.com/wallabag/wallabag/issues" >an issue</a> if you have trouble with the display of this E-Book on your device.').'</p>
218 <img src="themes/_global/img/appicon/apple-touch-icon-152.png" /></div>';
219
220 $pdf->writeHTMLCell(0, 0, '', '', $intro, 0, 1, 0, true, '', true);
221
222 /*
223 * Adding actual entries
224 */
225
226 foreach ($this->entries as $entry) {
227 foreach ($this->tags as $tag) {
228 $pdf->SetKeywords($tag['value']);
229 }
230
231 $pdf->AddPage();
232 $html = '<h1>'.$entry->getTitle().'</h1>';
233 $html .= $entry->getContent();
234 $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
235 }
236
237 // set image scale factor
238 $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
239
240 $pdf->Output($this->title.'.pdf', 'D');
241 }
242
243 private function produceCSV()
244 {
245 header('Content-type: application/csv');
246 header('Content-Disposition: attachment; filename="'.$this->title.'.csv"');
247 header('Content-Transfer-Encoding: UTF-8');
248
249 $output = fopen('php://output', 'a');
250
251 fputcsv($output, array('Title', 'URL', 'Content', 'Tags', 'MIME Type', 'Language'));
252 foreach ($this->entries as $entry) {
253 fputcsv($output, array($entry->getTitle(),
254 $entry->getURL(),
255 $entry->getContent(),
256 implode(', ', $entry->getTags()->toArray()),
257 $entry->getMimetype(),
258 $entry->getLanguage(), ));
259 }
260 fclose($output);
261 exit();
262 }
263}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
index 668824bc..5a231c86 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
@@ -91,6 +91,24 @@
91 {% endfor %} 91 {% endfor %}
92 </ul> 92 </ul>
93 93
94 <!-- Export -->
95 <div id="export" class="side-nav fixed right-aligned">
96 {% set currentRoute = app.request.attributes.get('_route') %}
97 {% if currentRoute == 'homepage' %}
98 {% set currentRoute = 'unread' %}
99 {% endif %}
100 <h4 class="center">{% trans %}Export{% endtrans %}</h4>
101 <ul>
102 <li class="bold"><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'epub' }) }}">{% trans %}EPUB{% endtrans %}</a></li>
103 <li class="bold"><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'mobi' }) }}">{% trans %}MOBI{% endtrans %}</a></li>
104 <li class="bold"><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'pdf' }) }}">{% trans %}PDF{% endtrans %}</a></li>
105 <li class="bold"><del><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'xml' }) }}">{% trans %}XML{% endtrans %}</a></del></li>
106 <li class="bold"><del><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'json' }) }}">{% trans %}JSON{% endtrans %}</a></del></li>
107 <li class="bold"><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'csv' }) }}">{% trans %}CSV{% endtrans %}</a></li>
108 <li class="bold"><del><a class="waves-effect" href="{{ path('ebook', { 'category': currentRoute, 'format': 'txt' }) }}">{% trans %}TXT{% endtrans %}</a></del></li>
109 </ul>
110 </div>
111
94 <!-- Filters --> 112 <!-- Filters -->
95 <div id="filters" class="side-nav fixed right-aligned"> 113 <div id="filters" class="side-nav fixed right-aligned">
96 <form action="{{ path('all') }}"> 114 <form action="{{ path('all') }}">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
index 7230506c..bece099a 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
@@ -102,13 +102,14 @@
102 <li class="bold"> 102 <li class="bold">
103 <a class="waves-effect collapsible-header"> 103 <a class="waves-effect collapsible-header">
104 <i class="mdi-file-file-download small"></i> 104 <i class="mdi-file-file-download small"></i>
105 <span><del>{% trans %}Download{% endtrans %}</del></span> 105 <span>{% trans %}Download{% endtrans %}</span>
106 </a> 106 </a>
107 <div class="collapsible-body"> 107 <div class="collapsible-body">
108 <ul> 108 <ul>
109 {% if export_epub %}<li><del><a href="?epub&amp;method=id&amp;value={{ entry.id }}" title="Generate ePub file">EPUB</a></del></li>{% endif %} 109 {% if export_epub %}<li><a href="{{ path('ebook_entry', { 'id': entry.id, 'format': 'epub' }) }}" title="Generate ePub file">EPUB</a></li>{% endif %}
110 {% if export_mobi %}<li><del><a href="?mobi&amp;method=id&amp;value={{ entry.id }}" title="Generate Mobi file">MOBI</a></del></li>{% endif %} 110 {% if export_mobi %}<li><a href="{{ path('ebook_entry', { 'id': entry.id, 'format': 'mobi' }) }}" title="Generate Mobi file">MOBI</a></li>{% endif %}
111 {% if export_pdf %}<li><del><a href="?pdf&amp;method=id&amp;value={{ entry.id }}" title="Generate PDF file">PDF</a></del> </li>{% endif %} 111 {% if export_pdf %}<li><a href="{{ path('ebook_entry', { 'id': entry.id, 'format': 'pdf' }) }}" title="Generate PDF file">PDF</a></li>{% endif %}
112 <li><a href="{{ path('ebook_entry', { 'id': entry.id, 'format': 'csv' }) }}" title="Generate CSV file">CSV</a></li>
112 </ul> 113 </ul>
113 </div> 114 </div>
114 </li> 115 </li>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
index 95b3977c..f426e25b 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -59,6 +59,7 @@
59 <li class="bold"><a title="{% trans %}Add a new entry{% endtrans %}" class="waves-effect" href="{{ path('new') }}" id="nav-btn-add"><i class="mdi-content-add"></i></a></li> 59 <li class="bold"><a title="{% trans %}Add a new entry{% endtrans %}" class="waves-effect" href="{{ path('new') }}" id="nav-btn-add"><i class="mdi-content-add"></i></a></li>
60 <li><a title="{% trans %}Search{% endtrans %}" class="waves-effect" href="javascript: void(null);" id="nav-btn-search"><i class="mdi-action-search"></i></a> 60 <li><a title="{% trans %}Search{% endtrans %}" class="waves-effect" href="javascript: void(null);" id="nav-btn-search"><i class="mdi-action-search"></i></a>
61 <li id="button_filters"><a title="{% trans %}Filter entries{% endtrans %}" href="#" data-activates="filters" class="nav-panel-menu button-collapse-right"><i class="mdi-content-filter-list"></i></a></li> 61 <li id="button_filters"><a title="{% trans %}Filter entries{% endtrans %}" href="#" data-activates="filters" class="nav-panel-menu button-collapse-right"><i class="mdi-content-filter-list"></i></a></li>
62 <li id="button_export"><a title="{% trans %}Export{% endtrans %}" class="nav-panel-menu button-collapse-right" href="#" data-activates="export" class="nav-panel-menu button-collapse-right"><i class="mdi-file-file-download"></i></a></li>
62 </ul> 63 </ul>
63 </div> 64 </div>
64 <form method="get" action="index.php"> 65 <form method="get" action="index.php">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/js/init.js b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/js/init.js
index edfdee82..491a7916 100755
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/public/js/init.js
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/public/js/init.js
@@ -11,6 +11,14 @@ function init_filters() {
11 } 11 }
12} 12}
13 13
14function init_export() {
15 // no display if export not aviable
16 if ($("div").is("#export")) {
17 $('#button_export').show();
18 $('.button-collapse-right').sideNav({ edge: 'right' });
19 }
20}
21
14$(document).ready(function(){ 22$(document).ready(function(){
15 // sideNav 23 // sideNav
16 $('.button-collapse').sideNav(); 24 $('.button-collapse').sideNav();
@@ -26,6 +34,7 @@ $(document).ready(function(){
26 format: 'dd/mm/yyyy', 34 format: 'dd/mm/yyyy',
27 }); 35 });
28 init_filters(); 36 init_filters();
37 init_export();
29 38
30 $('#nav-btn-add-tag').on('click', function(){ 39 $('#nav-btn-add-tag').on('click', function(){
31 $(".nav-panel-add-tag").toggle(100); 40 $(".nav-panel-add-tag").toggle(100);