Merge branch 'oembed-thumbnails' into 0.9.x
This commit is contained in:
		| @@ -112,6 +112,12 @@ class OembedAction extends Action | ||||
|                         //$oembed['width']= | ||||
|                         //$oembed['height']= | ||||
|                         $oembed['url']=$attachment->url; | ||||
|                         $thumb = $attachment->getThumbnail(); | ||||
|                         if ($thumb) { | ||||
|                             $oembed['thumbnail_url'] = $thumb->url; | ||||
|                             $oembed['thumbnail_width'] = $thumb->width; | ||||
|                             $oembed['thumbnail_height'] = $thumb->height; | ||||
|                         } | ||||
|                     }else{ | ||||
|                         $oembed['type']='link'; | ||||
|                         $oembed['url']=common_local_url('attachment', | ||||
|   | ||||
| @@ -331,6 +331,15 @@ class SingleNoticeItem extends DoFollowListItem | ||||
|         $this->showEnd(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * For our zoomed-in special case we'll use a fuller list | ||||
|      * for the attachment info. | ||||
|      */ | ||||
|     function showNoticeAttachments() { | ||||
|         $al = new AttachmentList($this->notice, $this->out); | ||||
|         $al->show(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * show the avatar of the notice's author | ||||
|      * | ||||
| @@ -356,9 +365,4 @@ class SingleNoticeItem extends DoFollowListItem | ||||
|                                          $this->profile->fullname : | ||||
|                                          $this->profile->nickname)); | ||||
|     } | ||||
|  | ||||
|     function showNoticeAttachments() { | ||||
|         $al = new AttachmentList($this->notice, $this->out); | ||||
|         $al->show(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -352,22 +352,28 @@ class File extends Memcached_DataObject | ||||
|                 $mimetype = substr($mimetype,0,$semicolon); | ||||
|             } | ||||
|             if(in_array($mimetype,$notEnclosureMimeTypes)){ | ||||
|                 // Never treat generic HTML links as an enclosure type! | ||||
|                 // But if we have oEmbed info, we'll consider it golden. | ||||
|                 $oembed = File_oembed::staticGet('file_id',$this->id); | ||||
|                 if($oembed){ | ||||
|                 if($oembed && in_array($oembed->type, array('photo', 'video'))){ | ||||
|                     $mimetype = strtolower($oembed->mimetype); | ||||
|                     $semicolon = strpos($mimetype,';'); | ||||
|                     if($semicolon){ | ||||
|                         $mimetype = substr($mimetype,0,$semicolon); | ||||
|                     } | ||||
|                     if(in_array($mimetype,$notEnclosureMimeTypes)){ | ||||
|                         return false; | ||||
|                     }else{ | ||||
|                     // @fixme uncertain if this is right. | ||||
|                     // we want to expose things like YouTube videos as | ||||
|                     // viewable attachments, but don't expose them as | ||||
|                     // downloadable enclosures.....? | ||||
|                     //if (in_array($mimetype, $notEnclosureMimeTypes)) { | ||||
|                     //    return false; | ||||
|                     //} else { | ||||
|                         if($oembed->mimetype) $enclosure->mimetype=$oembed->mimetype; | ||||
|                         if($oembed->url) $enclosure->url=$oembed->url; | ||||
|                         if($oembed->title) $enclosure->title=$oembed->title; | ||||
|                         if($oembed->modified) $enclosure->modified=$oembed->modified; | ||||
|                         unset($oembed->size); | ||||
|                     } | ||||
|                     //} | ||||
|                 } else { | ||||
|                     return false; | ||||
|                 } | ||||
| @@ -382,4 +388,14 @@ class File extends Memcached_DataObject | ||||
|         $enclosure = $this->getEnclosure(); | ||||
|         return !empty($enclosure); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the attachment's thumbnail record, if any. | ||||
|      * | ||||
|      * @return File_thumbnail | ||||
|      */ | ||||
|     function getThumbnail() | ||||
|     { | ||||
|         return File_thumbnail::staticGet('file_id', $this->id); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -58,11 +58,11 @@ class File_oembed extends Memcached_DataObject | ||||
|         return array(false, false, false); | ||||
|     } | ||||
|  | ||||
|     function _getOembed($url, $maxwidth = 500, $maxheight = 400) { | ||||
|     function _getOembed($url) { | ||||
|         require_once INSTALLDIR.'/extlib/Services/oEmbed.php'; | ||||
|         $parameters = array( | ||||
|             'maxwidth'=>$maxwidth, | ||||
|             'maxheight'=>$maxheight, | ||||
|             'maxwidth' => common_config('attachments', 'thumb_width'), | ||||
|             'maxheight' => common_config('attachments', 'thumb_height'), | ||||
|         ); | ||||
|         try{ | ||||
|             $oEmbed = new Services_oEmbed($url); | ||||
|   | ||||
| @@ -48,12 +48,34 @@ class File_thumbnail extends Memcached_DataObject | ||||
|         return array(false, false, false); | ||||
|     } | ||||
|  | ||||
|     function saveNew($data, $file_id) { | ||||
|     /** | ||||
|      * Save oEmbed-provided thumbnail data | ||||
|      * | ||||
|      * @param object $data | ||||
|      * @param int $file_id | ||||
|      */ | ||||
|     public static function saveNew($data, $file_id) { | ||||
|         self::saveThumbnail($file_id, | ||||
|                             $data->thumbnail_url, | ||||
|                             $data->thumbnail_width, | ||||
|                             $data->thumbnail_height); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save a thumbnail record for the referenced file record. | ||||
|      * | ||||
|      * @param int $file_id | ||||
|      * @param string $url | ||||
|      * @param int $width | ||||
|      * @param int $height | ||||
|      */ | ||||
|     static function saveThumbnail($file_id, $url, $width, $height) | ||||
|     { | ||||
|         $tn = new File_thumbnail; | ||||
|         $tn->file_id = $file_id; | ||||
|         $tn->url = $data->thumbnail_url; | ||||
|         $tn->width = intval($data->thumbnail_width); | ||||
|         $tn->height = intval($data->thumbnail_height); | ||||
|         $tn->url = $url; | ||||
|         $tn->width = intval($width); | ||||
|         $tn->height = intval($height); | ||||
|         $tn->insert(); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										57
									
								
								js/util.js
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								js/util.js
									
									
									
									
									
								
							| @@ -56,7 +56,7 @@ var SN = { // StatusNet | ||||
|             NoticeDataGeoCookie: 'NoticeDataGeo', | ||||
|             NoticeDataGeoSelected: 'notice_data-geo_selected', | ||||
|             StatusNetInstance:'StatusNetInstance' | ||||
|         }, | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     messages: {}, | ||||
| @@ -427,61 +427,6 @@ var SN = { // StatusNet | ||||
|                     return false; | ||||
|                 }).attr('title', SN.msg('showmore_tooltip')); | ||||
|             } | ||||
|             else { | ||||
|                 $.fn.jOverlay.options = { | ||||
|                     method : 'GET', | ||||
|                     data : '', | ||||
|                     url : '', | ||||
|                     color : '#000', | ||||
|                     opacity : '0.6', | ||||
|                     zIndex : 9999, | ||||
|                     center : false, | ||||
|                     imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif', | ||||
|                     bgClickToClose : true, | ||||
|                     success : function() { | ||||
|                         $('#jOverlayContent').append('<button class="close">×</button>'); | ||||
|                         $('#jOverlayContent button').click($.closeOverlay); | ||||
|                     }, | ||||
|                     timeout : 0, | ||||
|                     autoHide : true, | ||||
|                     css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'} | ||||
|                 }; | ||||
|  | ||||
|                 notice.find('a.attachment').click(function() { | ||||
|                     var attachId = ($(this).attr('id').substring('attachment'.length + 1)); | ||||
|                     if (attachId) { | ||||
|                         $().jOverlay({url: $('address .url')[0].href+'attachment/' + attachId + '/ajax'}); | ||||
|                         return false; | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 if ($('#shownotice').length == 0) { | ||||
|                     var t; | ||||
|                     notice.find('a.thumbnail').hover( | ||||
|                         function() { | ||||
|                             var anchor = $(this); | ||||
|                             $('a.thumbnail').children('img').hide(); | ||||
|                             anchor.closest(".entry-title").addClass('ov'); | ||||
|  | ||||
|                             if (anchor.children('img').length === 0) { | ||||
|                                 t = setTimeout(function() { | ||||
|                                     $.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) { | ||||
|                                         anchor.append(data); | ||||
|                                     }); | ||||
|                                 }, 500); | ||||
|                             } | ||||
|                             else { | ||||
|                                 anchor.children('img').show(); | ||||
|                             } | ||||
|                         }, | ||||
|                         function() { | ||||
|                             clearTimeout(t); | ||||
|                             $('a.thumbnail').children('img').hide(); | ||||
|                             $(this).closest('.entry-title').removeClass('ov'); | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         NoticeDataAttach: function() { | ||||
|   | ||||
| @@ -79,23 +79,33 @@ class AttachmentList extends Widget | ||||
|         $atts = new File; | ||||
|         $att = $atts->getAttachments($this->notice->id); | ||||
|         if (empty($att)) return 0; | ||||
|         $this->out->elementStart('dl', array('id' =>'attachments', | ||||
|                                              'class' => 'entry-content')); | ||||
|         // TRANS: DT element label in attachment list. | ||||
|         $this->out->element('dt', null, _('Attachments')); | ||||
|         $this->out->elementStart('dd'); | ||||
|         $this->out->elementStart('ol', array('class' => 'attachments')); | ||||
|         $this->showListStart(); | ||||
|  | ||||
|         foreach ($att as $n=>$attachment) { | ||||
|             $item = $this->newListItem($attachment); | ||||
|             $item->show(); | ||||
|         } | ||||
|  | ||||
|         $this->showListEnd(); | ||||
|  | ||||
|         return count($att); | ||||
|     } | ||||
|  | ||||
|     function showListStart() | ||||
|     { | ||||
|         $this->out->elementStart('dl', array('id' =>'attachments', | ||||
|                                              'class' => 'entry-content')); | ||||
|         // TRANS: DT element label in attachment list. | ||||
|         $this->out->element('dt', null, _('Attachments')); | ||||
|         $this->out->elementStart('dd'); | ||||
|         $this->out->elementStart('ol', array('class' => 'attachments')); | ||||
|     } | ||||
|  | ||||
|     function showListEnd() | ||||
|     { | ||||
|         $this->out->elementEnd('dd'); | ||||
|         $this->out->elementEnd('ol'); | ||||
|         $this->out->elementEnd('dl'); | ||||
|  | ||||
|         return count($att); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -187,7 +197,10 @@ class AttachmentListItem extends Widget | ||||
|     } | ||||
|  | ||||
|     function linkAttr() { | ||||
|         return array('class' => 'attachment', 'href' => $this->attachment->url, 'id' => 'attachment-' . $this->attachment->id); | ||||
|         return array('class' => 'attachment', | ||||
|                      'href' => $this->attachment->url, | ||||
|                      'id' => 'attachment-' . $this->attachment->id, | ||||
|                      'title' => $this->title()); | ||||
|     } | ||||
|  | ||||
|     function showLink() { | ||||
| @@ -203,9 +216,56 @@ class AttachmentListItem extends Widget | ||||
|     } | ||||
|  | ||||
|     function showRepresentation() { | ||||
|         $thumb = $this->getThumbInfo(); | ||||
|         if ($thumb) { | ||||
|             $thumb = $this->sizeThumb($thumb); | ||||
|             $this->out->element('img', array('alt' => '', 'src' => $thumb->url, 'width' => $thumb->width, 'height' => $thumb->height)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Pull a thumbnail image reference for the given file. | ||||
|      * In order we check: | ||||
|      *  1) file_thumbnail table (thumbnails found via oEmbed) | ||||
|      *  2) image URL from direct dereference or oEmbed 'photo' type URL | ||||
|      *  3) ??? | ||||
|      * | ||||
|      * @return mixed object with (url, width, height) properties, or false | ||||
|      */ | ||||
|     function getThumbInfo() | ||||
|     { | ||||
|         $thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id); | ||||
|         if (!empty($thumbnail)) { | ||||
|             $this->out->element('img', array('alt' => '', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height)); | ||||
|         if ($thumbnail) { | ||||
|             return $thumbnail; | ||||
|         } | ||||
|         $enc = $this->attachment->getEnclosure(); | ||||
|         if ($enc) { | ||||
|             switch ($enc->mimetype) { | ||||
|                 case 'image/gif': | ||||
|                 case 'image/png': | ||||
|                 case 'image/jpg': | ||||
|                 case 'image/jpeg': | ||||
|                     $thumb = (object)array(); | ||||
|                     $thumb->url = $enc->url; | ||||
|                     // @fixme use the given width/height aspect | ||||
|                     $thumb->width = common_config('attachments', 'thumb_width'); | ||||
|                     $thumb->height = common_config('attachments', 'thumb_height'); | ||||
|                     return $thumb; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     function sizeThumb($thumbnail) { | ||||
|         $maxWidth = 100; | ||||
|         $maxHeight = 75; | ||||
|         if ($thumbnail->width > $maxWidth) { | ||||
|             $thumb = clone($thumbnail); | ||||
|             $thumb->width = $maxWidth; | ||||
|             $thumb->height = intval($thumbnail->height * $maxWidth / $thumbnail->width); | ||||
|             return $thumb; | ||||
|         } else { | ||||
|             return $thumbnail; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -234,6 +294,9 @@ class AttachmentListItem extends Widget | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * used for one-off attachment action | ||||
|  */ | ||||
| class Attachment extends AttachmentListItem | ||||
| { | ||||
|     function showLink() { | ||||
| @@ -414,18 +477,4 @@ class Attachment extends AttachmentListItem | ||||
|  | ||||
|         return $scrubbed; | ||||
|     } | ||||
|  | ||||
|     function showFallback() | ||||
|     { | ||||
|         // If we don't know how to display an attachment inline, we probably | ||||
|         // shouldn't have gotten to this point. | ||||
|         // | ||||
|         // But, here we are... displaying details on a file or remote URL | ||||
|         // either on the main view or in an ajax-loaded lightbox. As a lesser | ||||
|         // of several evils, we'll try redirecting to the actual target via | ||||
|         // client-side JS. | ||||
|  | ||||
|         common_log(LOG_ERR, "Empty or unknown type for file id {$this->attachment->id}; falling back to client-side redirect."); | ||||
|         $this->out->raw('<script>window.location = ' . json_encode($this->attachment->url) . ';</script>'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -250,6 +250,9 @@ $default = | ||||
|               'monthly_quota' => 15000000, | ||||
|               'uploads' => true, | ||||
|               'filecommand' => '/usr/bin/file', | ||||
|               'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info | ||||
|               'thumb_width' => 100, | ||||
|               'thumb_height' => 75, | ||||
|               ), | ||||
|         'application' => | ||||
|         array('desclimit' => null), | ||||
|   | ||||
| @@ -115,10 +115,46 @@ class ImageFile | ||||
|         return new ImageFile(null, $_FILES[$param]['tmp_name']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compat interface for old code generating avatar thumbnails... | ||||
|      * Saves the scaled file directly into the avatar area. | ||||
|      * | ||||
|      * @param int $size target width & height -- must be square | ||||
|      * @param int $x (default 0) upper-left corner to crop from | ||||
|      * @param int $y (default 0) upper-left corner to crop from | ||||
|      * @param int $w (default full) width of image area to crop | ||||
|      * @param int $h (default full) height of image area to crop | ||||
|      * @return string filename | ||||
|      */ | ||||
|     function resize($size, $x = 0, $y = 0, $w = null, $h = null) | ||||
|     { | ||||
|         $targetType = $this->preferredType($this->type); | ||||
|         $outname = Avatar::filename($this->id, | ||||
|                                     image_type_to_extension($targetType), | ||||
|                                     $size, | ||||
|                                     common_timestamp()); | ||||
|         $outpath = Avatar::path($outname); | ||||
|         $this->resizeTo($outpath, $size, $size, $x, $y, $w, $h); | ||||
|         return $outname; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create and save a thumbnail image. | ||||
|      * | ||||
|      * @param string $outpath | ||||
|      * @param int $width target width | ||||
|      * @param int $height target height | ||||
|      * @param int $x (default 0) upper-left corner to crop from | ||||
|      * @param int $y (default 0) upper-left corner to crop from | ||||
|      * @param int $w (default full) width of image area to crop | ||||
|      * @param int $h (default full) height of image area to crop | ||||
|      * @return string full local filesystem filename | ||||
|      */ | ||||
|     function resizeTo($outpath, $width, $height, $x=0, $y=0, $w=null, $h=null) | ||||
|     { | ||||
|         $w = ($w === null) ? $this->width:$w; | ||||
|         $h = ($h === null) ? $this->height:$h; | ||||
|         $targetType = $this->preferredType($this->type); | ||||
|  | ||||
|         if (!file_exists($this->filepath)) { | ||||
|             throw new Exception(_('Lost our file.')); | ||||
| @@ -126,20 +162,16 @@ class ImageFile | ||||
|         } | ||||
|  | ||||
|         // Don't crop/scale if it isn't necessary | ||||
|         if ($size === $this->width | ||||
|             && $size === $this->height | ||||
|         if ($width === $this->width | ||||
|             && $height === $this->height | ||||
|             && $x === 0 | ||||
|             && $y === 0 | ||||
|             && $w === $this->width | ||||
|             && $h === $this->height) { | ||||
|             && $h === $this->height | ||||
|             && $this->type == $targetType) { | ||||
|  | ||||
|             $outname = Avatar::filename($this->id, | ||||
|                                         image_type_to_extension($this->type), | ||||
|                                         $size, | ||||
|                                         common_timestamp()); | ||||
|             $outpath = Avatar::path($outname); | ||||
|             @copy($this->filepath, $outpath); | ||||
|             return $outname; | ||||
|             return $outpath; | ||||
|         } | ||||
|  | ||||
|         switch ($this->type) { | ||||
| @@ -166,7 +198,7 @@ class ImageFile | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $image_dest = imagecreatetruecolor($size, $size); | ||||
|         $image_dest = imagecreatetruecolor($width, $height); | ||||
|  | ||||
|         if ($this->type == IMAGETYPE_GIF || $this->type == IMAGETYPE_PNG || $this->type == IMAGETYPE_BMP) { | ||||
|  | ||||
| @@ -189,30 +221,9 @@ class ImageFile | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $size, $size, $w, $h); | ||||
|         imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $width, $height, $w, $h); | ||||
|  | ||||
|         if($this->type == IMAGETYPE_BMP) { | ||||
|             //we don't want to save BMP... it's an inefficient, rare, antiquated format | ||||
|             //save png instead | ||||
|             $this->type = IMAGETYPE_PNG; | ||||
|         } else if($this->type == IMAGETYPE_WBMP) { | ||||
|             //we don't want to save WBMP... it's a rare format that we can't guarantee clients will support | ||||
|             //save png instead | ||||
|             $this->type = IMAGETYPE_PNG; | ||||
|         } else if($this->type == IMAGETYPE_XBM) { | ||||
|             //we don't want to save XBM... it's a rare format that we can't guarantee clients will support | ||||
|             //save png instead | ||||
|             $this->type = IMAGETYPE_PNG; | ||||
|         } | ||||
|  | ||||
|         $outname = Avatar::filename($this->id, | ||||
|                                     image_type_to_extension($this->type), | ||||
|                                     $size, | ||||
|                                     common_timestamp()); | ||||
|  | ||||
|         $outpath = Avatar::path($outname); | ||||
|  | ||||
|         switch ($this->type) { | ||||
|         switch ($targetType) { | ||||
|          case IMAGETYPE_GIF: | ||||
|             imagegif($image_dest, $outpath); | ||||
|             break; | ||||
| @@ -230,7 +241,31 @@ class ImageFile | ||||
|         imagedestroy($image_src); | ||||
|         imagedestroy($image_dest); | ||||
|  | ||||
|         return $outname; | ||||
|         return $outpath; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Several obscure file types should be normalized to PNG on resize. | ||||
|      * | ||||
|      * @param int $type | ||||
|      * @return int | ||||
|      */ | ||||
|     function preferredType($type) | ||||
|     { | ||||
|         if($type == IMAGETYPE_BMP) { | ||||
|             //we don't want to save BMP... it's an inefficient, rare, antiquated format | ||||
|             //save png instead | ||||
|             return IMAGETYPE_PNG; | ||||
|         } else if($type == IMAGETYPE_WBMP) { | ||||
|             //we don't want to save WBMP... it's a rare format that we can't guarantee clients will support | ||||
|             //save png instead | ||||
|             return IMAGETYPE_PNG; | ||||
|         } else if($type == IMAGETYPE_XBM) { | ||||
|             //we don't want to save XBM... it's a rare format that we can't guarantee clients will support | ||||
|             //save png instead | ||||
|             return IMAGETYPE_PNG; | ||||
|         } | ||||
|         return $type; | ||||
|     } | ||||
|  | ||||
|     function unlink() | ||||
|   | ||||
							
								
								
									
										108
									
								
								lib/inlineattachmentlist.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/inlineattachmentlist.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet, the distributed open-source microblogging tool | ||||
|  * | ||||
|  * widget for displaying notice attachments thumbnails | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * LICENCE: This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * @category  UI | ||||
|  * @package   StatusNet | ||||
|  * @author    Brion Vibber <brion@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| class InlineAttachmentList extends AttachmentList | ||||
| { | ||||
|     function showListStart() | ||||
|     { | ||||
|         $this->out->elementStart('div', array('class' => 'entry-content thumbnails')); | ||||
|     } | ||||
|  | ||||
|     function showListEnd() | ||||
|     { | ||||
|         $this->out->elementEnd('div'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * returns a new list item for the current attachment | ||||
|      * | ||||
|      * @param File $notice the current attachment | ||||
|      * | ||||
|      * @return ListItem a list item for displaying the attachment | ||||
|      */ | ||||
|     function newListItem($attachment) | ||||
|     { | ||||
|         return new InlineAttachmentListItem($attachment, $this->out); | ||||
|     } | ||||
| } | ||||
|  | ||||
| class InlineAttachmentListItem extends AttachmentListItem | ||||
| { | ||||
|     function show() | ||||
|     { | ||||
|         if ($this->attachment->isEnclosure()) { | ||||
|             parent::show(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function showLink() { | ||||
|         $this->out->elementStart('a', $this->linkAttr()); | ||||
|         $this->showRepresentation(); | ||||
|         $this->out->elementEnd('a'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build HTML attributes for the link | ||||
|      * @return array | ||||
|      */ | ||||
|     function linkAttr() | ||||
|     { | ||||
|         $attr = parent::linkAttr(); | ||||
|         $attr['class'] = 'attachment-thumbnail'; | ||||
|         return $attr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * start a single notice. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showStart() | ||||
|     { | ||||
|         // XXX: RDFa | ||||
|         // TODO: add notice_type class e.g., notice_video, notice_image | ||||
|         $this->out->elementStart('span', array('class' => 'inline-attachment')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * finish the notice | ||||
|      * | ||||
|      * Close the last elements in the notice list item | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showEnd() | ||||
|     { | ||||
|         $this->out->elementEnd('span'); | ||||
|     } | ||||
| } | ||||
| @@ -48,11 +48,14 @@ class MediaFile | ||||
|     { | ||||
|         if ($user == null) { | ||||
|             $this->user = common_current_user(); | ||||
|         } else { | ||||
|             $this->user = $user; | ||||
|         } | ||||
|  | ||||
|         $this->filename   = $filename; | ||||
|         $this->mimetype   = $mimetype; | ||||
|         $this->fileRecord = $this->storeFile(); | ||||
|         $this->thumbnailRecord = $this->storeThumbnail(); | ||||
|  | ||||
|         $this->fileurl = common_local_url('attachment', | ||||
|                                     array('attachment' => $this->fileRecord->id)); | ||||
| @@ -102,6 +105,52 @@ class MediaFile | ||||
|         return $file; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate and store a thumbnail image for the uploaded file, if applicable. | ||||
|      * | ||||
|      * @return File_thumbnail or null | ||||
|      */ | ||||
|     function storeThumbnail() | ||||
|     { | ||||
|         if (substr($this->mimetype, 0, strlen('image/')) != 'image/') { | ||||
|             // @fixme video thumbs would be nice! | ||||
|             return null; | ||||
|         } | ||||
|         try { | ||||
|             $image = new ImageFile($this->fileRecord->id, | ||||
|                                    File::path($this->filename)); | ||||
|         } catch (Exception $e) { | ||||
|             // Unsupported image type. | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         $outname = File::filename($this->user->getProfile(), 'thumb-' . $this->filename, $this->mimetype); | ||||
|         $outpath = File::path($outname); | ||||
|  | ||||
|         $maxWidth = common_config('attachments', 'thumb_width'); | ||||
|         $maxHeight = common_config('attachments', 'thumb_height'); | ||||
|         list($width, $height) = $this->scaleToFit($image->width, $image->height, $maxWidth, $maxHeight); | ||||
|  | ||||
|         $image->resizeTo($outpath, $width, $height); | ||||
|         File_thumbnail::saveThumbnail($this->fileRecord->id, | ||||
|                                       File::url($outname), | ||||
|                                       $width, | ||||
|                                       $height); | ||||
|     } | ||||
|  | ||||
|     function scaleToFit($width, $height, $maxWidth, $maxHeight) | ||||
|     { | ||||
|         $aspect = $maxWidth / $maxHeight; | ||||
|         $w1 = $maxWidth; | ||||
|         $h1 = intval($height * $maxWidth / $width); | ||||
|         if ($h1 > $maxHeight) { | ||||
|             $w2 = intval($width * $maxHeight / $height); | ||||
|             $h2 = $maxHeight; | ||||
|             return array($w2, $h2); | ||||
|         } | ||||
|         return array($w1, $h1); | ||||
|     } | ||||
|  | ||||
|     function rememberFile($file, $short) | ||||
|     { | ||||
|         $this->maybeAddRedir($file->id, $short); | ||||
|   | ||||
| @@ -208,6 +208,7 @@ class NoticeListItem extends Widget | ||||
|         $this->showStart(); | ||||
|         if (Event::handle('StartShowNoticeItem', array($this))) { | ||||
|             $this->showNotice(); | ||||
|             $this->showNoticeAttachments(); | ||||
|             $this->showNoticeInfo(); | ||||
|             $this->showNoticeOptions(); | ||||
|             Event::handle('EndShowNoticeItem', array($this)); | ||||
| @@ -383,6 +384,13 @@ class NoticeListItem extends Widget | ||||
|         $this->out->elementEnd('p'); | ||||
|     } | ||||
|  | ||||
|     function showNoticeAttachments() { | ||||
|         if (common_config('attachments', 'show_thumbs')) { | ||||
|             $al = new InlineAttachmentList($this->notice, $this->out); | ||||
|             $al->show(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * show the link to the main page for the notice | ||||
|      * | ||||
|   | ||||
| @@ -877,7 +877,7 @@ function common_linkify($url) { | ||||
|     } | ||||
|  | ||||
|     if (!empty($f)) { | ||||
|         if ($f->getEnclosure() || File_oembed::staticGet('file_id',$f->id)) { | ||||
|         if ($f->getEnclosure()) { | ||||
|             $is_attachment = true; | ||||
|             $attachment_id = $f->id; | ||||
|  | ||||
|   | ||||
| @@ -1325,15 +1325,6 @@ margin-left:4px; | ||||
| .notice .attachment.more { | ||||
| padding-left:0; | ||||
| } | ||||
| .notice .attachment img { | ||||
| position:absolute; | ||||
| top:18px; | ||||
| left:0; | ||||
| z-index:99; | ||||
| } | ||||
| #shownotice .notice .attachment img { | ||||
| position:static; | ||||
| } | ||||
|  | ||||
| #attachments { | ||||
| clear:both; | ||||
| @@ -1716,6 +1707,12 @@ width:auto; | ||||
| min-width:0; | ||||
| } | ||||
|  | ||||
| .inline-attachment img { | ||||
|     /* Why on earth is this changed to block at the top? */ | ||||
|     display: inline; | ||||
|     border: solid 1px #aaa; | ||||
|     padding: 1px; | ||||
| } | ||||
| }/*end of @media screen, projection, tv*/ | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user