Browse Source

Working implementation of the Reply feature of XEP-0277

pull/277/head
Jaussoin Timothée 9 years ago
parent
commit
a4fae1f3db
  1. 32
      app/models/postn/Postn.php
  2. 10
      app/models/postn/PostnDAO.php
  3. 10
      app/widgets/Menu/Menu.php
  4. 28
      app/widgets/Menu/_menu_list.tpl
  5. 58
      app/widgets/Post/Post.php
  6. 104
      app/widgets/Post/_post.tpl
  7. 19
      app/widgets/Publish/Publish.php
  8. 5
      app/widgets/Publish/_publish_create.tpl
  9. 4
      composer.json
  10. 37
      composer.lock
  11. 1
      locales/locales.ini
  12. 11
      themes/material/css/listn.css

32
app/models/postn/Postn.php

@ -32,6 +32,8 @@ class Postn extends Model {
public $links;
public $reply;
public $hash;
private $youtube;
@ -80,6 +82,9 @@ class Postn extends Model {
"delay" :
{"type":"date" },
"reply" :
{"type":"text" },
"lat" :
{"type":"string", "size":32 },
"lon" :
@ -273,6 +278,19 @@ class Postn extends Model {
if($this->isMicroblog() && empty($this->aid)) {
$this->__set('aid', $this->origin);
}
// We check if this is a reply
if($entry->entry->{'in-reply-to'}) {
$href = (string)$entry->entry->{'in-reply-to'}->attributes()->href;
$arr = explode(';', $href);
$reply = [
'origin' => substr($arr[0], 5, -1),
'node' => substr($arr[1], 5),
'nodeid' => substr($arr[2], 5)
];
$this->__set('reply', serialize($reply));
}
}
private function typeIsPicture($type) {
@ -473,6 +491,20 @@ class Postn extends Model {
return (strlen($this->contentcleaned) < 700);
}
public function isReply()
{
return isset($this->reply);
}
public function getReply()
{
if(!$this->reply) return;
$reply = unserialize($this->reply);
$pd = new \Modl\PostnDAO;
return $pd->get($reply['origin'], $reply['node'], $reply['nodeid']);
}
public function getPublicUrl()
{
return $this->openlink;

10
app/models/postn/PostnDAO.php

@ -24,6 +24,8 @@ class PostnDAO extends SQL {
updated = :updated,
delay = :delay,
reply = :reply,
lat = :lat,
lon = :lon,
@ -57,6 +59,8 @@ class PostnDAO extends SQL {
'updated' => $post->updated,
'delay' => $post->delay,
'reply' => $post->reply,
'lat' => $post->lat,
'lon' => $post->lon,
@ -99,6 +103,8 @@ class PostnDAO extends SQL {
updated,
delay,
reply,
lat,
lon,
@ -129,6 +135,8 @@ class PostnDAO extends SQL {
:updated,
:delay,
:reply,
:lat,
:lon,
@ -159,6 +167,8 @@ class PostnDAO extends SQL {
'updated' => $post->updated,
'delay' => $post->delay,
'reply' => $post->reply,
'lat' => $post->lat,
'lon' => $post->lon,

10
app/widgets/Menu/Menu.php

@ -10,10 +10,20 @@ class Menu extends \Movim\Widget\Base
{
$this->registerEvent('post', 'onPost');
$this->registerEvent('post_retract', 'onRetract');
$this->registerEvent('pubsub_postdelete', 'onRetract');
$this->registerEvent('pubsub_getitem_handle', 'onHandle');
$this->addjs('menu.js');
$this->addcss('menu.css');
}
function onHandle($packet)
{
if($packet->content['nodeid']) {
$this->onRetract($packet);
}
}
function onRetract($packet)
{
$this->ajaxGetAll();

28
app/widgets/Menu/_menu_list.tpl

@ -87,6 +87,34 @@
<p class="line">{$c->__('menu.contact_post')}</p>
{/if}
<p>{$value->contentcleaned|stripTags}</p>
{if="$value->isReply()"}
{$reply = $value->getReply()}
<ul class="list card">
<li class="block">
{if="$reply"}
<p class="line">{$reply->title}</p>
<p>{$reply->contentcleaned|stripTags}</p>
<p>
{if="$reply->isMicroblog()"}
<i class="zmdi zmdi-account"></i> {$reply->getContact()->getTrueName()}
{else}
<i class="zmdi zmdi-pages"></i> {$reply->node}
{/if}
<span class="info">
{$reply->published|strtotime|prepareDate:true,true}
</span>
</p>
{else}
<span class="primary icon gray">
<i class="zmdi zmdi-info-outline"></i>
</span>
<p class="line normal">{$c->__('post.original_deleted')}</p>
{/if}
</li>
</ul>
{/if}
<p>
{if="$value->isMicroblog()"}
<a href="{$c->route('contact', $value->getContact()->jid)}">

58
app/widgets/Post/Post.php

@ -20,6 +20,8 @@ class Post extends \Movim\Widget\Base
$this->registerEvent('microblog_commentsget_error', 'onCommentsError');
$this->registerEvent('pubsub_postpublish_handle', 'onPublish');
$this->registerEvent('pubsub_postdelete_handle', 'onDelete');
$this->registerEvent('pubsub_postdelete', 'onDelete');
$this->registerEvent('pubsub_getitem_handle', 'onHandle');
}
function onPublish($packet)
@ -29,6 +31,25 @@ class Post extends \Movim\Widget\Base
RPC::call('MovimTpl.hidePanel');
}
function onHandle($packet)
{
$content = $packet->content;
if($content['nodeid']) {
$pd = new \Modl\PostnDAO;
$p = $pd->get($content['origin'], $content['node'], $content['nodeid']);
if($p) {
$html = $this->preparePost($p);
RPC::call('MovimUtils.pushState', $this->route('news', [$p->origin, $p->node, $p->nodeid]));
RPC::call('MovimTpl.fill', '#post_widget', $html);
RPC::call('MovimUtils.enableVideos');
}
}
}
function onCommentPublished($packet)
{
Notification::append(false, $this->__('post.comment_published'));
@ -97,18 +118,35 @@ class Post extends \Movim\Widget\Base
$pd = new \Modl\PostnDAO;
$p = $pd->get($origin, $node, $id);
$gi = new GetItem;
$gi->setTo($p->origin)
->setNode($p->node)
->setId($p->nodeid)
->request();
if($p) {
$html = $this->preparePost($p);
RPC::call('MovimUtils.pushState', $this->route('news', [$p->origin, $p->node, $p->nodeid]));
$html = $this->preparePost($p);
RPC::call('MovimTpl.fill', '#post_widget', $html);
RPC::call('MovimUtils.enableVideos');
RPC::call('MovimUtils.pushState', $this->route('news', [$p->origin, $p->node, $p->nodeid]));
// If the post is a reply but we don't have the original
if($p->isReply() && !$p->getReply()) {
$reply = unserialize($p->reply);
RPC::call('MovimTpl.fill', '#post_widget', $html);
RPC::call('MovimUtils.enableVideos');
$gi = new GetItem;
$gi->setTo($reply['origin'])
->setNode($reply['node'])
->setId($reply['nodeid'])
->setAskReply([
'origin' => $p->origin,
'node' => $p->node,
'nodeid' => $p->nodeid])
->request();
}
$gi = new GetItem;
$gi->setTo($p->origin)
->setNode($p->node)
->setId($p->nodeid)
->request();
}
}
function ajaxDelete($to, $node, $id)
@ -197,6 +235,8 @@ class Post extends \Movim\Widget\Base
$view->assign('external', $external);
$view->assign('public', $public);
$view->assign('reply', $p->isReply() ? $p->getReply() : false);
// Is it a repost ?
if($p->isRecycled()) {
$cd = new \Modl\ContactDAO;

104
app/widgets/Post/_post.tpl

@ -130,32 +130,31 @@
{if="!$external && !$public"}
<article class="block">
{/if}
{if="$repost"}
<a href="{$c->route('contact', $post->getContact()->jid)}">
<ul class="list active middle">
<li>
{$url = $post->getContact()->getPhoto('s')}
{if="$url"}
<span class="primary icon bubble" style="background-image: url('{$url}');">
<i class="zmdi zmdi-loop"></i>
</span>
{else}
<span class="primary icon bubble color {$post->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-loop"></i>
</span>
{/if}
<span class="control icon">
<i class="zmdi zmdi-chevron-right"></i>
{if="$repost"}
<a href="{$c->route('contact', $post->getContact()->jid)}">
<ul class="list active middle">
<li>
{$url = $post->getContact()->getPhoto('s')}
{if="$url"}
<span class="primary icon bubble" style="background-image: url('{$url}');">
<i class="zmdi zmdi-loop"></i>
</span>
{else}
<span class="primary icon bubble color {$post->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-loop"></i>
</span>
{/if}
<p>{$c->__('post.repost', $post->getContact()->getTrueName())}</p>
<p>{$c->__('post.repost_profile', $post->getContact()->getTrueName())}</p>
</li>
</ul>
</a>
{/if}
<span class="control icon">
<i class="zmdi zmdi-chevron-right"></i>
</span>
<p>{$c->__('post.repost', $post->getContact()->getTrueName())}</p>
<p>{$c->__('post.repost_profile', $post->getContact()->getTrueName())}</p>
</li>
</ul>
</a>
{/if}
{if="$public && !$post->isPublic()"}
<ul class="list thick">
@ -188,6 +187,57 @@
</content>
</section>
<footer>
{if="$post->isReply()"}
<section>
{if="$reply"}
<a href="{$c->route('news', [$reply->origin, $reply->node, $reply->nodeid])}">
<ul class="list active thick card">
<li class="block">
{if="$reply->picture"}
<span
class="primary icon thumb white color"
style="background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.3) 100%), url({$reply->picture});">
<i class="zmdi zmdi-mail-reply"></i>
</span>
{elseif="$reply->isMicroblog()"}
{$url = $reply->getContact()->getPhoto('l')}
{if="$url"}
<span class="primary icon thumb color white" style="background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.3) 100%), url({$url});">
<i class="zmdi zmdi-mail-reply"></i>
</span>
{else}
<span class="primary icon thumb color {$value->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-mail-reply"></i>
</span>
{/if}
{/if}
<p class="line">{$reply->title}</p>
<p>{$reply->contentcleaned|stripTags}</p>
<p>
{if="$reply->isMicroblog()"}
<i class="zmdi zmdi-account"></i> {$reply->getContact()->getTrueName()}
{else}
<i class="zmdi zmdi-pages"></i> {$reply->node}
{/if}
<span class="info">
{$reply->published|strtotime|prepareDate:true,true}
</span>
</p>
</li>
</ul>
</a>
{else}
<ul class="list thick card">
<li class="block">
<span class="primary icon gray">
<i class="zmdi zmdi-info-outline"></i>
</span>
<p class="line normal">{$c->__('post.original_deleted')}</p>
</li>
</ul>
{/if}
</section>
{/if}
{$tags = $post->getTags()}
{if="isset($tags)"}
<ul class="list thick">
@ -273,9 +323,11 @@
</li>
</ul>
{/if}
<!--<a class="button action color" onclick="Publish_ajaxReply('{$post->origin}', '{$post->node}', '{$post->nodeid}')">
{if="!$post->isReply()"}
<a class="button action color" onclick="Publish_ajaxReply('{$post->origin}', '{$post->node}', '{$post->nodeid}')">
<i class="zmdi zmdi-share"></i>
</a>-->
</a>
{/if}
</footer>
{if="$external"}

19
app/widgets/Publish/Publish.php

@ -61,16 +61,23 @@ class Publish extends \Movim\Widget\Base
if($id) {
$pd = new \modl\PostnDAO();
$p = $pd->get($server, $node, $id);
if($p->isEditable() || $reply) {
if($p->isEditable() && !$reply) {
$post = $p;
}
if($p->isReply()) {
$reply = $p->getReply();
} elseif($reply) {
$reply = $p;
}
}
if($reply) {
$view->assign('to', $this->user->getLogin());
$view->assign('node', 'urn:xmpp:microblog:0');
$view->assign('item', false);
$view->assign('reply', $post);
$view->assign('item', $post);
$view->assign('reply', $reply);
} else {
$view->assign('to', $server);
$view->assign('node', $node);
@ -281,6 +288,12 @@ class Publish extends \Movim\Widget\Base
$p->setContentXhtml($content_xhtml);
}
if($form->reply->value) {
$pd = new \modl\PostnDAO();
$post = $pd->get($form->replyorigin->value, $form->replynode->value, $form->replynodeid->value);
$p->setReply($post->getRef());
}
$p->request();
} else {
RPC::call('Publish.enableSend');

5
app/widgets/Publish/_publish_create.tpl

@ -74,6 +74,11 @@
<input type="hidden" name="to" value="{$to}">
<input type="hidden" name="node" value="{$node}">
<input type="hidden" name="reply" value="{if="$reply"}1{else}0{/if}">
{if="$reply"}
<input type="hidden" name="replyorigin" value="{$reply->origin}">
<input type="hidden" name="replynode" value="{$reply->node}">
<input type="hidden" name="replynodeid" value="{$reply->nodeid}">
{/if}
<input type="hidden" name="id" value="{if="$item != false"}{$item->nodeid}{/if}">
<div>

4
composer.json

@ -17,13 +17,13 @@
"movim/modl": "dev-master",
"movim/sasl2": "dev-master",
"movim/moxl": "dev-master",
"movim/moxl": "dev-master#5934ed284b64539fb4070c9618affa101c0b755e",
"embed/embed": "dev-master",
"heyupdate/emoji": "0.2.*@dev",
"cboden/ratchet": "0.3.*",
"react/child-process": "0.5.*@dev",
"react/child-process": "dev-master",
"react/socket-client": "dev-master",
"react/stream": "0.4.*",
"react/http": "dev-master#cd15204bd15d106d7832c680e4fb0ca0ce2f5e30",

37
composer.lock

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "268bc95b66abbeb627bd7d442f90888d",
"content-hash": "7388a347b0fc03e194687bc025fd4152",
"hash": "ec16018cbab418bc36741aae530cf68a",
"content-hash": "a64bf72eeda5ac61d52ae76cb1299f63",
"packages": [
{
"name": "cboden/ratchet",
@ -678,20 +678,20 @@
},
{
"name": "heyupdate/emoji",
"version": "dev-master",
"version": "0.2.2",
"source": {
"type": "git",
"url": "https://github.com/heyupdate/emoji.git",
"reference": "0bb654d695553c20c6e72c32604086b7fde76e55"
"reference": "f1bad3641ebda73c71d9d078a9200e145169ca15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/heyupdate/emoji/zipball/0bb654d695553c20c6e72c32604086b7fde76e55",
"reference": "0bb654d695553c20c6e72c32604086b7fde76e55",
"url": "https://api.github.com/repos/heyupdate/emoji/zipball/f1bad3641ebda73c71d9d078a9200e145169ca15",
"reference": "f1bad3641ebda73c71d9d078a9200e145169ca15",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
@ -715,7 +715,7 @@
"keywords": [
"emoji"
],
"time": "2015-06-06 08:55:07"
"time": "2015-06-06 08:38:14"
},
{
"name": "michelf/php-markdown",
@ -886,12 +886,12 @@
"source": {
"type": "git",
"url": "https://github.com/movim/moxl.git",
"reference": "4e7fb4789025c01f780f3cbd2df20b603d2e2321"
"reference": "5934ed284b64539fb4070c9618affa101c0b755e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/movim/moxl/zipball/4e7fb4789025c01f780f3cbd2df20b603d2e2321",
"reference": "4e7fb4789025c01f780f3cbd2df20b603d2e2321",
"url": "https://api.github.com/repos/movim/moxl/zipball/5934ed284b64539fb4070c9618affa101c0b755e",
"reference": "5934ed284b64539fb4070c9618affa101c0b755e",
"shasum": ""
},
"require": {
@ -926,7 +926,7 @@
"php",
"xmpp"
],
"time": "2016-08-30 21:43:10"
"time": "2016-09-02 21:18:57"
},
{
"name": "movim/sasl2",
@ -1322,12 +1322,12 @@
"source": {
"type": "git",
"url": "https://github.com/reactphp/child-process.git",
"reference": "92b29374188e7bbfcfd5b9c9c1d68d7ec8358b30"
"reference": "3ab4f83c6f6c5862f7ca28d999a92d327472a671"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/child-process/zipball/92b29374188e7bbfcfd5b9c9c1d68d7ec8358b30",
"reference": "92b29374188e7bbfcfd5b9c9c1d68d7ec8358b30",
"url": "https://api.github.com/repos/reactphp/child-process/zipball/3ab4f83c6f6c5862f7ca28d999a92d327472a671",
"reference": "3ab4f83c6f6c5862f7ca28d999a92d327472a671",
"shasum": ""
},
"require": {
@ -1340,11 +1340,6 @@
"sebastian/environment": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.5-dev"
}
},
"autoload": {
"psr-4": {
"React\\ChildProcess\\": "src"
@ -1358,7 +1353,7 @@
"keywords": [
"process"
],
"time": "2016-03-08 21:22:43"
"time": "2016-08-01 18:09:48"
},
{
"name": "react/dns",

1
locales/locales.ini

@ -259,6 +259,7 @@ updated = Updated
content_not_found = Content not found
default_title = Contact publication
comments = Comments
original_deleted = Original post deleted
[api]
error = The API is not reachable, try again later

11
themes/material/css/listn.css

@ -69,7 +69,7 @@ ul.list.thick li .primary:not(.bubble):not(.thumb):not(.top) {
padding: 1.75rem 0.5rem;
}
ul.list > li > *:not(img):not(.counter):not(span):not(.bubble):not(.button),
ul.list > li > *:not(img):not(.counter):not(span):not(.bubble):not(.button):not(ul),
ul.list li.subheader p {
width: 100%;
box-sizing: border-box;
@ -154,6 +154,13 @@ ul.list li > p:nth-last-of-type(2) + p.all {
max-height: 100%;
}
/* In case of a card inside a li */
ul.list li > ul.list.card {
padding-right: 1rem;
padding-left: 8rem;
padding-bottom: 0.5rem;
}
/* Subheader */
ul.list li.subheader > p {
@ -173,7 +180,7 @@ ul.list li > .primary.bubble {
left: 2rem;
}
ul.list li > .primary ~ *:not(.primary):not(.counter):not(.bubble):not(.control) {
ul.list li > .primary ~ *:not(.primary):not(.counter):not(.bubble):not(.control):not(ul) {
padding-left: 9rem;
}

Loading…
Cancel
Save