OPiQuotations  v.03.00.00 — April 5, 2019
OPiQuotation.inc
Go to the documentation of this file.
1 <?php /* -*- coding: utf-8 -*- */
2 
3 /** \file OPiQuotation.inc
4  * (January 18, 2019)
5  *
6  * \brief
7  * Class quotation (text, author…) or maxim (text, nation…).
8  *
9  * Piece of OPiQuotations.
10  * https://bitbucket.org/OPiMedia/opiquotations
11  *
12  * GPLv3 --- Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019 Olivier Pirson
13  * http://www.opimedia.be/
14  *
15  * @package OPiQuotations
16  */
17 namespace OPiQuotations;
18 
19 
20 /**
21  * \brief
22  * Class quotation (text, author…) or maxim (text, nation…).
23  */
24 class OPiQuotation {
25  /**
26  * \brief
27  * Construct a quotation/maxim.
28  *
29  * See to_html().
30  *
31  * @param int $id Id of the quotation (must be > 0)
32  * @param string $text Text of the quotation (should not contain \htmlonly'@@@#'\endhtmlonly and \htmlonly'#@@@'\endhtmlonly)
33  * @param bool $is_maxim true if maxim (of a possibly nation), false if quotation (of an possibly author)
34  * @param bool $is_marked true if marked quotation/maxim, else false
35  * @param null|string $translation Possibly translation of the text (should not contain \htmlonly'@@@#'\endhtmlonly and \htmlonly'#@@@'\endhtmlonly)
36  * @param null|string $subject Possibly subject
37  * @param null|string $nation_author Possibly nation if maxim, else possibly author
38  * @param null|string $work Possibly work if quotation (must be null if $is_maxim)
39  * @param null|string $text_lang Language of text
40  * @param null|Selection[] $selections List of Selection
41  * @param bool $is_misattributed true if the quotation/maxim is misattributed to its author, else false
42  */
43  public function __construct($id, $text,
44  $is_maxim=false,
45  $is_marked=false,
46  $translation=null,
47  $subject=null, $nation_author=null, $work=null,
48  $text_lang=null,
49  $selections=null,
50  $is_misattributed=false) {
51  #DEBUG
52  assert('is_int($id)');
53  assert('$id > 0');
54  assert('is_string($text)');
55  assert('is_bool($is_maxim)');
56  assert('is_bool($is_marked)');
57  assert('($translation === null) || is_string($translation)');
58  assert('($subject === null) || is_string($subject)');
59  assert('($nation_author === null) || is_string($nation_author)');
60  assert('($work === null) || is_string($work)');
61  assert('($text_lang === null) || is_string($text_lang)');
62  assert('($selections === null) || is_array($selections)');
63  assert('is_bool($is_misattributed)');
64  #DEBUG_END
65 
66  $this->id = $id;
67  $this->text = $text;
68  $this->text_lang = $text_lang;
69  $this->maxim = $is_maxim;
70  $this->marked = $is_marked;
71  $this->translation = $translation;
72  $this->subject = $subject;
73  $this->misattributed = $is_misattributed;
74 
75  if ($is_maxim) {
76  #DEBUG
77  assert('$work === null');
78  #DEBUG_END
79 
80  $this->nation = $nation_author;
81  }
82  else {
83  $this->author = $nation_author;
84  $this->work = $work;
85  }
86 
87  $this->selections = ($selections === null
88  ? array()
89  : $selections);
90  }
91 
92 
93 
94  /**
95  * \brief
96  * Return $s with each '-'
97  * replaced by '<span class"Comme-fix">-</span>'
98  * to workaround bug with this character in the Comme-Light.ttf font.
99  *
100  * See "Bug in dash character Comme-Light.ttf (Vernon Adams)
101  * font with recent browsers"
102  * http://www.opimedia.be/DS/webdev/bugs-list/Bug-in-dash-character-of-Comme-Light-ttf-Vernon-Adams-font-with-recent-browsers/
103  *
104  * @param string $s
105  *
106  * @return string
107  */
108  private static function _add_comme_fix($s) {
109  #DEBUG
110  assert('is_string($s)');
111  #DEBUG_END
112 
113  // Cut on HTML tags
114  $a = preg_split('/(<.*?()>)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE); // (added () in regexp to avoid bug in PHPstripDEBUG)
115 
116  // Replace each '-' not in tag
117  foreach ($a as &$s) {
118  if (!preg_match('/(<.*?()>)/', $s)) { // (added () in regexp to avoid bug in PHPstripDEBUG)
119  $s = preg_replace('/\-/',
120  '<span class="Comme-fix">-</span>', $s);
121  }
122  }
123 
124  return implode($a);
125  }
126 
127 
128 
129  /**
130  * \brief
131  * Return $s with an adding '#' character before the last word.
132  *
133  * @param string $s
134  *
135  * @return string
136  */
137  private static function _add_hashtag($s) {
138  #DEBUG
139  assert('is_string($s)');
140  #DEBUG_END
141 
142  $a = explode(' ', $s);
143 
144  #DEBUG
145  assert('!empty($a)');
146  #DEBUG_END
147 
148  $a[count($a) - 1] = '#'.$a[count($a) - 1];
149 
150  return implode(' ', $a);
151  }
152 
153 
154  /**
155  * \brief
156  * Return $s formatted in HTML to be displayed.
157  *
158  * - HTML tags &lt;b>, &lt;c>, &lt;i>, &lt;sub>, &lt;sup> are used (the other tags are displayed as it is).
159  * - The special character ¨ (diaeresis, U+00A8) is used to justify to the right.
160  * - Beginning (at the beginning of the line and after an end of line) double space is used to indentation.
161  *
162  * @param string $s (should not contain \htmlonly'@@@#'\endhtmlonly and \htmlonly'#@@@'\endhtmlonly)
163  *
164  * @return string
165  */
166  private static function _format_correct_html($s) {
167  #DEBUG
168  assert('is_string($s)');
169  # assert('preg_match(\'/ $/\', $s) === 0'); // check if no final space
170  #DEBUG_END
171 
172  $s = preg_replace('/<(b|c|i|sub|sup|\/b|\/c|\/i|\/sub|\/sup)>/', '@@@#$1#@@@', $s); // protect some HTML tags
173 
174  $s = htmlspecialchars($s); // escape special HTLM characters
175 
176  // Restore HTML tags previously protected
177  $s = preg_replace('/@@@#(b|i|sub|sup|\/b|\/i|\/sub|\/sup)#@@@/', '<$1>', $s);
178  $s = preg_replace('/@@@#c#@@@/', '<span class="block-center">', $s);
179  $s = preg_replace('/@@@#c#@@@/', '<span class="block-center">', $s);
180  $s = preg_replace('/@@@#\/c#@@@\n?/', '</span>', $s);
181 
182  // Special character ¨ to justify this line to the right
183  $s = preg_replace('/¨(.+)\n?/', '<span class="block-right">$1</span>', $s);
184 
185  // Non-breaking space with after « and before », ! and ?
186  $s = preg_replace('/« /', '«&nbsp;', $s);
187  $s = preg_replace('/ (»|!|\?)/', '&nbsp;$1', $s);
188 
189  // Non-breaking thin space before : and ;
190  $s = preg_replace('/ (:|;)/', '<span class="nowrap">&thinsp;$1</span>', $s);
191 
192  // Spaces
193  $s = preg_replace('/(^|\n) /', '$1&emsp;&emsp;', $s);
194  $s = preg_replace('/ /', '&nbsp;&nbsp;', $s);
195  $s = preg_replace('/(^|\n) /', '&nbsp;', $s);
196 
197  // HTML tag to newline
198  $s = preg_replace('/\n/', '<br>', $s);
199 
200  #DEBUG
201  # assert('preg_match(\'/¨/\', $s) === 0'); // check if no character ¨
202  # assert('preg_match(\'/\\\'/\', $s) === 0'); // check if no character ' (use ’ instead)
203  #DEBUG_END
204 
205  return $s;
206  }
207 
208 
209  /**
210  * \brief
211  * If $search !== null
212  * then each occurence of $search is surrounded by '&lt;mark>' and '&lt;/mark>'.
213  *
214  * @param string $s
215  * @param null|string $search
216  *
217  * @return string
218  */
219  private static function _highlight_html($s, $search=null) {
220  #DEBUG
221  assert('is_string($s)');
222  assert('($search === null) || is_string($search)');
223  #DEBUG_END
224 
225  if ($search !== null && $search !== '') {
226  $search = preg_replace('/\n/', '<br>', $search); // split on HTML tags
227 
228  $pieces = preg_split('/(<.+?()>|&.+?;)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE); // (added () in regexp to avoid bug in PHPstripDEBUG)
229  foreach ($pieces as &$piece) {
230  if ((preg_match('/^<.+>$/', $piece) !== 1) && (preg_match('/^&.+;$/', $piece)) !== 1) { // it's NOT a HTML tag or entity
231  $piece = preg_replace('/('.preg_quote($search, '/').')/i', '<mark>$1</mark>', $piece);
232  }
233  }
234 
235  return implode($pieces);
236  }
237  else {
238  return $s;
239  }
240  }
241 
242 
243  /**
244  * \brief
245  * Return a translation of the message in the language.
246  *
247  * If don't exist in the dictionary,
248  * then return $message.
249  *
250  * @param string $message
251  * @param string $language
252  *
253  * @return string
254  */
255  private static function _translate_message($message, $language) {
256  #DEBUG
257  assert('is_string($message)');
258  assert('is_string($language)');
259  #DEBUG_END
260 
261  $DICTIONARY = array('Language:' => array('fr' => 'Langue&thinsp;:'),
262  'Share' => array('fr' => 'Partager'),
263  'Associate link:' => array('fr' => 'Lien associé :'),
264 
265  'maxim' => array('fr' => 'maxime'),
266 
267  'Misattributed to' => array('fr' => 'Attribuée de façon erronée à'),
268 
269  'en' => array('en' => 'English',
270  'fr' => 'anglais'),
271  'de' => array('en' => 'German',
272  'fr' => 'allemand'),
273  'el' => array('en' => 'Greek',
274  'fr' => 'grec'),
275  'es' => array('en' => 'Spanish',
276  'fr' => 'espagnol'),
277  'fr' => array('en' => 'French',
278  'fr' => 'français'),
279  'la' => array('en' => 'Latin',
280  'fr' => 'latin'),
281  'nl' => array('en' => 'Dutch',
282  'fr' => 'néerlandais'),
283  );
284 
285  if (empty($DICTIONARY[$message])) {
286  return $message;
287  }
288 
289  $translations = $DICTIONARY[$message];
290 
291  return (empty($translations[$language])
292  ? $message
293  : $translations[$language]);
294  }
295 
296 
297 
298  /**
299  * \brief
300  * Return null or the author of the quotation.
301  *
302  * @return null|string
303  */
304  public function author() {
305  return ($this->maxim
306  ? null
307  : $this->author);
308  }
309 
310 
311  /**
312  * \brief
313  * Return the id of the quotation/maxim.
314  *
315  * @return id > 0
316  */
317  public function id() {
318  return $this->id;
319  }
320 
321 
322  /**
323  * \brief
324  * Return true if is a maxim (of a possibly nation),
325  * false if is a quotation (of a possibly author).
326  *
327  * @return bool
328  */
329  public function is_maxim() {
330  return $this->maxim;
331  }
332 
333 
334  /**
335  * \brief
336  * Return true if is a marked quotation/maxim,
337  * else false.
338  *
339  * @return bool
340  */
341  public function is_marked() {
342  return $this->marked;
343  }
344 
345 
346  /**
347  * \brief
348  * Return true if is the quotation/maxim is misattributed to its author,
349  * else false.
350  *
351  * @return bool
352  */
353  public function is_misattributed() {
354  return $this->misattributed;
355  }
356 
357 
358  /**
359  * \brief
360  * Return null or the nation of the maxim.
361  *
362  * @return null|string
363  */
364  public function nation() {
365  return ($this->maxim
366  ? $this->nation
367  : null);
368  }
369 
370 
371  /**
372  * \brief
373  * Return the list of Selection.
374  *
375  * @return Selection[]
376  */
377  public function selections() {
378  return $this->selections;
379  }
380 
381 
382  /**
383  * \brief
384  * Add a Selection to the list.
385  *
386  * @param Selection $selection
387  */
388  public function selections_add($selection) {
389  #DEBUG
390  assert($selection instanceof Selection);
391  #DEBUG_END
392 
393  $this->selections[] = $selection;
394  }
395 
396 
397  /**
398  * \brief
399  * Return null or the subject of the quotation/maxim.
400  *
401  * @return null|string
402  */
403  public function subject() {
404  return $this->subject;
405  }
406 
407 
408  /**
409  * \brief
410  * Return the text of the quotation/maxim.
411  *
412  * @return string
413  */
414  public function text() {
415  return $this->text;
416  }
417 
418 
419  /**
420  * \brief
421  * Return null or the language of the text quotation/maxim.
422  *
423  * @return null|string
424  */
425  public function text_lang() {
426  return $this->text_lang;
427  }
428 
429 
430  /**
431  * \brief
432  * Return the complete quotation/maxim in a HTML format.
433  *
434  * Layout
435  * - for a quotation:
436  *\code
437 id one_OPiQuotation_link Share Selections
438  subject (mark)
439 text | translation
440  author
441  work
442  *\endcode
443  *
444  * - for a maxim:
445  *\code
446 id one_OPiQuotation_link Share Selections
447  subject (mark)
448 text | translation
449  nation
450  *\endcode
451  *
452  * In text and translation:
453  * - HTML tags &lt;b>, &lt;c>, &lt;i>, &lt;sub>, &lt;sup> are used (the other tags are displayed as it is).
454  * - The special character ¨ (diaeresis, U+00A8) is used to justify to the right.
455  * - Beginning (at the beginning of the line and after an end of line) double space is used to indentation.
456  *
457  * If $search !== null
458  * then each occurence of $search founded is surrounded by '&lt;mark>' and '&lt;/mark>'.
459  *
460  * If $add_link
461  * then add links to id, subject, nation, author and work.
462  *
463  * If $link_target
464  * then add a target attribut to each link.
465  *
466  * The subject is surrounded by $subject_tag.
467  *
468  * @param null|string $search
469  * @param bool $add_link
470  * @param null|string $link_target
471  * @param string $subject_tag
472  * @param string $one_OPiQuotation_link
473  * @param string $language
474  *
475  * @return string
476  */
477  public function to_html($search=null, $add_link=true, $link_target=null,
478  $subject_tag='h2', $one_OPiQuotation_link='une-OPiCitation.php',
479  $language='en') {
480  #DEBUG
481  assert('($search === null) || is_string($search)');
482  assert('is_bool($add_link)');
483  assert('($link_target === null) || is_string($link_target)');
484  assert('is_string($subject_tag)');
485  assert('is_string($one_OPiQuotation_link)');
486  assert('is_string($language)');
487  #DEBUG_END
488 
489  $html_link_target = ($link_target
490  ? ' target="'.$link_target.'"'
491  : '');
492 
493  // Maxim or quotation
494  $is_marked = ($this->is_marked()
495  ? ' marked'
496  : '');
497 
498  $a = array($this->is_maxim()
499  ? '<section id="maxim-'.$this->id().'" class="maxim'.$is_marked.'">'
500  : '<section id="quotation-'.$this->id().'" class="quotation'.$is_marked.'">');
501 
502  unset($is_marked);
503 
504 
505  // Header
506  $a[] = ' <header>';
507 
508  // Marked ?
509  if ($this->is_marked()) {
510  $a[] = ' <aside class="mark"></aside>';
511  }
512 
513  // Id
514  $url = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
515 
516  // Collates all pieces
517  $a[] = ' <nav class="id">
518 '.($add_link
519  ? ' <a href="./?id='.$this->id().'"'.$html_link_target.'>'.$this->id().'</a>
520  <a rel="nofollow" class="one-OPiQuotation" href="'.$one_OPiQuotation_link.'?id='.$this->id().'" target="_blank">&#10102;</a>
521  <div class="sharing"><span onclick="sharingOpen(this, '.$this->id().'); return false;">'.OPiQuotation::_translate_message('Share', $language).'</span></div>'
522  .Selection::_selections_to_html_ul($this->selections(), $link_target)
523  : $this->id()).'
524  </nav>';
525 
526  if ($this->subject() !== null) { // subject
527  $html = OPiQuotation::_highlight_html(htmlspecialchars($this->subject()), $search);
528  $a[] = ' <'.$subject_tag.' class="subject">'
529  .($add_link
530  ? '<a href="./?subject='.rawurlencode($this->subject()).'"'.$html_link_target.'>'.$html.'</a>'
531  : $html).'</'.$subject_tag.'>';
532  }
533  else {
534  $a[] = ' <'.$subject_tag.' class="no-display">'
535  .($this->is_maxim()
536  ? 'maxim'
537  : 'quotation').'</'.$subject_tag.'>';
538  }
539 
540  $a[] = ' </header>';
541 
542 
543  // Text and translation
544  $text_lang = ($this->text_lang() === null
545  ? ''
546  : ' lang="'.$this->text_lang().'"');
547  $text_lang_title = ($this->text_lang() === null
548  ? ''
549  : ' title="'.OPiQuotation::_translate_message('Language:', $language).' '.OPiQuotation::_translate_message($this->text_lang(), $language).'"');
550 
551  if ($this->translation() === null) { // text
552  $a[] = ' <div class="text"'.$text_lang_title.'><cite'.$text_lang.'>'.OPiQuotation::_highlight_html(OPiQuotation::_format_correct_html($this->text()), $search).'</cite></div>';
553  }
554  else { // text, translation
555  $a[] = ' <div class="text_translation">
556  <div class="text"'.$text_lang_title.'><cite'.$text_lang.'>'.OPiQuotation::_highlight_html(OPiQuotation::_format_correct_html($this->text()), $search).'</cite></div>
557  <div class="translation"><cite>'.OPiQuotation::_highlight_html(OPiQuotation::_format_correct_html($this->translation()), $search).'</cite></div>
558  </div>';
559  }
560 
561  unset($text_lang);
562  unset($text_lang_title);
563 
564 
565  // Footer
566  $a[] = ' <footer>';
567 
568  if ($this->is_maxim()) { // nation
569  #DEBUG
570  assert('$this->author() === null');
571  assert('$this->work() === null');
572  #DEBUG_END
573 
574  if ($this->nation() !== null) {
575  $html = OPiQuotation::_highlight_html(htmlspecialchars($this->nation()), $search);
576  $a[] = ' <div class="nation">'
577  .($this->is_misattributed()
578  ? '('.OPiQuotation::_translate_message('Misattributed to', $language).') '
579  : '')
580  .($add_link
581  ? '<a href="./?nation='.rawurlencode($this->nation()).'"'.$html_link_target.'>'.OPiQuotation::_translate_message('maxim', $language).' '.$html.'</a>'
582  : OPiQuotation::_translate_message('maxim', $language).' '.$html).'</div>';
583  }
584  }
585  else { // author, work
586  #DEBUG
587  assert('$this->nation() === null');
588  #DEBUG_END
589 
590  if ($this->author() !== null) {
591  $html = OPiQuotation::_highlight_html(htmlspecialchars($this->author()), $search);
592  $a[] = ' <div class="author">'
593  .($this->is_misattributed()
594  ? '('.OPiQuotation::_translate_message('Misattributed to', $language).') '
595  : '')
596  .($add_link
597  ? '<a href="./?author='.rawurlencode($this->author()).'"'.$html_link_target.'>'.$html.'</a>'
598  : $html).'</div>';
599  }
600 
601  if ($this->work() !== null) {
602  $html = OPiQuotation::_highlight_html(htmlspecialchars($this->work()), $search);
603  $a[] = ' <div class="work">'
604  .($add_link
605  ? '<a href="./?work='.rawurlencode($this->work()).'"'.$html_link_target.'>'.$html.'</a>'
606  : $html).'</div>';
607  }
608  }
609 
610  $a[] = ' </footer>';
611  $a[] = '</section>
612 ';
613 
614  return OPiQuotation::_add_comme_fix(implode('
615 ', $a));
616  }
617 
618 
619  /**
620  * \brief
621  * Return the quotation/maxim with its author/nation and work
622  * in text format
623  * (strip HTML tags &lt;b>, &lt;c>, &lt;i>, &lt;sub>, &lt;sup>
624  * and special character ¨ (diaeresis, U+00A8)).
625  *
626  * If $add_hashtags
627  * then add '#' character before the last word of author/nation and work.
628  *
629  * If $url !== ''
630  * then add this URL.
631  *
632  * If $add_selections is not empty
633  * then each add selection URL for each label.
634  *
635  * @param bool $add_hashtags
636  * @param string $language
637  * @param string $url
638  * @param bool $add_subject
639  * @param null|string[] $add_selections
640  *
641  * @return string
642  */
643  public function to_text($add_hashtags=false, $language='en', $url='', $add_subject=false, $add_selections=null) {
644  #DEBUG
645  assert('is_bool($add_hashtags)');
646  assert('is_string($language)');
647  assert('is_string($add_url)');
648  assert('is_bool($add_subject)');
649  assert('($add_selections === null) || is_array($add_selections)');
650  #DEBUG_END
651 
652  $quot = trim($this->text());
653 
654  // Replace <sub> and <sup> HTML tags
655  $quot = preg_replace('/<sub>(.)<\/sub>/', '_$1', $quot);
656  $quot = preg_replace('/<sub>(.+?)<\/sub>/', '_{$1}', $quot);
657  $quot = preg_replace('/<sup>(.)<\/sup>/', '^$1', $quot);
658  $quot = preg_replace('/<sup>(.+?)<\/sup>/', '^{$1}', $quot);
659 
660  $quot = preg_replace('/<(b|c|i|sub|sup|\/b|\/c|\/i|\/sub|\/sup)>/', '', $quot); // strip some HTML tags
661  $quot = preg_replace('/¨/', '', $quot); // strip special character ¨
662 
663  $quot = '“'.$quot.'”';
664 
665  if ($this->translation() !== null) {
666  $translation = trim($this->translation());
667 
668  $translation = preg_replace('/<(b|c|i|sub|sup|\/b|\/c|\/i|\/sub|\/sup)>/', '', $translation); // strip some HTML tags
669  $translation = preg_replace('/¨/', '', $translation); // strip special character ¨
670 
671  $quot .= '
672 ——————————
673 “'.$translation.'”';
674 
675  unset($translation);
676  }
677 
678  $quot .= '
679 ';
680 
681  if ($this->is_maxim()) {
682  if ($this->nation() !== null) { // add nation
683  $nation = $this->nation();
684  if ($add_hashtags) {
685  $nation = OPiQuotation::_add_hashtag($nation);
686  }
687  if ($this->is_misattributed()) {
688  $nation = OPiQuotation::_translate_message('Misattributed to', $language).' '.$nation;
689  }
690  $quot .= '
691 ('.OPiQuotation::_translate_message('maxim', $language).' '.$nation.')';
692  }
693  }
694  else {
695  if ($this->author() !== null) {
696  $author = $this->author();
697  if ($add_hashtags) {
698  $author = OPiQuotation::_add_hashtag($author);
699  }
700  if ($this->is_misattributed()) {
701  $author = OPiQuotation::_translate_message('Misattributed to', $language).' '.$author;
702  }
703  if ($this->work() !== null) { // add author and work
704  $quot .= '
705 ('.$author.'/
706 '.$this->work().')';
707  }
708  else { // add author
709  $quot .= '
710 ('.$author.')';
711  }
712  }
713  else if ($this->work() !== null) { // add work
714  $quot .= '
715 ('.$this->work().')';
716  }
717  }
718 
719  if (!empty($url)) { // add URL
720  $quot .= '
721 '.$url;
722  }
723 
724  if ($add_subject && ($this->subject() !== null)) { // add subject
725  $quot .= '
726 '.($add_hashtags
727  ? '#'
728  : '').$this->subject();
729  }
730 
731  $selections = $this->selections();
732  if (!empty($add_selections) && !empty($selections)) { // add some selections
733  foreach ($add_selections as $label) {
734  foreach ($selections as $selection) {
735  if ($selection->label() === $label) {
736  $quot .= '
737 '.OPiQuotation::_translate_message('Associate link:', $language).' '.$selection->url();
738  }
739  }
740  }
741  }
742 
743  return $quot;
744  }
745 
746 
747  /**
748  * \brief
749  * Return the quotation/maxim with its author/nation and work
750  * in text format to post to Facebook.
751  *
752  * If url !== ''
753  * then add this URL.
754  *
755  * If $add_selections is not empty
756  * then each add selection URL for each label.
757  *
758  * @param string $url
759  * @param string $language
760  * @param null|string[] $add_selections
761  *
762  * @return string
763  */
764  public function to_text_facebook($url='', $language='en', $add_selections=null) {
765  #DEBUG
766  assert('is_string($url)');
767  assert('is_string($language)');
768  #DEBUG_END
769 
770  return $this->to_text(true, $language, $url, true, $add_selections);
771  }
772 
773 
774  /**
775  * \brief
776  * Return the quotation/maxim with its author/nation and work
777  * in short text format to post to Twitter.
778  *
779  * If a cutting is required then reduce contiguous whitespaces.
780  *
781  * Cut the result to not be longer than $max_length characters.
782  *
783  * If url !== null
784  * then add url to the end on a newline.
785  *
786  * If $short_url_length === null
787  * then use the real length of the url,
788  * else assume that the url will be replaced by a short url not be longer than $short_url_length.
789  *
790  * @param null|string $url
791  * @param null|int $short_url_length
792  * @param int $max_length (must be > 0)
793  * @param string $language
794  *
795  * @return string
796  */
797  public function to_text_twitter($url=null, $short_url_length=null, $max_length=279,
798  $language='en') {
799  #DEBUG
800  assert('($url === null) || is_string($url)');
801  assert('($short_url_length === null) || is_int($short_url_length)');
802  assert('($short_url_length === null) || ($short_url_length >= 0)');
803  assert('is_int($max_length)');
804  assert('$max_length > 0');
805  assert('is_string($language)');
806  #DEBUG_END
807 
808  $quot = $this->to_text(true, $language);
809 
810  if ($url !== null) {
811  if ($short_url_length === null) {
812  $short_url_length = mb_strlen($url);
813  }
815 
816  $url = '
817 '.$url;
818  }
819 
820  $text = text_cut($quot, $max_length).$url;
821  $subject = ($this->subject() === null
822  ? ''
823  : '
824 #'.$this->subject());
825 
826  return $text.(mb_strlen($quot) + mb_strlen($subject) <= $max_length
827  ? $subject
828  : '');
829  }
830 
831 
832  /**
833  * \brief
834  * Return null or the translation of the quotation/maxim.
835  *
836  * @return null|string
837  */
838  public function translation() {
839  return $this->translation;
840  }
841 
842 
843  /**
844  * \brief
845  * Return null or the work of the quotation.
846  *
847  * @return null|string
848  */
849  public function work() {
850  return ($this->maxim
851  ? null
852  : $this->work);
853  }
854 
855 
856 
857  /** @var null|string $author
858  * \brief
859  * null or the author of the quotation if is a quotation,
860  * else null.
861  */
862  protected $author;
863 
864  /** @var int $id
865  * \brief
866  * The id of the quotation/maxim (must be > 0).
867  */
868  protected $id;
869 
870  /** @var bool $is_marked
871  * \brief
872  * true if marked quotation/maxim,
873  * else false.
874  */
875  protected $is_marked;
876 
877  /** @var bool $is_maxim
878  * \brief
879  * true if maxim (of a possibly nation),
880  * false if quotation (of an possibly author).
881  */
882  protected $is_maxim;
883 
884  /** @var bool $is_misattributed
885  * \brief
886  * true if the quotation/maxim is misattributed to its author,
887  * else false.
888  */
889  protected $is_misattributed;
890 
891  /** @var null|string $nation
892  * \brief
893  * null or the nation of the maxim if is a maxim,
894  * else null.
895  */
896  protected $nation;
897 
898  /** @var Selection[] $selections
899  * \brief
900  * List of Selection
901  */
902  protected $selections;
903 
904  /** @var null|string $subject
905  * \brief
906  * null or the subject of the quotation/maxim.
907  */
908  protected $subject;
909 
910  /**
911  * @var string $text
912  * \brief
913  * Text of the quotation/maxim.
914  *
915  * Maybe contains some HTML tags (see __construct()).
916  */
917  protected $text;
918 
919  /** @var string $text_lang
920  * \brief
921  * Language of text, in ISO 639-1 code:
922  * https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
923  *
924  * Mainly used to specify language when there is a translation.
925  */
926  protected $text_lang;
927 
928  /**
929  * @var null|string $translation
930  * \brief
931  * null or the translation of the quotation/maxim.
932  *
933  * Maybe contains some HTML tags (see __construct()).
934  */
935  protected $translation;
936 
937  /** @var null|string $work
938  * \brief
939  * null or the work of the quotation if is a quotation,
940  * else null.
941  */
942  protected $work;
943 }
944 
945 
946 
947 /**
948  * \brief
949  * Class selection.
950  *
951  * Used by applications to save quotations already chosen.
952  */
953 class Selection {
954  /**
955  * \brief
956  * Construct a selection.
957  *
958  * If $datetime_utc === null then use the current time.
959  *
960  * See to_html().
961  *
962  * @param string $label
963  * @param null|DateTime $datetime_utc
964  * @param null|string $url
965  */
966  public function __construct($label, $datetime_utc, $url=null) {
967  #DEBUG
968  assert('is_string($label)');
969  assert(($datetime_utc === null) || $datetime_utc instanceof \DateTime);
970  assert('($url === null) || is_string($url)');
971  #DEBUG_END
972 
973  $this->label = $label;
974  $this->datetime_utc = ($datetime_utc === null
975  ? new \DateTime('now', new \DateTimeZone('UTC'))
976  : $datetime_utc);
977 
978  $this->url = $url;
979  }
980 
981 
982 
983  /**
984  * \brief
985  * Return the list of selections in a HTML format,
986  * in a <ul class="selections"> item.
987  *
988  * If $link_target
989  * then add a target attribut to the link.
990  *
991  * @param array(Selection) $selections
992  * @param null|string $link_target
993  *
994  * @return string
995  */
996  public static function _selections_to_html_ul($selections, $link_target=null) {
997  #DEBUG
998  assert('is_array($selections)');
999  assert('($link_target === null) || is_string($link_target)');
1000  #DEBUG_END
1001 
1002  if (count($selections) === 0) {
1003  return '';
1004  }
1005 
1006  $a = [];
1007  foreach ($selections as $selection) {
1008  $a[] = $selection->to_html($link_target);
1009  }
1010 
1011  return '
1012  <ul class="selections">
1013  '.implode('
1014  ', $a).'
1015  </ul>';
1016  }
1017 
1018 
1019 
1020  /**
1021  * \brief
1022  * Return the date/time of the selection.
1023  *
1024  * @return DateTime
1025  */
1026  public function datetime_utc() {
1027  return $this->datetime_utc;
1028  }
1029 
1030 
1031  /**
1032  * \brief
1033  * Return the label
1034  * used to identify an application that already chosen a quotation.
1035  *
1036  * @return string
1037  */
1038  public function label() {
1039  return $this->label;
1040  }
1041 
1042 
1043  /**
1044  * \brief
1045  * Return the selection in a HTML format.
1046  * By default in a <li> item.
1047  *
1048  * If $link_target
1049  * then add a target attribut to the link.
1050  *
1051  * @param null|string $link_target
1052  * @param string $tag
1053  *
1054  * @return string
1055  */
1056  public function to_html($link_target, $tag='li') {
1057  #DEBUG
1058  assert('($link_target === null) || is_string($link_target)');
1059  assert('is_string($tag)');
1060  #DEBUG_END
1061 
1062  $title = htmlspecialchars($this->label());
1063  if ($this->datetime_utc() > new \DateTime('0000-00-00')) {
1064  $title.= ' &mdash; '.htmlspecialchars($this->datetime_utc()->format('Y-m-d'));
1065  }
1066 
1067  $content = (preg_match('/^Web( (\d+))?/', $this->label()) // if 'Web', 'Web 2'...
1068  ? ''
1069  : '&#10102;');
1070 
1071  return '<'.$tag.' class="'.explode(' ', $this->label())[0].'" title="'.$title.'">'
1072  .($this->url() === null
1073  ? '<span>'.$content.'</span>'
1074  : '<a rel="nofollow" href="'.$this->url().'"'
1075  .($link_target
1076  ? ' target="'.$link_target.'"'
1077  : '').'>'.$content.'</a>')
1078  .'</'.$tag.'>';
1079  }
1080 
1081 
1082  /**
1083  * \brief
1084  * Return null or URL to the quotation in the application.
1085  *
1086  * @return null|string
1087  */
1088  public function url() {
1089  return $this->url;
1090  }
1091 
1092 
1093 
1094  /** @var string $label
1095  * \brief
1096  * Label to identify an application that already chosen a quotation.
1097  */
1098  protected $label;
1099 
1100  /** @var DateTime $datetime_utc
1101  * \brief
1102  * date/time of the selection.
1103  */
1104  protected $datetime_utc;
1105 
1106  /** @var null|string $url
1107  * \brief
1108  * null or URL to the quotation in the application.
1109  *
1110  * Like this: https://twitter.com/OPiCitationJour/status/763268655845085184
1111  */
1112  protected $url;
1113 }
1114 
1115 
1116 return TRUE;
1117 
1118 ?>
$author
null or the author of the quotation if is a quotation, else null.
$text
Text of the quotation/maxim.
Class selection.
$work
null or the work of the quotation if is a quotation, else null.
if(!empty($params)) $search
Definition: index.php:175
to_html($search=null, $add_link=true, $link_target=null, $subject_tag='h2', $one_OPiQuotation_link='une-OPiCitation.php', $language='en')
Return the complete quotation/maxim in a HTML format.
if($quot===null) $text
to_text_twitter($url=null, $short_url_length=null, $max_length=279, $language='en')
Return the quotation/maxim with its author/nation and work in short text format to post to Twitter...
$text_lang
Language of text, in ISO 639-1 code: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes.
to_text($add_hashtags=false, $language='en', $url='', $add_subject=false, $add_selections=null)
Return the quotation/maxim with its author/nation and work in text format (strip HTML tags <b>...
selections()
Return the list of Selection.
$datetime_utc
date/time of the selection.
static _format_correct_html($s)
Return $s formatted in HTML to be displayed.
text_cut($text, $max_length, $hellip='…', $reduce=true)
If length of $text <= $max_length characters then return $text, else return $text cutted added of $he...
id()
Return the id of the quotation/maxim.
if($quot===null) $title
$id
The id of the quotation/maxim (must be > 0).
static _selections_to_html_ul($selections, $link_target=null)
Return the list of selections in a HTML format, in a <ul class="selections"> item.
is_maxim()
Return true if is a maxim (of a possibly nation), false if is a quotation (of a possibly author)...
text_lang()
Return null or the language of the text quotation/maxim.
datetime_utc()
Return the date/time of the selection.
$url
Definition: index.php:385
text()
Return the text of the quotation/maxim.
$url
null or URL to the quotation in the application.
$nation
null or the nation of the maxim if is a maxim, else null.
to_html($link_target, $tag='li')
Return the selection in a HTML format. By default in a <li> item.
$subject
null or the subject of the quotation/maxim.
$translation
null or the translation of the quotation/maxim.
is_marked()
Return true if is a marked quotation/maxim, else false.
to_text_facebook($url='', $language='en', $add_selections=null)
Return the quotation/maxim with its author/nation and work in text format to post to Facebook...
$label
Label to identify an application that already chosen a quotation.
static _add_comme_fix($s)
Return $s with each &#39;-&#39; replaced by &#39;<span class"Comme-fix">-</span>&#39; to workaround bug with this cha...
static _add_hashtag($s)
Return $s with an adding &#39;#&#39; character before the last word.
static _translate_message($message, $language)
Return a translation of the message in the language.
$is_marked
true if marked quotation/maxim, else false.
subject()
Return null or the subject of the quotation/maxim.
static _highlight_html($s, $search=null)
If $search !== null then each occurence of $search is surrounded by &#39;<mark>&#39; and &#39;</mark>&#39;.
nation()
Return null or the nation of the maxim.
author()
Return null or the author of the quotation.
is_misattributed()
Return true if is the quotation/maxim is misattributed to its author, else false. ...
selections_add($selection)
Add a Selection to the list.
__construct($id, $text, $is_maxim=false, $is_marked=false, $translation=null, $subject=null, $nation_author=null, $work=null, $text_lang=null, $selections=null, $is_misattributed=false)
Construct a quotation/maxim.
work()
Return null or the work of the quotation.
Class quotation (text, author…) or maxim (text, nation…).
translation()
Return null or the translation of the quotation/maxim.
$is_maxim
true if maxim (of a possibly nation), false if quotation (of an possibly author). ...
__construct($label, $datetime_utc, $url=null)
Construct a selection.
$is_misattributed
true if the quotation/maxim is misattributed to its author, else false.
url()
Return null or URL to the quotation in the application.
label()
Return the label used to identify an application that already chosen a quotation. ...