X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Fnoticelist.php;h=55dd902b4a3def0933b3c7a2fed3d431dd4d661c;hb=fecb8c706dadb790c3a8c219275b4ba88e00b8ea;hp=92a44c1c35c2b2fb386a38ff28b5f29259ed2118;hpb=816f87fd27ea7dbac291c8394f8b4ad0f9974f87;p=quix0rs-gnu-social.git diff --git a/lib/noticelist.php b/lib/noticelist.php index 92a44c1c35..55dd902b4a 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -1,224 +1,570 @@ . + * along with this program. If not, see . + * + * @category UI + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @copyright 2008 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/favorform.php'; +require_once INSTALLDIR.'/lib/disfavorform.php'; + +/** + * widget for displaying a list of notices + * + * There are a number of actions that display a list of notices, in + * reverse chronological order. This widget abstracts out most of the + * code for UI for notice lists. It's overridden to hide some + * data for e.g. the profile page. + * + * @category UI + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see Notice + * @see StreamAction + * @see NoticeListItem + * @see ProfileNoticeList */ -if (!defined('LACONICA')) { exit(1); } +class NoticeList extends Widget +{ + /** the current stream of notices being displayed. */ -class NoticeList { + var $notice = null; - var $notice = NULL; + /** + * constructor + * + * @param Notice $notice stream of notices from DB_DataObject + */ - function __construct($notice) { + function __construct($notice, $out=null) + { + parent::__construct($out); $this->notice = $notice; } - function show() { + /** + * show the list of notices + * + * "Uses up" the stream by looping through it. So, probably can't + * be called twice on the same list. + * + * @return int count of notices listed. + */ - common_element_start('ul', array('id' => 'notices')); + function show() + { + $this->out->elementStart('div', array('id' =>'notices_primary')); + $this->out->element('h2', null, _('Notices')); + $this->out->elementStart('ul', array('class' => 'notices')); - $cnt = 0; + $cnt = 0; - while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) { - $cnt++; + while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) { + $cnt++; - if ($cnt > NOTICES_PER_PAGE) { - break; - } + if ($cnt > NOTICES_PER_PAGE) { + break; + } - $item = $this->new_list_item($this->notice); + $item = $this->newListItem($this->notice); $item->show(); - } + } - common_element_end('ul'); + $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); return $cnt; - } + } - function new_list_item($notice) { - return new NoticeListItem($notice); + /** + * returns a new list item for the current notice + * + * Recipe (factory?) method; overridden by sub-classes to give + * a different list item class. + * + * @param Notice $notice the current notice + * + * @return NoticeListItem a list item for displaying the notice + */ + + function newListItem($notice) + { + return new NoticeListItem($notice, $this->out); } } -class NoticeListItem { +/** + * widget for displaying a single notice + * + * This widget has the core smarts for showing a single notice: what to display, + * where, and under which circumstances. Its key method is show(); this is a recipe + * that calls all the other show*() methods to build up a single notice. The + * ProfileNoticeListItem subclass, for example, overrides showAuthor() to skip + * author info (since that's implicit by the data in the page). + * + * @category UI + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see NoticeList + * @see ProfileNoticeListItem + */ - var $notice = NULL; - var $profile = NULL; +class NoticeListItem extends Widget +{ + /** The notice this item will show. */ - function __construct($notice) { - $this->notice = $notice; - $this->profile = $notice->getProfile(); - } - - function show() { - $this->show_start(); - $this->show_fave_form(); - $this->show_author(); - $this->show_content(); - $this->show_start_time_section(); - $this->show_notice_link(); - $this->show_notice_source(); - $this->show_reply_to(); - $this->show_reply_link(); - $this->show_delete_link(); - $this->show_end_time_section(); - $this->show_end(); - } - - function show_start() { - # XXX: RDFa - common_element_start('li', array('class' => 'notice_single hentry', - 'id' => 'notice-' . $this->notice->id)); - } - - function show_fave_form() { + var $notice = null; + + /** The profile of the author of the notice, extracted once for convenience. */ + + var $profile = null; + + /** + * constructor + * + * Also initializes the profile attribute. + * + * @param Notice $notice The notice we'll display + */ + + function __construct($notice, $out=null) + { + parent::__construct($out); + $this->notice = $notice; + $this->profile = $notice->getProfile(); + } + + /** + * recipe function for displaying a single notice. + * + * This uses all the other methods to correctly display a notice. Override + * it or one of the others to fine-tune the output. + * + * @return void + */ + + function show() + { + $this->showStart(); + $this->showNotice(); + $this->showNoticeAttachments(); + $this->showNoticeOptions(); + $this->showNoticeInfo(); + $this->showEnd(); + } + + function showNotice() + { +if (0) + $this->out->elementStart('entry-title'); +else + + if ('shownotice' === $this->out->args['action']) { + $width = '85%'; + } else { + $width = '90%'; + } + + + $this->out->elementStart('div', array('class' => 'entry-title', 'style' => "float: left; width: $width;")); + $this->showAuthor(); + $this->showContent(); + $this->out->elementEnd('div'); + } + + function showNoticeAttachments() + { + $f2p = new File_to_post; + $f2p->post_id = $this->notice->id; + $file = new File; + $file->joinAdd($f2p); + $file->selectAdd(); + $file->selectAdd('file.id as id'); + $count = $file->find(true); + if (!$count) return; + if (1 === $count) { + $href = common_local_url('attachment', array('attachment' => $file->id)); + $att_class = 'attachment'; + } else { + $href = common_local_url('attachments', array('notice' => $this->notice->id)); + $att_class = 'attachments'; + } + + $clip = theme_path('images/icons/clip', 'base'); + if ('shownotice' === $this->out->args['action']) { + $height = '96px'; + $width = '83%'; + $width_att = '15%'; + $clip .= '-big.png'; + $top = '70px'; + } else { + $height = '48px'; + $width = '90%'; + $width_att = '8%'; + $clip .= '.png'; + $top = '20px'; + } +if (0) + $this->out->elementStart('div', 'entry-attachments'); +else + $this->out->elementStart('p', array('class' => 'entry-attachments', 'style' => "float: right; width: $width_att; background: url($clip) no-repeat; text-align: right; height: $height;")); + $this->out->element('a', array('class' => $att_class, 'style' => "text-decoration: none; padding-top: $top; display: block; height: $height;", 'href' => $href, 'title' => "# of attachments: $count"), $count === 1 ? '' : $count); + + + $this->out->elementEnd('p'); + } + + function showNoticeInfo() + { +if(0) + $this->out->elementStart('div', 'entry-content'); +else + + if ('shownotice' === $this->out->args['action']) { + $width = '85%'; + } else { + $width = '90%'; + } + + $this->out->elementStart('div', array('class' => 'entry-content', 'style' => "float: left; width: $width;")); + $this->showNoticeLink(); + $this->showNoticeSource(); + $this->showContext(); + $this->out->elementEnd('div'); + } + + function showNoticeOptions() + { + $user = common_current_user(); + if ($user) { +if(0) + $this->out->elementStart('div', 'notice-options'); +else + $this->out->elementStart('div', array('class' => 'notice-options', 'style' => 'float: right; width: 16%;')); + $this->showFaveForm(); + $this->showReplyLink(); + $this->showDeleteLink(); + $this->out->elementEnd('div'); + } + } + + /** + * start a single notice. + * + * @return void + */ + + function showStart() + { + // XXX: RDFa + // TODO: add notice_type class e.g., notice_video, notice_image + $this->out->elementStart('li', array('class' => 'hentry notice', + 'id' => 'notice-' . $this->notice->id)); + } + + /** + * show the "favorite" form + * + * @return void + */ + + function showFaveForm() + { $user = common_current_user(); - if ($user) { - if ($user->hasFave($this->notice)) { - common_disfavor_form($this->notice); - } else { - common_favor_form($this->notice); - } - } - } - - function show_author() { - common_element_start('span', 'vcard author'); - $this->show_avatar(); - $this->show_nickname(); - common_element_end('span'); - } - - function show_avatar() { - $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE); - common_element_start('a', array('href' => $this->profile->profileurl)); - common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE), - 'class' => 'avatar stream photo', - 'width' => AVATAR_STREAM_SIZE, - 'height' => AVATAR_STREAM_SIZE, - 'alt' => - ($this->profile->fullname) ? $this->profile->fullname : - $this->profile->nickname)); - common_element_end('a'); - } - - function show_nickname() { - common_element('a', array('href' => $this->profile->profileurl, - 'class' => 'nickname fn url'), - $this->profile->nickname); - } - - function show_content() { - # FIXME: URL, image, video, audio - common_element_start('p', array('class' => 'content entry-title')); - if ($this->notice->rendered) { - common_raw($this->notice->rendered); - } else { - # XXX: may be some uncooked notices in the DB, - # we cook them right now. This should probably disappear in future - # versions (>> 0.4.x) - common_raw(common_render_content($this->notice->content, $this->notice)); - } - common_element_end('p'); - } - - function show_start_time_section() { - common_element_start('p', 'time'); - } - - function show_notice_link() { - $noticeurl = common_local_url('shownotice', array('notice' => $this->notice->id)); - # XXX: we need to figure this out better. Is this right? - if (strcmp($this->notice->uri, $this->noticeurl) != 0 && preg_match('/^http/', $this->notice->uri)) { - $noticeurl = $this->notice->uri; - } - common_element_start('a', array('class' => 'permalink', - 'rel' => 'bookmark', - 'href' => $noticeurl)); - common_element('abbr', array('class' => 'published', - 'title' => common_date_iso8601($this->notice->created)), - common_date_string($this->notice->created)); - common_element_end('a'); - } - - function show_notice_source() { - if ($this->notice->source) { - common_text(_(' from ')); + if ($user) { + if ($user->hasFave($this->notice)) { + $disfavor = new DisfavorForm($this->out, $this->notice); + $disfavor->show(); + } else { + $favor = new FavorForm($this->out, $this->notice); + $favor->show(); + } + } + } + + /** + * show the author of a notice + * + * By default, this shows the avatar and (linked) nickname of the author. + * + * @return void + */ + + function showAuthor() + { + $this->out->elementStart('span', 'vcard author'); + $attrs = array('href' => $this->profile->profileurl, + 'class' => 'url'); + if (!empty($this->profile->fullname)) { + $attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ') '; + } + $this->out->elementStart('a', $attrs); + $this->showAvatar(); + $this->showNickname(); + $this->out->elementEnd('a'); + $this->out->elementEnd('span'); + } + + /** + * show the avatar of the notice's author + * + * This will use the default avatar if no avatar is assigned for the author. + * It makes a link to the author's profile. + * + * @return void + */ + + function showAvatar() + { + if ('shownotice' === $this->out->trimmed('action')) { + $avatar_size = AVATAR_PROFILE_SIZE; + } else { + $avatar_size = AVATAR_STREAM_SIZE; + } + $avatar = $this->profile->getAvatar($avatar_size); + + $this->out->element('img', array('src' => ($avatar) ? + $avatar->displayUrl() : + Avatar::defaultImage($avatar_size), + 'class' => 'avatar photo', + 'width' => $avatar_size, + 'height' => $avatar_size, + 'alt' => + ($this->profile->fullname) ? + $this->profile->fullname : + $this->profile->nickname)); + } + + /** + * show the nickname of the author + * + * Links to the author's profile page + * + * @return void + */ + + function showNickname() + { + $this->out->element('span', array('class' => 'nickname fn'), + $this->profile->nickname); + } + + /** + * show the content of the notice + * + * Shows the content of the notice. This is pre-rendered for efficiency + * at save time. Some very old notices might not be pre-rendered, so + * they're rendered on the spot. + * + * @return void + */ + + function showContent() + { + // FIXME: URL, image, video, audio + $this->out->elementStart('p', array('class' => 'entry-content')); + if ($this->notice->rendered) { + $this->out->raw($this->notice->rendered); + } else { + // XXX: may be some uncooked notices in the DB, + // we cook them right now. This should probably disappear in future + // versions (>> 0.4.x) + $this->out->raw(common_render_content($this->notice->content, $this->notice)); + } + $this->out->elementEnd('p'); + } + + /** + * show the link to the main page for the notice + * + * Displays a link to the page for a notice, with "relative" time. Tries to + * get remote notice URLs correct, but doesn't always succeed. + * + * @return void + */ + + function showNoticeLink() + { + $noticeurl = common_local_url('shownotice', + array('notice' => $this->notice->id)); + // XXX: we need to figure this out better. Is this right? + if (strcmp($this->notice->uri, $noticeurl) != 0 && + preg_match('/^http/', $this->notice->uri)) { + $noticeurl = $this->notice->uri; + } + $this->out->elementStart('dl', 'timestamp'); + $this->out->element('dt', null, _('Published')); + $this->out->elementStart('dd', null); + $this->out->elementStart('a', array('rel' => 'bookmark', + 'href' => $noticeurl)); + $dt = common_date_iso8601($this->notice->created); + $this->out->element('abbr', array('class' => 'published', + 'title' => $dt), + common_date_string($this->notice->created)); + $this->out->elementEnd('a'); + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); + } + + /** + * Show the source of the notice + * + * Either the name (and link) of the API client that posted the notice, + * or one of other other channels. + * + * @return void + */ + + function showNoticeSource() + { + if ($this->notice->source) { + $this->out->elementStart('dl', 'device'); + $this->out->element('dt', null, _('From')); $source_name = _($this->notice->source); - switch ($source) { + switch ($this->notice->source) { case 'web': case 'xmpp': case 'mail': case 'omb': + case 'system': case 'api': - common_element('span', 'noticesource', $source_name); + $this->out->element('dd', null, $source_name); break; default: $ns = Notice_source::staticGet($this->notice->source); if ($ns) { - common_element('a', array('href' => $ns->url), - $ns->name); + $this->out->elementStart('dd', null); + $this->out->element('a', array('href' => $ns->url, + 'rel' => 'external'), + $ns->name); + $this->out->elementEnd('dd'); } else { - common_element('span', 'noticesource', $source_name); + $this->out->element('dd', null, $source_name); } break; } - } + $this->out->elementEnd('dl'); + } } - function show_reply_to() { - if ($this->notice->reply_to) { - $replyurl = common_local_url('shownotice', array('notice' => $this->notice->reply_to)); - common_text(' ('); - common_element('a', array('class' => 'inreplyto', - 'href' => $replyurl), - _('in reply to...')); - common_text(')'); - } + /** + * show link to notice this notice is a reply to + * + * If this notice is a reply, show a link to the notice it is replying to. The + * heavy lifting for figuring out replies happens at save time. + * + * @return void + */ + + function showContext() + { + // XXX: also show context if there are replies to this notice + if (!empty($this->notice->conversation) + && $this->notice->conversation != $this->notice->id) { + $convurl = common_local_url('conversation', + array('id' => $this->notice->conversation)); + $this->out->elementStart('dl', 'response'); + $this->out->element('dt', null, _('To')); + $this->out->elementStart('dd'); + $this->out->element('a', array('href' => $convurl), + _('in context')); + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); + } } - function show_reply_link() { - common_element_start('a', - array('href' => common_local_url('newnotice', - array('replyto' => $this->profile->nickname)), - 'onclick' => 'return doreply("'.$this->profile->nickname.'", '.$this->notice->id.');', - 'title' => _('reply'), - 'class' => 'replybutton')); - common_raw('→'); - common_element_end('a'); + /** + * show a link to reply to the current notice + * + * Should either do the reply in the current notice form (if available), or + * link out to the notice-posting form. A little flakey, doesn't always work. + * + * @return void + */ + + function showReplyLink() + { + if (common_logged_in()) { + $reply_url = common_local_url('newnotice', + array('replyto' => $this->profile->nickname)); + + $this->out->elementStart('dl', 'notice_reply'); + $this->out->element('dt', null, _('Reply to this notice')); + $this->out->elementStart('dd'); + $this->out->elementStart('a', array('href' => $reply_url, + 'title' => _('Reply to this notice'))); + $this->out->text(_('Reply')); + $this->out->element('span', 'notice_id', $this->notice->id); + $this->out->elementEnd('a'); + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); + } } - function show_delete_link() { + /** + * if the user is the author, let them delete the notice + * + * @return void + */ + + function showDeleteLink() + { $user = common_current_user(); - if ($user && $this->notice->profile_id == $user->id) { - $deleteurl = common_local_url('deletenotice', array('notice' => $this->notice->id)); - common_element_start('a', array('class' => 'deletenotice', - 'href' => $deleteurl, - 'title' => _('delete'))); - common_raw('×'); - common_element_end('a'); - } + if ($user && $this->notice->profile_id == $user->id) { + $deleteurl = common_local_url('deletenotice', + array('notice' => $this->notice->id)); + $this->out->elementStart('dl', 'notice_delete'); + $this->out->element('dt', null, _('Delete this notice')); + $this->out->elementStart('dd'); + $this->out->element('a', array('href' => $deleteurl, + 'title' => _('Delete this notice')), _('Delete')); + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); + } } - function show_end_time_section() { - common_element_end('p'); - } + /** + * finish the notice + * + * Close the last elements in the notice list item + * + * @return void + */ - function show_end() { - common_element_end('li'); + function showEnd() + { + $this->out->elementEnd('li'); } }