]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Attachments and their list now provide "ajax" view. Also added a few sidebars relatin...
authorRobin Millette <millette@controlyourself.ca>
Fri, 15 May 2009 19:04:58 +0000 (15:04 -0400)
committerRobin Millette <millette@controlyourself.ca>
Fri, 15 May 2009 19:04:58 +0000 (15:04 -0400)
17 files changed:
actions/attachment.php [new file with mode: 0644]
actions/attachment_ajax.php [new file with mode: 0644]
actions/attachments.php [new file with mode: 0644]
actions/attachments_ajax.php [new file with mode: 0644]
actions/tag.php
classes/File.php
classes/File_oembed.php
classes/File_thumbnail.php
classes/Notice.php
js/jquery.joverlay.min.js [new file with mode: 0644]
js/util.js
lib/action.php
lib/attachmentlist.php [new file with mode: 0644]
lib/noticelist.php
lib/router.php
theme/base/images/icons/clip-big.png [new file with mode: 0644]
theme/base/images/icons/clip.png [new file with mode: 0644]

diff --git a/actions/attachment.php b/actions/attachment.php
new file mode 100644 (file)
index 0000000..981882a
--- /dev/null
@@ -0,0 +1,250 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Show notice attachments
+ *
+ * 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  Personal
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008-2009 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/personalgroupnav.php';
+//require_once INSTALLDIR.'/lib/feedlist.php';
+require_once INSTALLDIR.'/lib/attachmentlist.php';
+
+/**
+ * Show notice attachments
+ *
+ * @category Personal
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
+class AttachmentAction extends Action
+{
+    /**
+     * Attachment object to show
+     */
+
+    var $attachment = null;
+
+    /**
+     * Profile of the notice object
+     */
+
+//    var $profile = null;
+
+    /**
+     * Avatar of the profile of the notice object
+     */
+
+//    var $avatar = null;
+
+    /**
+     * Load attributes based on database arguments
+     *
+     * Loads all the DB stuff
+     *
+     * @param array $args $_REQUEST array
+     *
+     * @return success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $id = $this->arg('attachment');
+
+        $this->attachment = File::staticGet($id);
+
+        if (!$this->attachment) {
+            $this->clientError(_('No such attachment.'), 404);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Is this action read-only?
+     *
+     * @return boolean true
+     */
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * Title of the page
+     *
+     * @return string title of the page
+     */
+    function title()
+    {
+        $a = new Attachment($this->attachment);
+        return $a->title();
+    }
+
+
+
+    /**
+     * Last-modified date for page
+     *
+     * When was the content of this page last modified? Based on notice,
+     * profile, avatar.
+     *
+     * @return int last-modified date as unix timestamp
+     */
+/*
+    function lastModified()
+    {
+        return max(strtotime($this->notice->created),
+                   strtotime($this->profile->modified),
+                   ($this->avatar) ? strtotime($this->avatar->modified) : 0);
+    }
+*/
+
+    /**
+     * An entity tag for this page
+     *
+     * Shows the ETag for the page, based on the notice ID and timestamps
+     * for the notice, profile, and avatar. It's weak, since we change
+     * the date text "one hour ago", etc.
+     *
+     * @return string etag
+     */
+/*
+    function etag()
+    {
+        $avtime = ($this->avatar) ?
+          strtotime($this->avatar->modified) : 0;
+
+        return 'W/"' . implode(':', array($this->arg('action'),
+                                          common_language(),
+                                          $this->notice->id,
+                                          strtotime($this->notice->created),
+                                          strtotime($this->profile->modified),
+                                          $avtime)) . '"';
+    }
+*/
+
+
+    /**
+     * Handle input
+     *
+     * Only handles get, so just show the page.
+     *
+     * @param array $args $_REQUEST data (unused)
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    /**
+     * Don't show local navigation
+     *
+     * @return void
+     */
+
+    function showLocalNavBlock()
+    {
+    }
+
+    /**
+     * Fill the content area of the page
+     *
+     * Shows a single notice list item.
+     *
+     * @return void
+     */
+
+    function showContent()
+    {
+        $this->elementStart('ul', array('class' => 'attachments'));
+        $ali = new Attachment($this->attachment, $this);
+        $cnt = $ali->show();
+        $this->elementEnd('ul');
+    }
+
+    /**
+     * Don't show page notice
+     *
+     * @return void
+     */
+
+    function showPageNoticeBlock()
+    {
+    }
+
+    /**
+     * Show aside: this attachments appears in what notices
+     *
+     * @return void
+     */
+
+    function showAside() {
+        $notice = new Notice;
+        $f2p = new File_to_post;
+        $f2p->file_id = $this->attachment->id;
+        $notice->joinAdd($f2p);
+        $notice->orderBy('created desc');
+        $x = $notice->find();
+        $this->elementStart('ol');
+        while($notice->fetch()) {
+            $this->elementStart('li');
+            $profile = $notice->getProfile();
+            $this->element('a', array('href' => $notice->uri), $profile->nickname . ' on ' . $notice->created);
+            $this->elementEnd('li');
+        }
+        $this->elementEnd('ol');
+        $notice->free();
+        $f2p->free();
+
+        $notice_tag = new Notice_tag;
+        $attachment = new File;
+
+        $query = 'select tag,count(tag) as c from notice_tag join file_to_post on (notice_tag.notice_id=post_id) join notice on notice_id = notice.id where file_id=' . $notice_tag->escape($this->attachment->id) . ' group by tag order by c desc';
+
+        $notice_tag->query($query);
+        $this->elementStart('ol');
+        while($notice_tag->fetch()) {
+            $this->elementStart('li');
+            $href = common_local_url('tag', array('tag' => $notice_tag->tag));
+            $this->element('a', array('href' => $href), $notice_tag->tag . ' (' . $notice_tag->c . ')');
+            $this->elementEnd('li');
+        }
+        $this->elementEnd('ol');
+    }
+}
diff --git a/actions/attachment_ajax.php b/actions/attachment_ajax.php
new file mode 100644 (file)
index 0000000..1620b27
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Show notice attachments
+ *
+ * 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  Personal
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008-2009 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.'/actions/attachment.php';
+
+/**
+ * Show notice attachments
+ *
+ * @category Personal
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
+class Attachment_ajaxAction extends AttachmentAction
+{
+    /**
+     * Load attributes based on database arguments
+     *
+     * Loads all the DB stuff
+     *
+     * @param array $args $_REQUEST array
+     *
+     * @return success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        if (!$this->attachment) {
+            $this->clientError(_('No such attachment.'), 404);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Show page, a template method.
+     *
+     * @return nothing
+     */
+    function showPage()
+    {
+        if (Event::handle('StartShowBody', array($this))) {
+            $this->showCore();
+            Event::handle('EndShowBody', array($this));
+        }
+    }
+
+    /**
+     * Show core.
+     *
+     * Shows local navigation, content block and aside.
+     *
+     * @return nothing
+     */
+    function showCore()
+    {
+        $this->elementStart('div', array('id' => 'core'));
+        if (Event::handle('StartShowContentBlock', array($this))) {
+            $this->showContentBlock();
+            Event::handle('EndShowContentBlock', array($this));
+        }
+        $this->elementEnd('div');
+    }
+
+
+
+    /**
+     * Last-modified date for page
+     *
+     * When was the content of this page last modified? Based on notice,
+     * profile, avatar.
+     *
+     * @return int last-modified date as unix timestamp
+     */
+/*
+    function lastModified()
+    {
+        return max(strtotime($this->notice->created),
+                   strtotime($this->profile->modified),
+                   ($this->avatar) ? strtotime($this->avatar->modified) : 0);
+    }
+*/
+
+    /**
+     * An entity tag for this page
+     *
+     * Shows the ETag for the page, based on the notice ID and timestamps
+     * for the notice, profile, and avatar. It's weak, since we change
+     * the date text "one hour ago", etc.
+     *
+     * @return string etag
+     */
+/*
+    function etag()
+    {
+        $avtime = ($this->avatar) ?
+          strtotime($this->avatar->modified) : 0;
+
+        return 'W/"' . implode(':', array($this->arg('action'),
+                                          common_language(),
+                                          $this->notice->id,
+                                          strtotime($this->notice->created),
+                                          strtotime($this->profile->modified),
+                                          $avtime)) . '"';
+    }
+*/
+}
+
diff --git a/actions/attachments.php b/actions/attachments.php
new file mode 100644 (file)
index 0000000..6b31c83
--- /dev/null
@@ -0,0 +1,292 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Show notice attachments
+ *
+ * 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  Personal
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008-2009 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/personalgroupnav.php';
+//require_once INSTALLDIR.'/lib/feedlist.php';
+require_once INSTALLDIR.'/lib/attachmentlist.php';
+
+/**
+ * Show notice attachments
+ *
+ * @category Personal
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
+class AttachmentsAction extends Action
+{
+    /**
+     * Notice object to show
+     */
+
+    var $notice = null;
+
+    /**
+     * Profile of the notice object
+     */
+
+    var $profile = null;
+
+    /**
+     * Avatar of the profile of the notice object
+     */
+
+    var $avatar = null;
+
+    /**
+     * Is this action read-only?
+     *
+     * @return boolean true
+     */
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * Last-modified date for page
+     *
+     * When was the content of this page last modified? Based on notice,
+     * profile, avatar.
+     *
+     * @return int last-modified date as unix timestamp
+     */
+
+    function lastModified()
+    {
+        return max(strtotime($this->notice->created),
+                   strtotime($this->profile->modified),
+                   ($this->avatar) ? strtotime($this->avatar->modified) : 0);
+    }
+
+    /**
+     * An entity tag for this page
+     *
+     * Shows the ETag for the page, based on the notice ID and timestamps
+     * for the notice, profile, and avatar. It's weak, since we change
+     * the date text "one hour ago", etc.
+     *
+     * @return string etag
+     */
+
+    function etag()
+    {
+        $avtime = ($this->avatar) ?
+          strtotime($this->avatar->modified) : 0;
+
+        return 'W/"' . implode(':', array($this->arg('action'),
+                                          common_language(),
+                                          $this->notice->id,
+                                          strtotime($this->notice->created),
+                                          strtotime($this->profile->modified),
+                                          $avtime)) . '"';
+    }
+
+    /**
+     * Title of the page
+     *
+     * @return string title of the page
+     */
+
+    function title()
+    {
+        return sprintf(_('%1$s\'s status on %2$s'),
+                       $this->profile->nickname,
+                       common_exact_date($this->notice->created));
+    }
+
+
+    /**
+     * Load attributes based on database arguments
+     *
+     * Loads all the DB stuff
+     *
+     * @param array $args $_REQUEST array
+     *
+     * @return success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $id = $this->arg('notice');
+
+        $this->notice = Notice::staticGet($id);
+
+        if (!$this->notice) {
+            $this->clientError(_('No such notice.'), 404);
+            return false;
+        }
+
+
+/*
+// STOP if there are no attachments
+// maybe even redirect if there's a single one
+// RYM FIXME TODO
+            $this->clientError(_('No such attachment.'), 404);
+            return false;
+
+*/
+
+
+
+
+        $this->profile = $this->notice->getProfile();
+
+        if (!$this->profile) {
+            $this->serverError(_('Notice has no profile'), 500);
+            return false;
+        }
+
+        $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
+        return true;
+    }
+
+
+
+    /**
+     * Handle input
+     *
+     * Only handles get, so just show the page.
+     *
+     * @param array $args $_REQUEST data (unused)
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+
+        if ($this->notice->is_local == 0) {
+            if (!empty($this->notice->url)) {
+                common_redirect($this->notice->url, 301);
+            } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
+                common_redirect($this->notice->uri, 301);
+            }
+        } else {
+            $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) {
+                common_redirect(common_local_url('attachment', array('attachment' => $file->id)), 301);
+            } else {
+                $this->showPage();
+            }
+        }
+    }
+
+    /**
+     * Don't show local navigation
+     *
+     * @return void
+     */
+
+    function showLocalNavBlock()
+    {
+    }
+
+    /**
+     * Fill the content area of the page
+     *
+     * Shows a single notice list item.
+     *
+     * @return void
+     */
+
+    function showContent()
+    {
+        $al = new AttachmentList($this->notice, $this);
+        $cnt = $al->show();
+    }
+
+    /**
+     * Don't show page notice
+     *
+     * @return void
+     */
+
+    function showPageNoticeBlock()
+    {
+    }
+
+    /**
+     * Don't show aside
+     *
+     * @return void
+     */
+
+    function showAside() {
+    }
+
+    /**
+     * Extra <head> content
+     *
+     * We show the microid(s) for the author, if any.
+     *
+     * @return void
+     */
+
+    function extraHead()
+    {
+        $user = User::staticGet($this->profile->id);
+
+        if (!$user) {
+            return;
+        }
+
+        if ($user->emailmicroid && $user->email && $this->notice->uri) {
+            $id = new Microid('mailto:'. $user->email,
+                              $this->notice->uri);
+            $this->element('meta', array('name' => 'microid',
+                                         'content' => $id->toString()));
+        }
+
+        if ($user->jabbermicroid && $user->jabber && $this->notice->uri) {
+            $id = new Microid('xmpp:', $user->jabber,
+                              $this->notice->uri);
+            $this->element('meta', array('name' => 'microid',
+                                         'content' => $id->toString()));
+        }
+    }
+}
+
diff --git a/actions/attachments_ajax.php b/actions/attachments_ajax.php
new file mode 100644 (file)
index 0000000..402d8b5
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Show notice attachments
+ *
+ * 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  Personal
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008-2009 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/personalgroupnav.php';
+//require_once INSTALLDIR.'/lib/feedlist.php';
+require_once INSTALLDIR.'/actions/attachments.php';
+
+/**
+ * Show notice attachments
+ *
+ * @category Personal
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
+class Attachments_ajaxAction extends AttachmentsAction
+{
+    function showContent()
+    {
+    }
+
+    /**
+     * Fill the content area of the page
+     *
+     * Shows a single notice list item.
+     *
+     * @return void
+     */
+
+    function showContentBlock()
+    {
+        $al = new AttachmentList($this->notice, $this);
+        $cnt = $al->show();
+    }
+
+    /**
+     * Extra <head> content
+     *
+     * We show the microid(s) for the author, if any.
+     *
+     * @return void
+     */
+
+    function extraHead()
+    {
+    }
+
+
+    /**
+     * Show page, a template method.
+     *
+     * @return nothing
+     */
+    function showPage()
+    {
+        if (Event::handle('StartShowBody', array($this))) {
+            $this->showCore();
+            Event::handle('EndShowBody', array($this));
+        }
+    }
+
+    /**
+     * Show core.
+     *
+     * Shows local navigation, content block and aside.
+     *
+     * @return nothing
+     */
+    function showCore()
+    {
+        $this->elementStart('div', array('id' => 'core'));
+        if (Event::handle('StartShowContentBlock', array($this))) {
+            $this->showContentBlock();
+            Event::handle('EndShowContentBlock', array($this));
+        }
+        $this->elementEnd('div');
+    }
+
+
+
+
+}
+
index 02f3e35225cca6976fc7efe5a8b0930b346664eb..2202f9bb07041e713ced894331f3232795f84b23 100644 (file)
@@ -49,8 +49,18 @@ class TagAction extends Action
     {
         $pop = new PopularNoticeSection($this);
         $pop->show();
-    }
 
+        $notice_tag = new Notice_tag;
+        $query = 'select file_id, count(file_id) as c from notice_tag join file_to_post on post_id = notice_id where tag="' . $notice_tag->escape($this->tag) . '" group by file_id order by c desc';
+        $notice_tag->query($query);
+        $this->elementStart('ol');
+        while ($notice_tag->fetch()) {
+            $this->elementStart('li');
+            $this->element('a', array('class' => 'attachment', 'href' => common_local_url('attachment', array('attachment' => $notice_tag->file_id))), "Attachment tagged {$notice_tag->c} times");
+            $this->elementEnd('li');
+        }
+        $this->elementEnd('ol');
+    }
 
     function title()
     {
index 2ddc5deb8b69446230e953a5ed20b947f7e01ca7..e5913115b7a3ed5a47bf473a30464b66dcfa3d69 100644 (file)
@@ -54,6 +54,17 @@ class File extends Memcached_DataObject
         return 'http://www.facebook.com/login.php' === $url;
     }
 
+    function getAttachments($post_id) {
+        $query = "select file.* from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $this->escape($post_id);
+        $this->query($query);
+        $att = array();
+        while ($this->fetch()) {
+            $att[] = clone($this);
+        }
+        $this->free();
+        return $att;
+    }
+
     function saveNew($redir_data, $given_url) {
         $x = new File;
         $x->url = $given_url;
index 2846f49dbcf6ecbaa6331d28bcb742028ddd9b51..f1b2cb13c02d90a0b50f2c8bf7e2b0c4d522ebda 100644 (file)
@@ -78,18 +78,9 @@ class File_oembed extends Memcached_DataObject
         if (!empty($data['author_url'])) $file_oembed->author_url = $data['author_url'];
         if (!empty($data['url'])) $file_oembed->url = $data['url'];
         $file_oembed->insert();
-
         if (!empty($data['thumbnail_url'])) {
-            $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->insert();
+            File_thumbnail::saveNew($data, $file_id);
         }
-
-
-        
     }
 }
 
index 7b906a07caaae5f6f24d04e700a1d99dcb0955dd..1a65b92c9018dc2464e82e3a9beb294bbd395cd9 100644 (file)
@@ -42,4 +42,14 @@ class File_thumbnail extends Memcached_DataObject
 
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
+
+    function saveNew($data, $file_id) {
+        $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->insert();
+    }
 }
+
index c2fa2d19e5e84bbf394f81706ea07a1a8700cbed..30508070e53320b7783c898747c45aa2bc8e6e16 100644 (file)
@@ -124,8 +124,6 @@ class Notice extends Memcached_DataObject
 
         $profile = Profile::staticGet($profile_id);
 
-//        $final =  common_shorten_links($content);
-
         if (!$profile) {
             common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
             return _('Problem saving notice. Unknown user.');
@@ -279,6 +277,16 @@ class Notice extends Memcached_DataObject
         return true;
     }
 
+    function hasAttachments() {
+        $post = clone($this);
+        $query = "select count(file_id) as n_attachments from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $post->escape($this->id);
+        $post->query($query);
+        $post->fetch();
+        $n_attachments = intval($post->n_attachments);
+        $post->free();
+        return $n_attachments;
+    }
+
     function blowCaches($blowLast=false)
     {
         $this->blowSubsCache($blowLast);
diff --git a/js/jquery.joverlay.min.js b/js/jquery.joverlay.min.js
new file mode 100644 (file)
index 0000000..c916850
--- /dev/null
@@ -0,0 +1,6 @@
+/* Copyright (c) 2009 Alvaro A. Lima Jr http://alvarojunior.com/jquery/joverlay.html
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * Version: 0.6 (Abr 23, 2009)
+ * Requires: jQuery 1.3+
+ */
+(function($){var f=$.browser.msie&&$.browser.version==6.0;var g=null;$.fn.jOverlay=function(b){var b=$.extend({},$.fn.jOverlay.options,b);if(g!=null){clearTimeout(g)}var c=this.is('*')?this:'#jOverlayContent';var d=f?'absolute':'fixed';var e=b.imgLoading?"<img id='jOverlayLoading' src='"+b.imgLoading+"' style='position:"+d+"; z-index:"+(b.zIndex+9)+";'/>":'';$('body').prepend(e+"<div id='jOverlay' />"+"<div id='jOverlayContent' style='position:"+d+"; z-index:"+(b.zIndex+5)+"; display:none;'/>");$('#jOverlayLoading').load(function(){if(b.center){$.center(this)}});if(f){$("select").hide();$("#jOverlayContent select").show()}$('#jOverlay').css({backgroundColor:b.color,position:d,top:'0px',left:'0px',filter:'alpha(opacity='+(b.opacity*100)+')',opacity:b.opacity,zIndex:b.zIndex,width:!f?'100%':$(window).width()+'px',height:!f?'100%':$(document).height()+'px'}).show();if(this.is('*')){$('#jOverlayContent').html(this.addClass('jOverlayChildren').show()).show();if(b.center){$.center('#jOverlayContent')}if(!b.url&&$.isFunction(b.success)){b.success(this.html())}}if(b.url){$.ajax({type:b.method,data:b.data,url:b.url,success:function(a){$('#jOverlayLoading').fadeOut(600);$(c).html(a).show();if(b.center){$.center('#jOverlayContent')}if($.isFunction(b.success)){b.success(a)}}})}if(f){$(window).scroll(function(){if(b.center){$.center('#jOverlayContent')}});$(window).resize(function(){$('#jOverlay').css({width:$(window).width()+'px',height:$(document).height()+'px'});if(b.center){$.center('#jOverlayContent')}})}$(document).keydown(function(a){if(a.keyCode==27){$.closeOverlay()}});if(b.bgClickToClose){$('#jOverlay').click($.closeOverlay)}if(Number(b.timeout)>0){g=setTimeout($.closeOverlay,Number(b.timeout))}};$.center=function(a){var a=$(a);var b=a.height();var c=a.width();a.css({width:c+'px',marginLeft:'-'+(c/2)+'px',marginTop:'-'+b/2+'px',height:'auto',top:!f?'50%':$(window).scrollTop()+($(window).height()/2)+"px",left:'50%'})};$.fn.jOverlay.options={method:'GET',data:'',url:'',color:'#000',opacity:'0.6',zIndex:9999,center:true,imgLoading:'',bgClickToClose:true,success:null,timeout:0};$.closeOverlay=function(){if(f){$("select").show()}$('#jOverlayContent .jOverlayChildren').hide().prependTo($('body'));$('#jOverlayLoading, #jOverlayContent, #jOverlay').remove()}})(jQuery);
\ No newline at end of file
index 3f14bc61c6d831d35a822c704a637f702b4beda9..31d9eb4f54706a09a384ca2cf0604ae7904373ef 100644 (file)
  */
 
 $(document).ready(function(){
+    $('.attachments').click(function() {$().jOverlay({zIndex:999, success:function(html) {$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
+        }, url:$(this).attr('href') + '/ajax'}); return false; });
+    $('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
+
        // count character on keyup
        function counter(event){
                var maxLength = 140;
index 3e43ffe3e3ee1427d53c571ee4fb52b639b31aa6..fc123a6332933976e2b064a608467847645b35a3 100644 (file)
@@ -98,15 +98,15 @@ class Action extends HTMLOutputter // lawsuit
             Event::handle('EndShowHTML', array($this));
         }
         if (Event::handle('StartShowHead', array($this))) {
-        $this->showHead();
+            $this->showHead();
             Event::handle('EndShowHead', array($this));
         }
         if (Event::handle('StartShowBody', array($this))) {
-        $this->showBody();
+            $this->showBody();
             Event::handle('EndShowBody', array($this));
         }
         if (Event::handle('StartEndHTML', array($this))) {
-        $this->endHTML();
+            $this->endHTML();
             Event::handle('EndEndHTML', array($this));
         }
     }
@@ -243,6 +243,12 @@ class Action extends HTMLOutputter // lawsuit
                 $this->element('script', array('type' => 'text/javascript',
                                                'src' => common_path('js/jquery.form.js')),
                                ' ');
+
+                $this->element('script', array('type' => 'text/javascript',
+                                               'src' => common_path('js/jquery.joverlay.min.js')),
+                               ' ');
+
+
                 Event::handle('EndShowJQueryScripts', array($this));
             }
             if (Event::handle('StartShowLaconicaScripts', array($this))) {
diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php
new file mode 100644 (file)
index 0000000..9485fe3
--- /dev/null
@@ -0,0 +1,300 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * widget for displaying a list of notice attachments
+ *
+ * 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   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @author    Sarven Capadisli <csarven@controlyourself.ca>
+ * @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);
+}
+
+/**
+ * widget for displaying a list of notice attachments
+ *
+ * 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 <evan@controlyourself.ca>
+ * @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
+ */
+
+class AttachmentList extends Widget
+{
+    /** the current stream of notices being displayed. */
+
+    var $notice = null;
+
+    /**
+     * constructor
+     *
+     * @param Notice $notice stream of notices from DB_DataObject
+     */
+
+    function __construct($notice, $out=null)
+    {
+        parent::__construct($out);
+        $this->notice = $notice;
+    }
+
+    /**
+     * 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.
+     */
+
+    function show()
+    {
+//        $this->out->elementStart('div', array('id' =>'attachments_primary'));
+        $this->out->elementStart('div', array('id' =>'content'));
+        $this->out->element('h2', null, _('Attachments'));
+        $this->out->elementStart('ul', array('class' => 'attachments'));
+
+        $atts = new File;
+        $att = $atts->getAttachments($this->notice->id);
+        foreach ($att as $n=>$attachment) {
+            $item = $this->newListItem($attachment);
+            $item->show();
+        }
+
+        $this->out->elementEnd('ul');
+        $this->out->elementEnd('div');
+
+        return count($att);
+    }
+
+    /**
+     * 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($attachment)
+    {
+        return new AttachmentListItem($attachment, $this->out);
+    }
+}
+
+/**
+ * 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 <evan@controlyourself.ca>
+ * @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
+ */
+
+class AttachmentListItem extends Widget
+{
+    /** The attachment this item will show. */
+
+    var $attachment = null;
+
+    var $oembed = null;
+
+    /**
+     * constructor
+     *
+     * Also initializes the profile attribute.
+     *
+     * @param Notice $notice The notice we'll display
+     */
+
+    function __construct($attachment, $out=null)
+    {
+        parent::__construct($out);
+        $this->attachment  = $attachment;
+        $this->oembed = File_oembed::staticGet('file_id', $this->attachment->id);
+    }
+
+    function title() {
+        if (empty($this->attachment->title)) {
+            if (empty($this->oembed->title)) {
+                $title = $this->attachment->url;
+            } else {
+                $title = $this->oembed->title;
+            }
+        } else {
+            $title = $this->attachment->title;
+        }
+
+        return $title;
+    }
+
+    function linkTitle() {
+        return 'Our page for ' . $this->title();
+    }
+
+    /**
+     * 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->showNoticeAttachment();
+        $this->showEnd();
+    }
+
+    function linkAttr() {
+        return array('class' => 'attachment', 'href' => common_local_url('attachment', array('attachment' => $this->attachment->id)));
+    }
+
+    function showLink() {
+        $attr = $this->linkAttr();
+        $text = $this->linkTitle();
+        $this->out->elementStart('h4');
+        $this->out->element('a', $attr, $text);
+
+        if ($this->attachment->url !== $this->title())
+            $this->out->element('span', null, " ({$this->attachment->url})");
+
+
+        $this->out->elementEnd('h4');
+    }
+
+    function showNoticeAttachment()
+    {
+        $this->showLink();
+        $this->showRepresentation();
+    }
+
+    function showRepresentation() {
+        $thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
+        if (!empty($thumbnail)) {
+            $this->out->elementStart('a', $this->linkAttr()/*'href' => $this->linkTo()*/);
+            $this->out->element('img', array('alt' => 'nothing to say', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height));
+            $this->out->elementEnd('a');
+        }
+    }
+
+    /**
+     * 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');
+    }
+
+    /**
+     * finish the notice
+     *
+     * Close the last elements in the notice list item
+     *
+     * @return void
+     */
+
+    function showEnd()
+    {
+        $this->out->elementEnd('li');
+    }
+}
+
+class Attachment extends AttachmentListItem
+{
+    function show() {
+        $this->showNoticeAttachment();
+    }
+
+    function linkAttr() {
+        return array('class' => 'external', 'href' => $this->attachment->url);
+    }
+
+    function linkTitle() {
+        return 'Direct link to ' . $this->title();
+    }
+
+    function showRepresentation() {
+        if (empty($this->oembed->type)) {
+            if (empty($this->attachment->mimetype)) {
+                $this->out->element('pre', null, 'oh well... not sure how to handle the following: ' . print_r($this->attachment, true));
+            } else {
+                switch ($this->attachment->mimetype) {
+                case 'image/gif':
+                case 'image/png':
+                case 'image/jpg':
+                case 'image/jpeg':
+                    $this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
+                    break;
+                }
+            }
+        } else {
+            switch ($this->oembed->type) {
+            case 'rich':
+            case 'video':
+            case 'link':
+                if (!empty($this->oembed->html)) {
+                    $this->out->raw($this->oembed->html);
+                }
+                break;
+
+            case 'photo':
+                $this->out->element('img', array('src' => $this->oembed->url, 'width' => $this->oembed->width, 'height' => $this->oembed->height, 'alt' => 'alt'));
+                break;
+
+            default:
+                $this->out->element('pre', null, 'oh well... not sure how to handle the following oembed: ' . print_r($this->oembed, true));
+            }
+        }
+    }
+}
+
index 8fccba73e1c93788926f671b9c2193d0d7a5dcf0..55dd902b4a3def0933b3c7a2fed3d431dd4d661c 100644 (file)
@@ -179,22 +179,86 @@ class NoticeListItem extends Widget
     {
         $this->showStart();
         $this->showNotice();
-        $this->showNoticeInfo();
+        $this->showNoticeAttachments();
         $this->showNoticeOptions();
+        $this->showNoticeInfo();
         $this->showEnd();
     }
 
     function showNotice()
     {
-        $this->out->elementStart('div', 'entry-title');
+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();
@@ -205,7 +269,10 @@ class NoticeListItem extends Widget
     {
         $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();
index 9308c818a4bf2e0f65824dcdd5203ad1d4ede2af..635e1d77e09dddde427d2e9d1c8a971bc0683250 100644 (file)
@@ -151,12 +151,26 @@ class Router
         $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
                     array('q' => '.+'));
 
+        $m->connect('attachment/:attachment/ajax',
+                    array('action' => 'attachment_ajax'),
+                    array('notice' => '[0-9]+'));
+
+        $m->connect('attachment/:attachment',
+                    array('action' => 'attachment'),
+                    array('notice' => '[0-9]+'));
+
         // notice
 
         $m->connect('notice/new', array('action' => 'newnotice'));
         $m->connect('notice/new?replyto=:replyto',
                     array('action' => 'newnotice'),
                     array('replyto' => '[A-Za-z0-9_-]+'));
+        $m->connect('notice/:notice/attachments/ajax',
+                    array('action' => 'attachments_ajax'),
+                    array('notice' => '[0-9]+'));
+        $m->connect('notice/:notice/attachments',
+                    array('action' => 'attachments'),
+                    array('notice' => '[0-9]+'));
         $m->connect('notice/:notice',
                     array('action' => 'shownotice'),
                     array('notice' => '[0-9]+'));
diff --git a/theme/base/images/icons/clip-big.png b/theme/base/images/icons/clip-big.png
new file mode 100644 (file)
index 0000000..3945f56
Binary files /dev/null and b/theme/base/images/icons/clip-big.png differ
diff --git a/theme/base/images/icons/clip.png b/theme/base/images/icons/clip.png
new file mode 100644 (file)
index 0000000..3c5a17d
Binary files /dev/null and b/theme/base/images/icons/clip.png differ