· 11 years ago · Sep 24, 2015, 04:44 PM
1Index: dev-branches/tic6013-opengraph/db/migrations/174_change_opengraph_data_pk.php
2===================================================================
3--- dev-branches/tic6013-opengraph/db/migrations/174_change_opengraph_data_pk.php (revision 35422)
4+++ dev-branches/tic6013-opengraph/db/migrations/174_change_opengraph_data_pk.php (revision 35422)
5@@ -0,0 +1,33 @@
6+<?php
7+/**
8+ * Add a numeric id column to table "opengraphdata" in order to avoid problems
9+ * with innodb and to reduce key size.
10+ *
11+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
12+ * @license GPL2 or any later version
13+ */
14+class ChangeOpengraphDataPk extends Migration
15+{
16+ public function up()
17+ {
18+ $query = "ALTER TABLE `opengraphdata`
19+ DROP PRIMARY KEY,
20+ ADD COLUMN `opengraph_id` INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST,
21+ ADD UNIQUE KEY `url` (`url`(512))";
22+ DBManager::get()->exec($query);
23+
24+ SimpleORMap::expireTableScheme();
25+ }
26+
27+ public function down()
28+ {
29+ $query = "ALTER TABLE `opengraphdata`
30+ DROP PRIMARY KEY,
31+ DROP INDEX `url`,
32+ DROP COLUMN `opengraph_id`,
33+ ADD PRIMARY KEY (`url`)";
34+ DBManager::get()->exec($query);
35+
36+ SimpleORMap::expireTableScheme();
37+ }
38+}
39Index: dev-branches/tic6013-opengraph/lib/classes/FormattedContent.php
40===================================================================
41--- dev-branches/tic6013-opengraph/lib/classes/FormattedContent.php (revision 35422)
42+++ dev-branches/tic6013-opengraph/lib/classes/FormattedContent.php (revision 35422)
43@@ -0,0 +1,71 @@
44+<?php
45+use Studip\Markup;
46+
47+/**
48+ * Storage for formatted content
49+ *
50+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
51+ * @license GPL2 or any later version
52+ * @since Stud.IP 3.4
53+ */
54+class FormattedContent
55+{
56+ protected $format;
57+ protected $formatted_content = null;
58+
59+ /**
60+ * Constructs the object for the given content (with the given format).
61+ * If no format is provided, the default StudipFormat will be used.
62+ *
63+ * @param String $content Content to format
64+ * @param mixed $format Used format (optional, defaults to StudipFormat)
65+ */
66+ public function __construct($content, StudipFormat $format = null)
67+ {
68+ $this->format = $format ?: new StudipFormat;
69+
70+ $formatted = Markup::apply($this->format, $content, false);
71+ $wrapped = sprintf(FORMATTED_CONTENT_WRAPPER, $formatted);
72+
73+ $this->formatted_content = $wrapped;
74+ }
75+
76+ /**
77+ * Returns the formatted content (optionally with the opengraph data
78+ * included).
79+ *
80+ * @param bool $include_open_graph Append the rendered opengraph data
81+ * (optional, defaults to false)
82+ * @return String containg the formatted content as html
83+ */
84+ public function getContent($include_open_graph = false)
85+ {
86+ $result = $this->formatted_content;
87+ if ($include_open_graph) {
88+ $result .= $this->getOpenGraphURLCollection()->render();
89+ }
90+ return $result;
91+ }
92+
93+ /**
94+ * Return the detected opengraph urls as a collection.
95+ *
96+ * @return OpenGraphURLCollection Collected opengraph urls
97+ */
98+ public function getOpenGraphURLCollection()
99+ {
100+ return $this->format->getOpenGraphCollection();
101+ }
102+
103+ /**
104+ * Converts the object to a string by returning the formatted content.
105+ * This will be used a lot since formatReady() is usually expected to
106+ * return a string.
107+ *
108+ * @return String containing the formatted content as html
109+ */
110+ public function __toString()
111+ {
112+ return $this->getContent();
113+ }
114+}
115Index: dev-branches/tic6013-opengraph/lib/classes/StudipFormat.php
116===================================================================
117--- trunk/lib/classes/StudipFormat.php (revision 35413)
118+++ dev-branches/tic6013-opengraph/lib/classes/StudipFormat.php (revision 35422)
119@@ -292,4 +292,6 @@
120 }
121
122+ private $opengraph_collection;
123+
124 /**
125 * Initializes a new StudipFormat instance.
126@@ -298,4 +300,33 @@
127 {
128 parent::__construct(self::getStudipMarkups());
129+
130+ // StudipFormat::markupLinks stores OpenGraph media preview URLs
131+ // Blubber and Forum plugins add media previews after formatReady
132+ // returns
133+ $this->opengraph_collection = new OpenGraphURLCollection();
134+ }
135+
136+ /**
137+ * Add an url to the opengraph collection. The url will only be added
138+ * if it exists does not yet exists in the collection.
139+ *
140+ * @param String $url URL to add.
141+ */
142+ public function addOpenGraphURL($url)
143+ {
144+ $og = OpenGraphURL::fromURL($url);
145+ if ($og && !$this->opengraph_collection->find($og->id)) {
146+ $this->opengraph_collection[] = $og;
147+ }
148+ }
149+
150+ /**
151+ * Returns the collected opengraph urls.
152+ *
153+ * @return OpenGraphURLCollection Collection of opengraph urls
154+ */
155+ public function getOpenGraphCollection()
156+ {
157+ return $this->opengraph_collection;
158 }
159
160@@ -626,16 +657,14 @@
161 protected static function markupLinks($markup, $matches)
162 {
163- if ($markup->isInsideOf('htmlAnchor')
164- || $markup->isInsideOf('htmlImg')
165- ) {
166+ if ($markup->isInsideOf('htmlAnchor') || $markup->isInsideOf('htmlImg')) {
167 return $matches[0];
168 }
169
170- $url = $matches[2];
171- $title = $matches[1] ? $matches[1] : $url;
172+ $url = $matches[2];
173+ $title = $matches[1] ?: $url;
174
175 $intern = isLinkIntern($url);
176- if (!$intern) {
177- OpenGraphURL::$tempURLStorage[] = $url;
178+ if (!$intern && Config::get()->OPENGRAPH_ENABLE && method_exists($markup, 'addOpenGraphURL')) {
179+ $markup->addOpenGraphURL($url);
180 }
181
182@@ -643,11 +672,11 @@
183
184 $linkmarkup = clone $markup;
185- $linkmarkup->removeMarkup("links");
186- $linkmarkup->removeMarkup("wiki-links");
187+ $linkmarkup->removeMarkup('links');
188+ $linkmarkup->removeMarkup('wiki-links');
189
190 return sprintf('<a class="%s" href="%s"%s>%s</a>',
191- $intern ? "link-intern" : "link-extern",
192+ $intern ? 'link-intern' : 'link-extern',
193 $url,
194- $intern ? "" : ' target="_blank"',
195+ $intern ? '' : ' target="_blank"',
196 $linkmarkup->format($title)
197 );
198Index: dev-branches/tic6013-opengraph/lib/classes/StudipTransformFormat.php
199===================================================================
200--- trunk/lib/classes/StudipTransformFormat.php (revision 35413)
201+++ dev-branches/tic6013-opengraph/lib/classes/StudipTransformFormat.php (revision 35422)
202@@ -111,12 +111,6 @@
203 $url = $matches[2];
204 $intern = isLinkIntern($url);
205- $ogurl = new OpenGraphURL($url);
206- if (!$intern && ($ogurl->isNew() || $ogurl['last_update'] < time() - 86400)) {
207- $ogurl->fetch();
208- $ogurl['last_update'] = time();
209- $ogurl->store();
210- } elseif(!$ogurl->isNew()) {
211- $ogurl['chdate'] = time();
212- $ogurl->store();
213+ if (!$intern) {
214+ OpenGraphURL::fromURL($url)->store();
215 }
216 return $matches[0];
217Index: dev-branches/tic6013-opengraph/lib/models/OpenGraphURL.class.php
218===================================================================
219--- trunk/lib/models/OpenGraphURL.class.php (revision 35413)
220+++ dev-branches/tic6013-opengraph/lib/models/OpenGraphURL.class.php (revision 35422)
221@@ -25,8 +25,13 @@
222 * @property string mkdate database column
223 */
224-class OpenGraphURL extends SimpleORMap {
225-
226- static public $tempURLStorage = array(); //place to store opengraph-urls from a text.
227-
228+class OpenGraphURL extends SimpleORMap
229+{
230+ const EXPIRES_DURATION = 86400; // = 24 * 60 * 60
231+
232+ /**
233+ * Configures this model.
234+ *
235+ * @param Array $config Configuration array
236+ */
237 protected static function configure($config = array())
238 {
239@@ -35,4 +40,62 @@
240 $config['default_values']['data'] = '';
241 parent::configure($config);
242+ }
243+
244+ /**
245+ * Create an instance of this model given url. Differs from findOneByURL
246+ * insofar that it will return a new object with the given url set
247+ * instead of null.
248+ *
249+ * @param String $url URL to find
250+ * @return OpenGraphURL Either existing instance or a new instance for
251+ * the given url
252+ */
253+ public static function fromURL($url)
254+ {
255+ $og = self::findOneByUrl($url);
256+ if (!$og) {
257+ $og = new self();
258+ $og->url = $url;
259+ }
260+ return $og;
261+ }
262+
263+ /**
264+ * Constructor of the object. Provides a fallback if a url is passed
265+ * instead of the usually expected numeric id in order to not break
266+ * backward compatibility.
267+ * But this constructor will fail miserably if a url is passed that
268+ * is not in the database. This was chosen by design to encourage the
269+ * correct use of an id.
270+ *
271+ * @param mixed $id Numeric id, existing url or null
272+ */
273+ public function __construct($id = null)
274+ {
275+ // Try to find matching id when an url is passed instead of an id.
276+ // This is to ensure that no legacy code will immediately break.
277+ if ($id !== null && !ctype_digit($id)) {
278+ $temp = self::findOneByUrl($id);
279+ if ($temp) {
280+ $id = $temp->id;
281+ }
282+ }
283+ parent::__construct($id);
284+ }
285+
286+ /**
287+ * Stores the object and fetches the opengraph information when either
288+ * the object is new or outdated.
289+ *
290+ * @return int Number of updated records
291+ */
292+ public function store()
293+ {
294+ if ($this->isNew() || $this->last_update < time() - self::EXPIRES_DURATION) {
295+ $this->fetch();
296+ $this->last_update = time();
297+ }
298+
299+ return parent::store();
300 }
301
302@@ -44,6 +107,7 @@
303 * indicates that the site is no opengraph node at all.
304 */
305- public function fetch() {
306- if (!get_config("OPENGRAPH_ENABLE")) {
307+ public function fetch()
308+ {
309+ if (!get_config('OPENGRAPH_ENABLE')) {
310 return;
311 }
312@@ -53,5 +117,5 @@
313 $currentEncoding = $match[0];
314 } else {
315- $currentEncoding = "ISO-8859-1";
316+ $currentEncoding = 'ISO-8859-1';
317 }
318
319@@ -77,11 +141,12 @@
320 foreach ($metatags as $tag) {
321 $key = false;
322- if ($tag->hasAttribute('property') &&
323- strpos($tag->getAttribute('property'), 'og:') === 0) {
324+ if ($tag->hasAttribute('property')
325+ && strpos($tag->getAttribute('property'), 'og:') === 0)
326+ {
327 $key = strtolower(substr($tag->getAttribute('property'), 3));
328 }
329- if (!$key &&
330- $tag->hasAttribute('name') &&
331- strpos($tag->getAttribute('name'), 'og:') === 0) {
332+ if (!$key && $tag->hasAttribute('name')
333+ && strpos($tag->getAttribute('name'), 'og:') === 0)
334+ {
335 $key = strtolower(substr($tag->getAttribute('name'), 3));
336 }
337@@ -107,5 +172,6 @@
338 foreach ($metatags as $tag) {
339 if (stripos($tag->getAttribute('name'), "description") !== false
340- || stripos($tag->getAttribute('property'), "description") !== false) {
341+ || stripos($tag->getAttribute('property'), "description") !== false)
342+ {
343 $this['description'] = studip_utf8decode($tag->getAttribute('content'));
344 }
345@@ -120,12 +186,14 @@
346 * Renders a small box with the information of the opengraph url. Used in
347 * blubber and in the forum.
348- * @return string : html output of the box.
349- */
350- public function render() {
351- if (!get_config("OPENGRAPH_ENABLE") || !$this->getValue('is_opengraph')) {
352- return "";
353- }
354- $template = $GLOBALS['template_factory']->open("shared/opengraphinfo_wide.php");
355- $template->set_attribute('og', $this);
356+ *
357+ * @return string html output of the box.
358+ */
359+ public function render()
360+ {
361+ if (!get_config('OPENGRAPH_ENABLE') || !$this->getValue('is_opengraph')) {
362+ return '';
363+ }
364+ $template = $GLOBALS['template_factory']->open('shared/opengraphinfo_wide.php');
365+ $template->og = $this;
366 return $template->render();
367 }
368@@ -135,8 +203,10 @@
369 * Each array-entry is an array itself with the url as first parameter and the
370 * content-type (important for <audio/> tags) as the second.
371+ *
372 * @return array(array($url, $content_type), ...)
373 */
374- public function getAudioFiles() {
375- return $this->getMediaFiles("audio");
376+ public function getAudioFiles()
377+ {
378+ return $this->getMediaFiles('audio');
379 }
380
381@@ -145,8 +215,10 @@
382 * Each array-entry is an array itself with the url as first parameter and the
383 * content-type (important for <video/> tags) as the second.
384+ *
385 * @return array(array($url, $content_type), ...)
386 */
387- public function getVideoFiles() {
388- return $this->getMediaFiles("video");
389+ public function getVideoFiles()
390+ {
391+ return $this->getMediaFiles('video');
392 }
393
394@@ -155,8 +227,10 @@
395 * Each array-entry is an array itself with the url as first parameter and the
396 * content-type (important for <audio/> or <video/> tags) as the second.
397- * @param string $type: "audio" or "video"
398+ *
399+ * @param string $type "audio" or "video"
400 * @return array(array($url, $content_type), ...)
401 */
402- protected function getMediaFiles($type) {
403+ protected function getMediaFiles($type)
404+ {
405 $files = array();
406 $media = array();
407Index: dev-branches/tic6013-opengraph/lib/models/OpenGraphURLCollection.class.php
408===================================================================
409--- dev-branches/tic6013-opengraph/lib/models/OpenGraphURLCollection.class.php (revision 35422)
410+++ dev-branches/tic6013-opengraph/lib/models/OpenGraphURLCollection.class.php (revision 35422)
411@@ -0,0 +1,53 @@
412+<?php
413+/**
414+ * Specialized version of SimpleORMapCollection that accepts only
415+ * OpenGraphURL objects and provides a method that renders the collection
416+ * to html.
417+ *
418+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
419+ * @license GPL2 or any later version
420+ */
421+class OpenGraphURLCollection extends SimpleORMapCollection
422+{
423+ /**
424+ * Returns the class name of the object this collection accepts.
425+ *
426+ * @return String containing the provided class name 'OpenGraphURL'
427+ */
428+ public function getClassName()
429+ {
430+ return 'OpenGraphURL';
431+ }
432+
433+ /**
434+ * Renders the collection to html. The collection is usually wrapped in
435+ * a wrapper element but in some edge cases you might want to choose not
436+ * to do so. This is enabled by the only parameter this method accepts.
437+ *
438+ * Note: I advice you not to exclude the wrapper. The javascript that
439+ * handles the collection will fail!
440+ *
441+ * @param bool $with_wrapper Should the collection be wrapped in a wrapper
442+ * element (optional, defaults to true)
443+ * @return String containing the rendered collection as a html chunk
444+ */
445+ public function render($with_wrapper = true)
446+ {
447+ if (!Config::Get()->OPENGRAPH_ENABLE || count($this) === 0) {
448+ return '';
449+ }
450+
451+ $rendered_urls = $this->sendMessage('render');
452+ $rendered_urls = array_filter($rendered_urls);
453+
454+ if ($with_wrapper) {
455+ $template = $GLOBALS['template_factory']->open('shared/opengraph-container.php');
456+ $template->urls = $rendered_urls;
457+ $result = $template->render();
458+ } else {
459+ $result = implode("\n", $rendered_urls);
460+ }
461+
462+ return $result;
463+ }
464+}
465Index: dev-branches/tic6013-opengraph/lib/visual.inc.php
466===================================================================
467--- trunk/lib/visual.inc.php (revision 35413)
468+++ dev-branches/tic6013-opengraph/lib/visual.inc.php (revision 35422)
469@@ -267,14 +267,16 @@
470 * @param boolean $wiki (deprecated, has no effect)
471 * @param string $show_comments (deprecated, has no effect)
472- * @return string HTML code computed by applying markup-rules.
473+ * @return FormattedContent Object containing the HTML code computed by
474+ * applying markup-rules (will convert itself to
475+ * string if neccessary).
476 */
477 // TODO remove unused function arguments
478-function formatReady($text, $trim=TRUE, $extern=FALSE, $wiki=FALSE, $show_comments='icon'){
479- // StudipFormat::markupLinks stores OpenGraph media preview URLs
480- // Blubber and Forum plugins add media previews after formatReady returns
481- OpenGraphURL::$tempURLStorage = array();
482-
483- return sprintf(FORMATTED_CONTENT_WRAPPER,
484- Markup::apply(new StudipFormat(), $text, $trim));
485+function formatReady($text, $trim=TRUE, $extern=FALSE, $wiki=FALSE, $show_comments='icon')
486+{
487+ if ($trim) {
488+ $text = trim($text);
489+ }
490+
491+ return new FormattedContent($text);
492 }
493
494Index: dev-branches/tic6013-opengraph/public/assets/javascripts/application.js
495===================================================================
496--- trunk/public/assets/javascripts/application.js (revision 35413)
497+++ dev-branches/tic6013-opengraph/public/assets/javascripts/application.js (revision 35422)
498@@ -394,2 +394,44 @@
499 }
500 })(window.print);
501+
502+// OpenGraph
503+$(document).on('dialog-update ready ajaxComplete', function () {
504+ $('.opengraph-area:not(.handled)').each(function () {
505+ var items = $('.opengraph', this),
506+ switcher;
507+ if (items.length > 1) {
508+ items.filter(':gt(0)').addClass('hidden');
509+
510+ switcher = $('<ul class="switcher">');
511+ $('<li><button class="switch-left" disabled><</button></li>').appendTo(switcher);
512+ $('<li><button class="switch-right">></button></li>').appendTo(switcher);
513+ switcher.prependTo(this);
514+ }
515+
516+ $(this).addClass('handled');
517+ });
518+}).on('click', '.opengraph-area .switcher button', function (event) {
519+ var direction = $(this).is('.switch-left') ? 'left' : 'right',
520+ current = $(this).closest('.opengraph-area').find('.opengraph:visible'),
521+ switcher = $(this).closest('.switcher'),
522+ buttons = {left: $('.switch-left', switcher),
523+ right: $('.switch-right', switcher)};
524+
525+ if (direction === 'left') {
526+ current = current.addClass('hidden').prev().removeClass('hidden');
527+ buttons.left.attr('disabled', current.prev('.opengraph').length === 0);
528+ buttons.right.attr('disabled', false);
529+ } else {
530+ current = current.addClass('hidden').next().removeClass('hidden');
531+ buttons.left.attr('disabled', false);
532+ buttons.right.attr('disabled', current.next('.opengraph').length === 0);
533+ }
534+
535+ event.preventDefault();
536+}).on('click', '.opengraph a.flash-embedder', function (event) {
537+ var url = $(this).attr('href'),
538+ template = _.template('<iframe width="100%" height="200px" frameborder="0" src="<%= url %>"></iframe>');
539+ $(this).replaceWith(template({url: url}));
540+
541+ event.preventDefault();
542+});
543Index: dev-branches/tic6013-opengraph/public/assets/stylesheets/less/opengraph.less
544===================================================================
545--- trunk/public/assets/stylesheets/less/opengraph.less (revision 35413)
546+++ dev-branches/tic6013-opengraph/public/assets/stylesheets/less/opengraph.less (revision 35422)
547@@ -1,17 +1,70 @@
548-.opengraph {
549- font-size: 0.8em;
550- border: thin solid lightgrey;
551- padding: 10px;
552- margin-top: 10px;
553- min-height: 120px;
554-
555- margin-left: auto;
556- margin-right: auto;
557+.opengraph-area {
558+ margin: 10px auto 5px;
559 max-width: 700px;
560
561+ .switcher {
562+ list-style: none;
563+ text-align: right;
564+
565+ li {
566+ border-top: thin solid @dark-gray-color-20;
567+ display: inline-block;
568+ padding: 5px;
569+
570+ &:first-child {
571+ border-left: thin solid @dark-gray-color-20;
572+ }
573+ &:last-child {
574+ border-right: thin solid @dark-gray-color-20;
575+ }
576+ }
577+ .switch-left, .switch-right {
578+ .hide-text();
579+ .square(20px);
580+ background-position: center;
581+ background-repeat: no-repeat;
582+ padding: 0;
583+
584+ &:not([disabled]) {
585+ cursor: pointer;
586+ }
587+ }
588+ .switch-left {
589+ .retina-background-icon('blue/arr_1left.svg');
590+ &[disabled] {
591+ .retina-background-icon('grey/arr_1left.svg');
592+ }
593+ }
594+ .switch-right {
595+ .retina-background-icon('blue/arr_1right.svg');
596+ &[disabled] {
597+ .retina-background-icon('grey/arr_1right.svg');
598+ }
599+ }
600+ }
601+
602+ .js & .opengraph.hidden,
603+ .js &:not(.handled) .opengraph:not(:first-of-type) {
604+ // The second selector prevents flash of content before everything
605+ // is setup
606+ display: none;
607+ }
608+}
609+
610+.opengraph {
611+ @padding: 10px;
612+ @height: 120px;
613+
614+ .clearfix;
615+
616+ font-size: 0.8em;
617+ border: 1px solid @dark-gray-color-20;
618+ padding: @padding;
619+ min-height: @height;
620+
621 .flash-embedder {
622- display: flex;
623- justify-content: center;
624- align-items: center;
625+ .flex();
626+ .flex-justify-content(center);
627+ .flex-align-items(center);
628 width: 100%;
629 height: 100px;
630@@ -20,45 +73,34 @@
631 background-size: 100% auto;
632 .play {
633- background-color: rgba(0,0,0,0.7);
634- border-radius: 100px;
635+ .border-radius(100px);
636+ .transition(background-color 300ms);
637+ background-color: rgba(0, 0, 0, 0.7);
638 padding: 10px;
639- transition: background-color 0.3s;
640 }
641 &:hover .play {
642- background-color: rgba(0,0,0,1);
643- transition: background-color 0.3s;
644+ background-color: rgba(0, 0, 0, 1);
645 }
646 }
647- .video {
648- .flash-embedder {
649- height: 200px;
650- }
651- }
652- .audio {
653- text-align: center;
654+ .video .flash-embedder {
655+ height: 200px;
656 }
657
658 a.info {
659+ .box-sizing(border-box);
660+ color: black;
661 display: block;
662 word-break: normal !important;
663- color: black;
664+ &:hover {
665+ color: black;
666+ }
667 }
668- a.info:hover {
669- color: black;
670- }
671- .info_image {
672- transition: margin, padding, width, height;
673- transition-duration: 100ms;
674- float:left;
675- width: 120px;
676- height: 120px;
677- margin: 0px;
678- margin-right: 10px;
679- padding: 0px;
680- background-size: auto 100%;
681- background-position: center center;
682+ .image {
683+ .square(@height);
684+ background-size: contain;
685+ background-position: left center;
686 background-repeat: no-repeat;
687+ display: inline-block;
688+ float: left;
689+ margin-right: @padding;
690 }
691 }
692-
693-
694Index: dev-branches/tic6013-opengraph/public/assets/stylesheets/style.css
695===================================================================
696--- trunk/public/assets/stylesheets/style.css (revision 35413)
697+++ dev-branches/tic6013-opengraph/public/assets/stylesheets/style.css (revision 35422)
698@@ -5717,17 +5717,100 @@
699 display: none;
700 }
701+.opengraph-area {
702+ margin: 10px auto 5px;
703+ max-width: 700px;
704+}
705+.opengraph-area .switcher {
706+ list-style: none;
707+ text-align: right;
708+}
709+.opengraph-area .switcher li {
710+ border-top: thin solid #d8dadc;
711+ display: inline-block;
712+ padding: 5px;
713+}
714+.opengraph-area .switcher li:first-child {
715+ border-left: thin solid #d8dadc;
716+}
717+.opengraph-area .switcher li:last-child {
718+ border-right: thin solid #d8dadc;
719+}
720+.opengraph-area .switcher .switch-left,
721+.opengraph-area .switcher .switch-right {
722+ font: 0/0 a;
723+ color: transparent;
724+ text-shadow: none;
725+ background-color: transparent;
726+ border: 0;
727+ width: 20px;
728+ height: 20px;
729+ background-position: center;
730+ background-repeat: no-repeat;
731+ padding: 0;
732+}
733+.opengraph-area .switcher .switch-left:not([disabled]),
734+.opengraph-area .switcher .switch-right:not([disabled]) {
735+ cursor: pointer;
736+}
737+.opengraph-area .switcher .switch-left {
738+ background-image: url("../images/icons/blue/arr_1left.svg");
739+ -webkit-background-size: 16px 16px;
740+ -moz-background-size: 16px 16px;
741+ -o-background-size: 16px 16px;
742+ background-size: 16px 16px;
743+}
744+.opengraph-area .switcher .switch-left[disabled] {
745+ background-image: url("../images/icons/grey/arr_1left.svg");
746+ -webkit-background-size: 16px 16px;
747+ -moz-background-size: 16px 16px;
748+ -o-background-size: 16px 16px;
749+ background-size: 16px 16px;
750+}
751+.opengraph-area .switcher .switch-right {
752+ background-image: url("../images/icons/blue/arr_1right.svg");
753+ -webkit-background-size: 16px 16px;
754+ -moz-background-size: 16px 16px;
755+ -o-background-size: 16px 16px;
756+ background-size: 16px 16px;
757+}
758+.opengraph-area .switcher .switch-right[disabled] {
759+ background-image: url("../images/icons/grey/arr_1right.svg");
760+ -webkit-background-size: 16px 16px;
761+ -moz-background-size: 16px 16px;
762+ -o-background-size: 16px 16px;
763+ background-size: 16px 16px;
764+}
765+.js .opengraph-area .opengraph.hidden,
766+.js .opengraph-area:not(.handled) .opengraph:not(:first-of-type) {
767+ display: none;
768+}
769 .opengraph {
770+ *zoom: 1;
771 font-size: 0.8em;
772- border: thin solid lightgrey;
773+ border: 1px solid #d8dadc;
774 padding: 10px;
775- margin-top: 10px;
776 min-height: 120px;
777- margin-left: auto;
778- margin-right: auto;
779- max-width: 700px;
780+}
781+.opengraph:before,
782+.opengraph:after {
783+ display: table;
784+ content: "";
785+ line-height: 0;
786+}
787+.opengraph:after {
788+ clear: both;
789 }
790 .opengraph .flash-embedder {
791+ display: -ms-flexbox;
792+ display: -webkit-box;
793+ display: -webkit-box-flex;
794+ display: -webkit-flex;
795+ display: -moz-box;
796 display: flex;
797+ -webkit-justify-content: center;
798 justify-content: center;
799+ -webkit-align-items: center;
800+ -ms-flex-align: center;
801+ -moz-box-align: center;
802 align-items: center;
803 width: 100%;
804@@ -5738,39 +5821,40 @@
805 }
806 .opengraph .flash-embedder .play {
807+ -webkit-border-radius: 100px;
808+ -moz-border-radius: 100px;
809+ border-radius: 100px;
810+ -webkit-transition: background-color 300ms;
811+ -moz-transition: background-color 300ms;
812+ -o-transition: background-color 300ms;
813+ transition: background-color 300ms;
814 background-color: rgba(0, 0, 0, 0.7);
815- border-radius: 100px;
816 padding: 10px;
817- transition: background-color 0.3s;
818 }
819 .opengraph .flash-embedder:hover .play {
820 background-color: #000000;
821- transition: background-color 0.3s;
822 }
823 .opengraph .video .flash-embedder {
824 height: 200px;
825 }
826-.opengraph .audio {
827- text-align: center;
828-}
829 .opengraph a.info {
830+ -webkit-box-sizing: border-box;
831+ -moz-box-sizing: border-box;
832+ box-sizing: border-box;
833+ color: black;
834 display: block;
835 word-break: normal !important;
836- color: black;
837 }
838 .opengraph a.info:hover {
839 color: black;
840 }
841-.opengraph .info_image {
842- transition: margin, padding, width, height;
843- transition-duration: 100ms;
844- float: left;
845+.opengraph .image {
846 width: 120px;
847 height: 120px;
848- margin: 0px;
849+ background-size: contain;
850+ background-position: left center;
851+ background-repeat: no-repeat;
852+ display: inline-block;
853+ float: left;
854 margin-right: 10px;
855- padding: 0px;
856- background-size: auto 100%;
857- background-position: center center;
858- background-repeat: no-repeat;
859 }
860 #sort1,
861Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/assets/javascripts/blubber.js
862===================================================================
863--- trunk/public/plugins_packages/core/Blubber/assets/javascripts/blubber.js (revision 35413)
864+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/assets/javascripts/blubber.js (revision 35422)
865@@ -181,5 +181,5 @@
866 jQuery("#posting_" + posting_id + " > .content_column .content").html(new_version.find(".content").html());
867 jQuery("#posting_" + posting_id + " > .content_column .additional_tags").html(new_version.find(".additional_tags").html());
868- jQuery("#posting_" + posting_id + " > .content_column .opengraph_area").html(new_version.find(".opengraph_area").html());
869+ jQuery("#posting_" + posting_id + " > .content_column .opengraph-area").html(new_version.find(".opengraph-area").html());
870 if (jQuery("#posting_" + posting_id + " > .reshares").length > 0) {
871 jQuery("#posting_" + posting_id + " > .reshares").html(new_version.find(".reshares").html());
872Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/models/BlubberPosting.class.php
873===================================================================
874--- trunk/public/plugins_packages/core/Blubber/models/BlubberPosting.class.php (revision 35413)
875+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/models/BlubberPosting.class.php (revision 35422)
876@@ -22,4 +22,7 @@
877 static public $hashtags_regexp = "(^|\s)\#([\w\d_\.\-\?!\+=%]*[\w\d])";
878
879+ // Storage for formatted content for performance reasons
880+ protected $formatted_content = null;
881+
882 /**
883 * Special format-function that adds hashtags to the common formatReady-markup.
884@@ -31,4 +34,5 @@
885 $output = formatReady($text);
886 StudipFormat::removeStudipMarkup("blubberhashtag");
887+
888 return $output;
889 }
890@@ -183,4 +187,26 @@
891 $this->registerCallback('after_store', 'synchronizeHashtags');
892 parent::__construct($id);
893+ }
894+
895+ /**
896+ * @return String containing the formatted content
897+ */
898+ public function getContent()
899+ {
900+ if ($this->formatted_content === null) {
901+ $content = $this->description;
902+ if ($this->isThread() && $this->name && strpos($this->description, $this->name) === false) {
903+ $content = $this->name . "\n" . $content;
904+ }
905+
906+ $this->formatted_content = self::format($content);
907+ }
908+
909+ return $this->formatted_content;
910+ }
911+
912+ public function getOpenGraphURLs()
913+ {
914+ return $this->getContent()->getOpenGraphURLCollection();
915 }
916
917Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/views/streams/_blubber.php
918===================================================================
919--- trunk/public/plugins_packages/core/Blubber/views/streams/_blubber.php (revision 35413)
920+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/views/streams/_blubber.php (revision 35422)
921@@ -137,11 +137,5 @@
922 </div>
923 <div class="content">
924- <?
925- $content = $thread['description'];
926- if ($thread['name'] && strpos($thread['description'], $thread['name']) === false) {
927- $content = $thread['name']."\n".$content;
928- }
929- ?>
930- <?= BlubberPosting::format($content) ?>
931+ <?= $thread->getContent() ?>
932 </div>
933 <div class="additional_tags"><? foreach ($thread->getTags() as $tag) : ?>
934@@ -151,12 +145,5 @@
935 <? endif ?>
936 <? endforeach ?></div>
937- <div class="opengraph_area"><?
938- if (count(OpenGraphURL::$tempURLStorage)) {
939- $og = new OpenGraphURL(OpenGraphURL::$tempURLStorage[0]);
940- if (!$og->isNew()) {
941- echo $og->render();
942- }
943- }
944- ?></div>
945+ <?= $thread->getOpenGraphURLs()->render() ?>
946 </div>
947 <ul class="comments"><?
948Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/views/streams/comment.php
949===================================================================
950--- trunk/public/plugins_packages/core/Blubber/views/streams/comment.php (revision 35413)
951+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Blubber/views/streams/comment.php (revision 35422)
952@@ -47,14 +47,7 @@
953 </div>
954 <div class="content">
955- <?= BlubberPosting::format($posting['description']) ?>
956+ <?= $posting->getContent() ?>
957 </div>
958- <div class="opengraph_area"><?
959- if (count(OpenGraphURL::$tempURLStorage)) {
960- $og = new OpenGraphURL(OpenGraphURL::$tempURLStorage[0]);
961- if (!$og->isNew()) {
962- echo $og->render();
963- }
964- }
965- ?></div>
966+ <?= $posting->getOpenGraphURLs()->render() ?>
967 </div>
968 </li>
969Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/models/ForumEntry.php
970===================================================================
971--- trunk/public/plugins_packages/core/Forum/models/ForumEntry.php (revision 35413)
972+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/models/ForumEntry.php (revision 35422)
973@@ -88,7 +88,14 @@
974 static function getContentAsHtml($description, $anonymous = false)
975 {
976- $content = formatReady(ForumEntry::killEdit($description));
977+ $raw_content = ForumEntry::killEdit($description);
978+
979 $comment = ForumEntry::getEditComment($description, $anonymous);
980- return $content . ($comment ? '<br><i>' . htmlReady($comment) . '</i>' : '');
981+ if ($comment) {
982+ $raw_content .= "\n" . '%%' . $comment . '%%';
983+ }
984+
985+ $content = formatReady($raw_content);
986+
987+ return $content;
988 }
989
990@@ -393,5 +400,4 @@
991 'content_raw' => ForumEntry::killEdit($data['content']),
992 'content_short' => $desc_short,
993- 'opengraph' => ($og = OpenGraphURL::find(OpenGraphURL::$tempURLStorage[0])) ? $og->render() : "",
994 'chdate' => $data['chdate'],
995 'mkdate' => $data['mkdate'],
996Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/models/ForumHelpers.php
997===================================================================
998--- trunk/public/plugins_packages/core/Forum/models/ForumHelpers.php (revision 35413)
999+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/models/ForumHelpers.php (revision 35422)
1000@@ -31,5 +31,7 @@
1001 {
1002 foreach ($highlight as $hl) {
1003- $text = str_ireplace(htmlReady($hl), '<span class="highlight">'. htmlReady($hl) .'</span>', $text);
1004+ $text = preg_replace('/' . preg_quote(htmlReady($hl), '/') . '/i',
1005+ '<span class="highlight">$0</span>',
1006+ $text);
1007 }
1008 return $text;
1009@@ -46,5 +48,7 @@
1010 function highlight($text, $highlight)
1011 {
1012- if (empty($highlight)) return $text;
1013+ if (empty($highlight)) {
1014+ return $text;
1015+ }
1016
1017 $data = array();
1018Index: dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/views/index/_post.php
1019===================================================================
1020--- trunk/public/plugins_packages/core/Forum/views/index/_post.php (revision 35413)
1021+++ dev-branches/tic6013-opengraph/public/plugins_packages/core/Forum/views/index/_post.php (revision 35422)
1022@@ -91,7 +91,7 @@
1023 <span data-show-topic="<?= $post['topic_id'] ?>" data-topic-content="<?= $post['topic_id'] ?>" <?= $edit_posting != $post['topic_id'] ? '' : 'style="display: none;"' ?>>
1024 <?= ForumHelpers::highlight($post['content'], $highlight) ?>
1025+ <?= $post['content']->getOpenGraphURLCollection()->render() ?>
1026 </span>
1027 </div>
1028- <div class="opengraph_area"><?= $post['opengraph'] ?></div>
1029
1030 <!-- Buttons for this Posting -->
1031Index: dev-branches/tic6013-opengraph/templates/shared/opengraph-container.php
1032===================================================================
1033--- dev-branches/tic6013-opengraph/templates/shared/opengraph-container.php (revision 35422)
1034+++ dev-branches/tic6013-opengraph/templates/shared/opengraph-container.php (revision 35422)
1035@@ -0,0 +1,5 @@
1036+<div class="opengraph-area">
1037+<? foreach ($urls as $url): ?>
1038+ <?= $url ?>
1039+<? endforeach; ?>
1040+</div>
1041Index: dev-branches/tic6013-opengraph/templates/shared/opengraphinfo_wide.php
1042===================================================================
1043--- trunk/templates/shared/opengraphinfo_wide.php (revision 35413)
1044+++ dev-branches/tic6013-opengraph/templates/shared/opengraphinfo_wide.php (revision 35422)
1045@@ -1,62 +1,51 @@
1046 <? $videofiles = $og->getVideoFiles() ?>
1047 <? $audiofiles = $og->getAudioFiles() ?>
1048-<div class="opengraph<?= count($videofiles) > 0 ? " video" : "" ?>">
1049+<div class="opengraph <? if (count($videofiles) > 0) echo 'video'; ?> <? if (count($audiofiles) > 0) echo 'audio'; ?>">
1050+<? if ($og['image'] && count($videofiles) === 0): ?>
1051+ <a href="<?= URLHelper::getLink($og['url'], array(), false) ?>" class="image" target="_blank"
1052+ style="background-image:url(<?= $og['image'] ?>)">
1053+ </a>
1054+<? endif; ?>
1055 <a href="<?= URLHelper::getLink($og['url'], array(), false) ?>" class="info" target="_blank">
1056- <? if ($og['image'] && !count($videofiles)) : ?>
1057- <div class="info_image" style="background-image: url('<?= htmlReady($og['image']) ?>');">
1058- </div>
1059- <? endif ?>
1060 <strong><?= htmlReady($og['title']) ?></strong>
1061- <? if (!count($videofiles)) : ?>
1062- <p>
1063- <?= htmlReady($og['description']) ?>
1064- </p>
1065- <? endif ?>
1066+ <? if (!count($videofiles)) : ?>
1067+ <p><?= htmlReady($og['description']) ?></p>
1068+ <? endif ?>
1069 </a>
1070- <? if (count($videofiles)) : ?>
1071+<? if (count($videofiles)) : ?>
1072 <div class="video">
1073- <? if (in_array($videofiles[0][1], array("text/html", "application/x-shockwave-flash"))) : ?>
1074- <?
1075- $embedder = '<iframe width="100%" height="200px" frameborder="0" src="'. htmlReady($videofiles[0][0]).'"></iframe>';
1076- ?>
1077- <a href="#"
1078- class="flash-embedder"
1079- style="background-image: url('<?= htmlReady($og['image']) ?>');"
1080- onClick="jQuery(this).replaceWith(jQuery(this).data('embedder')); return false;"
1081- data-embedder="<?= htmlReady($embedder) ?>"
1082- title="<?= _("Video abspielen") ?>">
1083- <?= Assets::img("icons/80/blue/play.svg", array('class' => "play"))?>
1084- </a>
1085- <? else : ?>
1086+ <? if (in_array($videofiles[0][1], array("text/html", "application/x-shockwave-flash"))) : ?>
1087+ <a href="<?= htmlReady($videofiles[0][0]) ?>"
1088+ class="flash-embedder"
1089+ style="background-image: url('<?= htmlReady($og['image']) ?>');"
1090+ title="<?= _("Video abspielen") ?>">
1091+ <?= Assets::img("icons/80/blue/play.svg", array('class' => "play"))?>
1092+ </a>
1093+ <? else : ?>
1094 <video width="100%" height="200px" controls>
1095- <? foreach ($videofiles as $file) : ?>
1096+ <? foreach ($videofiles as $file) : ?>
1097 <source src="<?= htmlReady($file[0]) ?>"<?= $file[1] ? ' type="'.htmlReady($file[1]).'"' : "" ?>></source>
1098- <? endforeach ?>
1099+ <? endforeach ?>
1100 </video>
1101- <? endif ?>
1102+ <? endif ?>
1103 </div>
1104+<? endif ?>
1105+<? if (count($audiofiles)) : ?>
1106+ <div class="audio">
1107+ <? if (in_array($audiofiles[0][1], array("text/html", "application/x-shockwave-flash"))) : ?>
1108+ <a href="<?= htmlReady($audiofiles[0][0]) ?>"
1109+ class="flash-embedder"
1110+ style="background-image: url('<?= htmlReady($og['image']) ?>');"
1111+ title="<?= _("Audio abspielen") ?>">
1112+ <?= Assets::img("icons/100/blue/play.svg")?>
1113+ </a>
1114+ <? else : ?>
1115+ <audio width="100%" height="50px" controls>
1116+ <? foreach ($audiofiles as $file) : ?>
1117+ <source src="<?= htmlReady($file[0]) ?>"<?= $file[1] ? ' type="'.htmlReady($file[1]).'"' : "" ?>></source>
1118+ <? endforeach ?>
1119+ </audio>
1120 <? endif ?>
1121- <? if (count($audiofiles)) : ?>
1122- <div class="audio">
1123- <? if (in_array($audiofiles[0][1], array("text/html", "application/x-shockwave-flash"))) : ?>
1124- <?
1125- $embedder = '<iframe width="100%" height="200px" frameborder="0" src="'. htmlReady($audiofiles[0][0]).'"></iframe>';
1126- ?>
1127- <a href="#"
1128- class="flash-embedder"
1129- style="background-image: url('<?= htmlReady($og['image']) ?>');"
1130- onClick="jQuery(this).replaceWith(jQuery(this).data('embedder')); return false;"
1131- data-embedder="<?= htmlReady($embedder) ?>"
1132- title="<?= _("Audio abspielen") ?>">
1133- <?= Assets::img("icons/100/blue/play.svg")?>
1134- </a>
1135- <? else : ?>
1136- <audio width="100%" height="50px" controls>
1137- <? foreach ($audiofiles as $file) : ?>
1138- <source src="<?= htmlReady($file[0]) ?>"<?= $file[1] ? ' type="'.htmlReady($file[1]).'"' : "" ?>></source>
1139- <? endforeach ?>
1140- </audio>
1141- <? endif ?>
1142 </div>
1143- <? endif ?>
1144+<? endif ?>
1145 </div>
1146Index: dev-branches/tic6013-opengraph/tests/unit/lib/VisualTest.php
1147===================================================================
1148--- trunk/tests/unit/lib/VisualTest.php (revision 35413)
1149+++ dev-branches/tic6013-opengraph/tests/unit/lib/VisualTest.php (revision 35422)
1150@@ -12,6 +12,13 @@
1151 require_once dirname(__FILE__) . '/../bootstrap.php';
1152 require_once 'config.inc.php'; //$SMILE_SHORT and $SYMBOL_SHORT needed by formatReady
1153+require_once 'lib/classes/StudipArrayObject.class.php';
1154+require_once 'lib/classes/MultiDimArrayObject.class.php';
1155+require_once 'lib/classes/JSONArrayObject.class.php';
1156 require_once 'lib/models/SimpleORMap.class.php';
1157+require_once 'lib/models/SimpleCollection.class.php';
1158+require_once 'lib/models/SimpleORMapCollection.class.php';
1159 require_once 'lib/models/OpenGraphURL.class.php';
1160+require_once 'lib/models/OpenGraphURLCollection.class.php';
1161+require_once 'lib/classes/FormattedContent.php';
1162 require_once 'lib/visual.inc.php';
1163 require_once 'lib/classes/Config.class.php';
1164@@ -23,5 +30,6 @@
1165 {
1166 static $config = array(
1167- 'LOAD_EXTERNAL_MEDIA' => 'allow'
1168+ 'LOAD_EXTERNAL_MEDIA' => 'allow',
1169+ 'OPENGRAPH_ENABLE' => false,
1170 );