Browse Source

- Add a new page Groups to manage the Pubsub nodes (reimplementation of the 0.8 feature)

- Add the subscribe/unsubscribe feature (+ bookmark sync)
- Add the pubsub configuration feature
- Add the node refresh feature
- Add a .spinner CSS class to display a spinner in the UI
- Clean the titles of the Movim pages
- Fix Some SQL requests
- Fiw some warnings
- Fix a CSS label issue
pull/16/head
Jaussoin Timothée 11 years ago
parent
commit
e7d1e56a10
  1. 10
      app/assets/js/movim_tpl.js
  2. 3
      app/controllers/ChatController.php
  3. 3
      app/controllers/ConfController.php
  4. 3
      app/controllers/ContactController.php
  5. 2
      app/controllers/GroupController.php
  6. 3
      app/controllers/HelpController.php
  7. 2
      app/controllers/MainController.php
  8. 2
      app/controllers/NewsController.php
  9. 3
      app/models/contact/ContactDAO.php
  10. 60
      app/models/item/ItemDAO.php
  11. 24
      app/models/postn/PostnDAO.php
  12. 1
      app/models/subscription/Subscription.php
  13. 1
      app/models/subscription/SubscriptionDAO.php
  14. 3
      app/views/group.tpl
  15. 21
      app/widgets/Chats/Chats.php
  16. 2
      app/widgets/Chats/_chats_add.tpl
  17. 329
      app/widgets/Group/Group.php
  18. 13
      app/widgets/Group/_group_config.tpl
  19. 4
      app/widgets/Group/_group_empty.tpl
  20. 41
      app/widgets/Group/_group_header.tpl
  21. 64
      app/widgets/Group/_group_posts.tpl
  22. 3
      app/widgets/Group/_group_publish.tpl
  23. 37
      app/widgets/Group/_group_subscribe.tpl
  24. 19
      app/widgets/Group/_group_unsubscribe.tpl
  25. 9
      app/widgets/Group/group.js
  26. 3
      app/widgets/Group/group.tpl
  27. 12
      app/widgets/Group/locales.ini
  28. 102
      app/widgets/Groups/Groups.php
  29. 18
      app/widgets/Groups/_groups_header.tpl
  30. 31
      app/widgets/Groups/_groups_server.tpl
  31. 36
      app/widgets/Groups/_groups_subscriptions.tpl
  32. 30
      app/widgets/Groups/groups.js
  33. 3
      app/widgets/Groups/groups.tpl
  34. 5
      app/widgets/Groups/locales.ini
  35. 12
      app/widgets/Header/_header_group.tpl
  36. 1
      app/widgets/Header/locales.ini
  37. 2
      app/widgets/Login/Login.php
  38. 2
      app/widgets/Menu/menu.js
  39. 2
      app/widgets/Navigation/navigation.tpl
  40. 2
      app/widgets/Node/Node.php
  41. 4
      app/widgets/Presence/_presence.tpl
  42. 2
      app/widgets/Rooms/Rooms.php
  43. 9
      app/widgets/Rooms/_rooms.tpl
  44. 2
      app/widgets/Rooms/locales.ini
  45. 6
      linker.php
  46. 4
      themes/material/css/form.css
  47. 5
      themes/material/css/list.css
  48. 52
      themes/material/css/style.css

10
app/assets/js/movim_tpl.js

@ -60,6 +60,7 @@ var MovimTpl = {
},
showPanel : function() {
movim_add_class('main section > div:first-child:nth-last-child(2) ~ div', 'enabled');
MovimTpl.scrollPanelTop();
},
hidePanel : function() {
Header_ajaxReset(CURRENT_PAGE);
@ -79,13 +80,20 @@ var MovimTpl = {
return false;
}
},
scrollPanel : function() { // On for panel that are .contained
scrollPanel : function() {
var selector = document.querySelector('main section > div:first-child:nth-last-child(2) ~ div div');
if(selector != null) {
selector.scrollTop = selector.scrollHeight;
}
},
scrollPanelTop : function() {
var selector = document.querySelector('main section > div:first-child:nth-last-child(2) ~ div');
if(selector != null) {
selector.scrollTop = 0;
}
},
toggleMenu : function() {
movim_toggle_class('body > nav', 'active');
},

3
app/controllers/ChatController.php

@ -6,7 +6,6 @@ class ChatController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.main', APP_TITLE));
$this->page->setColor('blue');
$this->page->setTitle(__('page.chats'));
}
}

3
app/controllers/ConfController.php

@ -6,7 +6,6 @@ class ConfController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.configuration', APP_TITLE));
$this->page->setColor('red');
$this->page->setTitle(__('page.configuration'));
}
}

3
app/controllers/ContactController.php

@ -6,7 +6,6 @@ class ContactController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.main', APP_TITLE));
$this->page->setColor('orange');
$this->page->setTitle(__('page.contacts'));
}
}

2
app/controllers/GroupController.php

@ -6,6 +6,6 @@ class GroupController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.main', APP_TITLE));
$this->page->setTitle(__('page.groups'));
}
}

3
app/controllers/HelpController.php

@ -6,7 +6,6 @@ class HelpController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.help', APP_TITLE));
$this->page->setColor('indigo');
$this->page->setTitle(__('page.help'));
}
}

2
app/controllers/MainController.php

@ -6,6 +6,6 @@ class MainController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.main', APP_TITLE));
$this->page->setTitle(__('page.home'));
}
}

2
app/controllers/NewsController.php

@ -6,6 +6,6 @@ class NewsController extends BaseController {
}
function dispatch() {
$this->page->setTitle(__('title.news', APP_TITLE));
$this->page->setTitle(__('page.news'));
}
}

3
app/models/contact/ContactDAO.php

@ -615,6 +615,7 @@ class ContactDAO extends SQL {
select jidfrom, count(*) as count from message
where jidfrom not like :jid
and session = :jid
and type != \'groupchat\'
group by jidfrom
order by count desc
limit :tunelenght
@ -635,7 +636,7 @@ class ContactDAO extends SQL {
from rosterlink
where session = :jid
) as rosterlink on jidfrom = rosterlink.jid
order by value';
order by value is null';
$this->prepare(
'Contact',

60
app/models/item/ItemDAO.php

@ -3,35 +3,37 @@
namespace modl;
class ItemDAO extends SQL {
function set(Item $item) {
$this->_sql = '
update item
set name = :name,
creator = :creator,
created = :created,
updated = :updated,
description = :description
where server = :server
and jid = :jid
and node = :node';
$this->prepare(
'Item',
array(
'name' => $item->name,
'created' => $item->created,
'updated' => $item->updated,
'server' => $item->server,
'jid' => $item->jid,
'node' => $item->node,
'creator' => $item->creator,
'description' => $item->description
)
);
$this->run('Item');
function set(Item $item, $insert_only = false) {
if(!$insert_only) {
$this->_sql = '
update item
set name = :name,
creator = :creator,
created = :created,
updated = :updated,
description = :description
where server = :server
and jid = :jid
and node = :node';
$this->prepare(
'Item',
array(
'name' => $item->name,
'created' => $item->created,
'updated' => $item->updated,
'server' => $item->server,
'jid' => $item->jid,
'node' => $item->node,
'creator' => $item->creator,
'description' => $item->description
)
);
$this->run('Item');
}
if(!$this->_effective) {
if(!$this->_effective || $insert_only) {
$this->_sql = '
insert into item
(server,
@ -138,7 +140,7 @@ class ItemDAO extends SQL {
select * from item
left outer join (
select node, count(node) as num from postn
where jid = :server
where origin = :server
group by node) as p
on p.node = item.node
left outer join (select server, node, subscription from subscription where jid = :node)

24
app/models/postn/PostnDAO.php

@ -202,6 +202,7 @@ class PostnDAO extends SQL {
where ((postn.origin, node) in (select server, node from subscription where jid = :aid))
and postn.origin = :origin
and postn.node = :node
and postn.node != \'urn:xmpp:microblog:0\'
order by postn.published desc';
if($limitr)
@ -219,6 +220,29 @@ class PostnDAO extends SQL {
return $this->run('ContactPostn');
}
function getNodeUnfiltered($from, $node, $limitf = false, $limitr = false) {
$this->_sql = '
select *, postn.aid, privacy.value as privacy from postn
left outer join contact on postn.aid = contact.jid
left outer join privacy on postn.nodeid = privacy.pkey
where postn.origin = :origin
and postn.node = :node
order by postn.published desc';
if($limitr)
$this->_sql = $this->_sql.' limit '.$limitr.' offset '.$limitf;
$this->prepare(
'Postn',
array(
'origin' => $from,
'node' => $node
)
);
return $this->run('ContactPostn');
}
function getGallery($from) {
$this->_sql = '
select *, postn.aid, privacy.value as privacy from postn

1
app/models/subscription/Subscription.php

@ -9,6 +9,7 @@ class Subscription extends Model {
public $subscription;
public $subid;
public $title;
public $description;
public $tags;
public $timestamp;
public $name;

1
app/models/subscription/SubscriptionDAO.php

@ -78,6 +78,7 @@ class SubscriptionDAO extends SQL {
subscription.server,
subscription.node,
subscription,
item.description,
name
from subscription
left outer join item

3
app/views/group.tpl

@ -6,6 +6,7 @@
<main>
<?php $this->widget('Header'); ?>
<section>
<?php $this->widget('Groups'); ?>
<?php $this->widget('Group'); ?>
</section>
</main>

21
app/widgets/Chats/Chats.php

@ -4,6 +4,8 @@ use Moxl\Xec\Action\Presence\Muc;
use Moxl\Xec\Action\Bookmark\Get;
use Moxl\Xec\Action\Bookmark\Set;
use Respect\Validation\Validator;
class Chats extends WidgetCommon
{
function load()
@ -59,12 +61,13 @@ class Chats extends WidgetCommon
function ajaxOpen($jid)
{
if(!$this->validateJid($jid)) return;
$chats = Cache::c('chats');
if($chats == null) $chats = array();
if(!array_key_exists($jid, $chats)
&& $jid != $this->user->getLogin()
&& $jid != '') {
&& $jid != $this->user->getLogin()) {
$chats[$jid] = 1;
} else {
unset($chats[$jid]);
@ -74,12 +77,16 @@ class Chats extends WidgetCommon
Cache::c('chats', $chats);
RPC::call('movim_delete', $jid.'_chat_item');
RPC::call('movim_prepend', 'chats_widget_list', $this->prepareChat($jid));
RPC::call('Chats.refresh');
}
function ajaxClose($jid)
{
if(!$this->validateJid($jid)) return;
$chats = Cache::c('chats');
unset($chats[$jid]);
Cache::c('chats', $chats);
@ -132,6 +139,8 @@ class Chats extends WidgetCommon
function prepareChat($jid)
{
if(!$this->validateJid($jid)) return;
$view = $this->tpl();
$cd = new \Modl\ContactDAO;
@ -157,6 +166,14 @@ class Chats extends WidgetCommon
return $view->draw('_chats_item', true);
}
private function validateJid($jid)
{
$validate_jid = Validator::email()->noWhitespace()->length(6, 40);
if($validate_jid->validate($jid)) return true;
else return false;
}
function display()
{
$this->view->assign('list', $this->prepareChats());

2
app/widgets/Chats/_chats_add.tpl

@ -1,7 +1,7 @@
<section class="scroll">
<h3>{$c->__('chats.add')}</h3>
<ul class="active" id="add_extend">
<li class="subheader condensed">{$c->__('chats.frequent')}</li>
<li class="subheader">{$c->__('chats.frequent')}</li>
{loop="$top"}
<li class="condensed" onclick="Chats_ajaxOpen('{$value->jid}'); Dialog.clear()">
{$url = $value->getPhoto('s')}

329
app/widgets/Group/Group.php

@ -0,0 +1,329 @@
<?php
use Moxl\Xec\Action\Pubsub\GetItems;
use Moxl\Xec\Action\Pubsub\GetMetadata;
use Moxl\Xec\Action\Pubsub\GetAffiliations;
use Moxl\Xec\Action\Pubsub\Subscribe;
use Moxl\Xec\Action\Pubsub\Unsubscribe;
use Moxl\Xec\Action\Pubsub\GetConfig;
use Moxl\Xec\Action\Pubsub\SetConfig;
use Respect\Validation\Validator;
class Group extends WidgetCommon
{
private $_paging = 15;
private $_role = null;
function load()
{
$this->registerEvent('pubsub_getitems_handle', 'onItems');
$this->registerEvent('pubsub_getitems_error', 'onItemsError');
$this->registerEvent('pubsub_subscribe_handle', 'onSubscribed');
$this->registerEvent('pubsub_unsubscribe_handle', 'onUnsubscribed');
$this->registerEvent('pubsub_getaffiliations_handle', 'onAffiliations');
$this->registerEvent('pubsub_getconfig_handle', 'onConfig');
$this->registerEvent('pubsub_setconfig_handle', 'onConfigSaved');
$this->registerEvent('bookmark_set_handle', 'onBookmark');
$this->addjs('group.js');
}
function onItems($packet)
{
$arr = $packet->content;
$this->displayItems($arr['server'], $arr['node']);
RPC::call('Group.clearLoad');
RPC::call('MovimTpl.showPanel');
}
function onBookmark()
{
$this->ajaxClear();
$g = new Groups;
$g->ajaxHeader();
$g->ajaxSubscriptions();
}
function onItemsError($packet)
{
$arr = $packet->content;
Notification::append(false, $this->__('group.empty'));
// Display an error message
RPC::call('Group.clearLoad');
}
function onAffiliations($packet)
{
list($affiliations, $server, $node) = array_values($packet->content);
foreach($affiliations as $r) {
if($r[0] == $this->user->getLogin())
$this->_role = (string)$r[1];
}
Header::fill($this->prepareHeader($server, $node));
if(isset($this->_role)
&& ($this->_role == 'owner' || $this->_role == 'publisher')) {
$view = $this->tpl();
RPC::call('movim_append', 'group_widget', $view->draw('_group_publish', true));
}
}
function onConfig($packet)
{
list($config, $server, $node) = array_values($packet->content);
$view = $this->tpl();
$xml = new \XMPPtoForm();
$form = $xml->getHTML($config->x->asXML());
$view->assign('form', $form);
$view->assign('server', $server);
$view->assign('node', $node);
$view->assign('attributes', $config->attributes());
Dialog::fill($view->draw('_group_config', true), true);
}
function onConfigSaved()
{
Notification::append(false, $this->__('group.config_saved'));
}
function onSubscribed($packet)
{
$arr = $packet->content;
// Set the bookmark
$r = new Rooms;
$r->setBookmark();
Notification::append(null, $this->__('group.subscribed'));
// Set the public list
/*
//add the group to the public list (if checked)
if($this->_data['listgroup'] == true){
$add = new ListAdd();
$add->setTo($this->_to)
->setNode($this->_node)
->setFrom($this->_from)
->setData($this->_data)
->request();
}
}*/
}
function onUnsubscribed($packet)
{
$arr = $packet->content;
// Set the bookmark
$r = new Rooms;
$r->setBookmark();
Notification::append(null, $this->__('group.unsubscribed'));
}
private function displayItems($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$html = $this->prepareGroup($server, $node);
$header = $this->prepareHeader($server, $node);
Header::fill($header);
RPC::call('movim_fill', 'group_widget', $html);
}
function ajaxGetMetadata($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$r = new GetMetadata;
$r->setTo($server)->setNode($node)
->request();
}
function ajaxGetConfig($server, $node){
if(!$this->validateServerNode($server, $node)) return;
$r = new GetConfig;
$r->setTo($server)
->setNode($node)
->request();
}
function ajaxSetConfig($data, $server, $node){
if(!$this->validateServerNode($server, $node)) return;
$r = new SetConfig;
$r->setTo($server)
->setNode($node)
->setData($data)
->request();
}
function ajaxGetItems($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$r = new GetItems;
$r->setTo($server)
->setNode($node);
$pd = new \Modl\PostnDAO();
$posts = $pd->getNodeUnfiltered($server, $node, 0, 1);
if(isset($posts[0])) {
$r->setSince($posts[0]->updated);
}
$r->request();
RPC::call('Group.addLoad');
}
function ajaxGetAffiliations($server, $node){
if(!$this->validateServerNode($server, $node)) return;
$r = new GetAffiliations;
$r->setTo($server)->setNode($node)
->request();
}
function ajaxAskSubscribe($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$view = $this->tpl();
$view->assign('server', $server);
$view->assign('node', $node);
$pd = new \Modl\ItemDAO;
$item = $pd->getItem($server, $node);
if(isset($item)) {
$view->assign('item', $item);
} else {
$view->assign('item', null);
}
Dialog::fill($view->draw('_group_subscribe', true));
}
function ajaxSubscribe($form, $server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$g = new Subscribe;
$g->setTo($server)
->setNode($node)
->setFrom($this->user->getLogin())
->setData($form)
->request();
}
function ajaxAskUnsubscribe($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$view = $this->tpl();
$view->assign('server', $server);
$view->assign('node', $node);
$pd = new \Modl\ItemDAO;
$item = $pd->getItem($server, $node);
if(isset($item)) {
$view->assign('item', $item);
} else {
$view->assign('item', null);
}
Dialog::fill($view->draw('_group_unsubscribe', true));
}
function ajaxUnsubscribe($server, $node)
{
if(!$this->validateServerNode($server, $node)) return;
$sd = new \Modl\SubscriptionDAO();
foreach($sd->get($server, $node) as $s) {
$g = new Unsubscribe;
$g->setTo($server)
->setNode($node)
->setSubid($s->subid)
->setFrom($this->user->getLogin())
->request();
}
}
function ajaxClear()
{
$html = $this->prepareEmpty();
RPC::call('movim_fill', 'group_widget', $html);
}
function prepareEmpty()
{
$view = $this->tpl();
$html = $view->draw('_group_empty', true);
return $html;
}
private function prepareHeader($server, $node)
{
$pd = new \Modl\ItemDAO;
$item = $pd->getItem($server, $node);
$pd = new \Modl\SubscriptionDAO;
$subscription = $pd->get($server, $node);
$view = $this->tpl();
$view->assign('item', $item);
$view->assign('subscription', $subscription);
$view->assign('role', $this->_role);
return $view->draw('_group_header', true);
}
private function prepareGroup($server, $node)
{
$pd = new \Modl\PostnDAO();
$posts = $pd->getNodeUnfiltered($server, $node, 0, $this->_paging);
$view = $this->tpl();
$view->assign('posts', $posts);
$html = $view->draw('_group_posts', true);
return $html;
}
private function validateServerNode($server, $node)
{
$validate_server = Validator::string()->noWhitespace()->length(6, 40);
$validate_node = Validator::string()->length(3, 100);
if(!$validate_server->validate($server)
|| !$validate_node->validate($node)
) return false;
else return true;
}
function display()
{
}
}

13
app/widgets/Group/_group_config.tpl

@ -0,0 +1,13 @@
<section class="scroll">
<form name="config" data-sessionid="{$attributes->sessionid}" data-node="{$attributes->node}">
{$form}
</form>
</section>
<div>
<a onclick="Dialog.clear()" class="button flat">
{$c->__('button.close')}
</a>
<a onclick="Group_ajaxSetConfig(movim_parse_form('config'), '{$server}', '{$node}'); Dialog.clear();" class="button flat">
{$c->__('button.save')}
</a>
</div>

4
app/widgets/Group/_group_empty.tpl

@ -0,0 +1,4 @@
<div class="placeholder icon pages">
<h1>{$c->__('group.empty_title')}</h1>
<h4>{$c->__('group.empty_text')}</h4>
</div>

41
app/widgets/Group/_group_header.tpl

@ -0,0 +1,41 @@
<div>
<span class="on_desktop icon"><i class="md md-pages"></i></span>
<h2>
{$c->__('page.groups')}
</h2>
</div>
<div>
<ul class="active">
{if="$role == 'owner'"}
<li onclick="Group_ajaxGetConfig('{$item->server}', '{$item->node}')">
<span class="icon">
<i class="md md-settings"></i>
</span>
</li>
{/if}
{if="$subscription == null"}
<li onclick="Group_ajaxAskSubscribe('{$item->server}', '{$item->node}')">
<span class="icon">
<i class="md md-bookmark-outline"></i>
</span>
</li>
{else}
<li onclick="Group_ajaxAskUnsubscribe('{$item->server}', '{$item->node}')">
<span class="icon">
<i class="md md-bookmark"></i>
</span>
</li>
{/if}
</ul>
<h2 class="active {if="$role == 'owner'"}r2{else}r1{/if}"
onclick="MovimTpl.hidePanel(); Group_ajaxClear(); Groups_ajaxHeader();">
<span id="back" class="icon"><i class="md md-arrow-back"></i></span>
{if="$item != null"}
{if="$item->name"}
{$item->name}
{else}
{$item->node}
{/if}
{/if}
</h2>
</div>

64
app/widgets/Group/_group_posts.tpl

@ -0,0 +1,64 @@
{loop="$posts"}
<article>
<header>
<ul class="thick">
<li class="condensed">
{$url = $value->getContact()->getPhoto('s')}
{if="$url"}
<span class="icon bubble">
<img src="{$url}">
</span>
{else}
<span class="icon bubble color {$value->node|stringToColor}">{$value->node|firstLetterCapitalize}</span>
{/if}
<h2>
{if="$value->title != null"}
{$value->title}
{else}
{$c->__('post.default_title')}
{/if}
</h2>
<p>
{if="$value->node == 'urn:xmpp:microblog:0' && $value->getContact()->getTrueName() != ''"}
{$value->getContact()->getTrueName()} -
{/if}
{$value->published|strtotime|prepareDate}
</p>
</li>
</ul>
</header>
<section>
{$value->contentcleaned}
</section>
<footer>
<ul class="thin">
{if="isset($value->getAttachements().links)"}
{loop="$value->getAttachements().links"}
<li>
<span class="icon small"><img src="http://icons.duckduckgo.com/ip2/{$value.url.host}.ico"/></span>
<a href="{$value.href}" class="alternate" target="_blank">
<span>{$value.href|urldecode}</span>
</a>
</li>
{/loop}
{/if}
{if="isset($value->getAttachements().files)"}
{loop="$value->getAttachements().files"}
<li>
<a
href="{$value.href}"
class="enclosure"
type="{$value.type}"
target="_blank">
<span class="icon small gray">
<span class="md md-attach-file"></span>
</span>
<span>{$value.href|urldecode}</span>
</a>
</li>
{/loop}
{/if}
</ul>
</footer>
</article>
{/loop}

3
app/widgets/Group/_group_publish.tpl

@ -0,0 +1,3 @@
<a onclick="Group_ajaxPublish()" class="button action color">
<i class="md md-create"></i>
</a>

37
app/widgets/Group/_group_subscribe.tpl

@ -0,0 +1,37 @@
<section>
<h3>{$c->__('group.subscribe')}</h3>
{if="$item"}
<br />
<h4 class="gray">
{$item->name}
</h4>
{/if}
<ul class="simple">
<li>
<form name="subscribe">
<div>
<input
name="label"
type="text"
title="{$c->__('group.label_label')}"
placeholder="My Group Name"
{if="$item"}
value="{$item->name}"
{/if}
/>
<label for="label">{$c->__('group.label_label')}</label>
</div>
</form>
</li>
</ul>
</section>
<div>
<a onclick="Dialog.clear()" class="button flat">
{$c->__('button.close')}
</a>
<a
onclick="Group_ajaxSubscribe(movim_form_to_json('subscribe'), '{$server}', '{$node}'); Dialog.clear()"
class="button flat">
{$c->__('group.subscribe')}
</a>
</div>

19
app/widgets/Group/_group_unsubscribe.tpl

@ -0,0 +1,19 @@
<section>
<h3>{$c->__('group.sure')}</h3>
{if="$item"}
<br />
<h4 class="gray">
{$c->__('group.unsubscribe_text')} : {$item->name}
</h4>
{/if}
</section>
<div>
<a onclick="Dialog.clear()" class="button flat">
{$c->__('button.close')}
</a>
<a
onclick="Group_ajaxUnsubscribe('{$server}', '{$node}'); Dialog.clear()"
class="button flat">
{$c->__('group.unsubscribe')}
</a>
</div>

9
app/widgets/Group/group.js

@ -0,0 +1,9 @@
var Group = {
addLoad: function() {
movim_add_class('#group_widget', 'on');
},
clearLoad: function() {
movim_remove_class('#group_widget', 'on');
}
}

3
app/widgets/Group/group.tpl

@ -0,0 +1,3 @@
<div id="group_widget" class="divided spinner">
{$c->prepareEmpty()}
</div>

12
app/widgets/Group/locales.ini

@ -0,0 +1,12 @@
group.subscribe = 'Subscribe'
group.subscribed = 'Subscribed'
group.unsubscribe = 'Unsubscribe'
group.unsubscribe_text = 'You are going to unsubscribe from this Group'
group.unsubscribed = 'Unsubscribed'
group.share_label = 'Make your membership to this group public to your friends'
group.label_label = 'Give a label for this group'
group.sure = 'Are you sure ?'
group.empty_title = 'Groups'
group.empty_text = 'Discover, follow and share'
group.empty = 'Something bad happened to this group'
group.config_saved = 'Group configuration saved'

102
app/widgets/Groups/Groups.php

@ -0,0 +1,102 @@
<?php
use Moxl\Xec\Action\Pubsub\GetItems;
use Moxl\Xec\Action\Pubsub\DiscoItems;
use Respect\Validation\Validator;
class Groups extends WidgetCommon
{
private $_list_server;
function load()
{
$this->registerEvent('pubsub_discoitems_handle', 'onDisco');
$this->registerEvent('pubsub_discoitems_error', 'onDiscoError');
$this->addjs('groups.js');
}
function onDisco($packet)
{
$server = $packet->content;
$this->displayServer($server);
}
function onDiscoError($packet)
{
// Display a nice error
}
function ajaxHeader()
{
$id = new \modl\ItemDAO();
$view = $this->tpl();
$view->assign('servers', $id->getServers());
$header = $view->draw('_groups_header', true);
Header::fill($header);
}
function ajaxSubscriptions()
{
$html = $this->prepareSubscriptions();
RPC::call('movim_fill', 'groups_widget', $html);
RPC::call('Groups.refresh');
}
function ajaxDisco($server)
{
$validate_server = Validator::string()->noWhitespace()->length(6, 40);
if(!$validate_server->validate($server)) return;
$r = new DiscoItems;
$r->setTo($server)->request();
}
private function displayServer($server)
{
$validate_server = Validator::string()->noWhitespace()->length(6, 40);
if(!$validate_server->validate($server)) return;
$html = $this->prepareServer($server);
RPC::call('movim_fill', 'groups_widget', $html);
RPC::call('Groups.refresh');
}
function checkNewServer($node) {
$r = false;
if($this->_list_server != $node->server)
$r = true;
$this->_list_server = $node->server;
return $r;
}
function prepareSubscriptions() {
$sd = new \modl\SubscriptionDAO();
$view = $this->tpl();
$view->assign('subscriptions', $sd->getSubscribed());
$html = $view->draw('_groups_subscriptions', true);
return $html;
}
private function prepareServer($server) {
$id = new \modl\ItemDAO();
$view = $this->tpl();
$view->assign('nodes', $id->getItems($server));
$view->assign('server', $server);
$html = $view->draw('_groups_server', true);
return $html;
}
function display()
{
}
}

18
app/widgets/Groups/_groups_header.tpl

@ -0,0 +1,18 @@
<div>
<span id="menu" class="on_mobile icon active" onclick="MovimTpl.toggleMenu()"><i class="md md-menu"></i></span>
<span class="on_desktop icon"><i class="md md-pages"></i></span>
<form>
<div>
<div class="select">
<select onchange="window[this.value].apply(this, [this.options[this.selectedIndex].dataset['server']]);" name="language" id="language">
<option value="Groups_ajaxSubscriptions" selected="selected">{$c->__('groups.subscriptions')}</option>
{loop="$servers"}
{if="!filter_var($value->server, FILTER_VALIDATE_EMAIL)"}
<option value="Groups_ajaxDisco" data-server="{$value->server}">{$value->server} ({$value->number})</option>
{/if}
{/loop}
</select>
</div>
</div>
</form>
</div>

31
app/widgets/Groups/_groups_server.tpl

@ -0,0 +1,31 @@
<ul class="middle divided spaced active">
{loop="$nodes"}
<li
class="
{if="$value->subscription == 'subscribed'"}action{/if}
{if="$value->description"}condensed{/if}
"
data-server="{$value->server}"
data-node="{$value->node}"
title="{$value->server} - {$value->node}"
>
{if="$value->subscription == 'subscribed'"}
<div class="action">
<i class="md md-bookmark"></i>
</div>
{/if}
<span class="icon bubble color {$value->node|stringToColor}">{$value->node|firstLetterCapitalize}</span>
<span>
{if="$value->name"}
{$value->name}
{else}
{$value->node}
{/if}
<span class="second">{$value->num}</span>
</span>
{if="$value->description"}
<p class="wrap">{$value->description|strip_tags}</p>
{/if}
</li>
{/loop}
</ul>

36
app/widgets/Groups/_groups_subscriptions.tpl

@ -0,0 +1,36 @@
{if="$subscriptions == null"}
<ul class="thick">
<li class="condensed">
<span class="icon bubble color green">
<i class="md md-bookmark"></i>
</span>
<span>{$c->__('groups.empty_title')}</span>
<p>{$c->__('groups.empty_text1')} {$c->__('groups.empty_text2')}</p>
</li>
</ul>
{else}
<ul class="divided spaced middle active">
{loop="$subscriptions"}
{if="$c->checkNewServer($value)"}
<li class="subheader">{$value->server}</li>
{/if}
<li
{if="$value->description"}class="condensed"{/if}
data-server="{$value->server}"
data-node="{$value->node}"
>
<span class="icon bubble color {$value->node|stringToColor}">{$value->node|firstLetterCapitalize}</span>
<span>
{if="$value->name"}
{$value->name}
{else}
{$value->node}
{/if}
</span>
{if="$value->description"}
<p class="wrap">{$value->description|strip_tags}</p>
{/if}
</li>
{/loop}
</ul>
{/if}

30
app/widgets/Groups/groups.js

@ -0,0 +1,30 @@
var Groups = {
refresh: function() {
var items = document.querySelectorAll('#groups_widget ul li:not(.subheader)');
var i = 0;
while(i < items.length)
{
items[i].onclick = function(e) {
MovimTpl.scrollPanelTop();
Group_ajaxGetItems(this.dataset.server, this.dataset.node);
Group_ajaxGetAffiliations(this.dataset.server, this.dataset.node);
Group_ajaxGetMetadata(this.dataset.server, this.dataset.node);
Groups.reset(items);
movim_add_class(this, 'active');
}
i++;
}
},
reset: function(list) {
for(i = 0; i < list.length; i++) {
movim_remove_class(list[i], 'active');
}
}
}
MovimWebsocket.attach(function() {
Groups_ajaxHeader();
Groups.refresh();
});

3
app/widgets/Groups/groups.tpl

@ -0,0 +1,3 @@
<div id="groups_widget">
{$c->prepareSubscriptions()}
</div>

5
app/widgets/Groups/locales.ini

@ -0,0 +1,5 @@
groups.empty_title = 'Hello'
groups.contact_post = 'Contact post'
groups.empty_text1 = "You don't have any subscriptions yet, select a group server above to start exploring."
groups.empty_text2 = "Subscribe to your favorite feeds by bookmarking them."
groups.subscriptions = 'My Subscriptions'

12
app/widgets/Header/_header_group.tpl

@ -1,13 +1,5 @@
<div>
<span id="menu" class="on_mobile icon active" onclick="MovimTpl.toggleMenu()"><i class="md md-menu"></i></span>
<span class="on_desktop icon"><i class="md md-receipt"></i></span>
<form>
<div>
<div class="select">
<select onchange="window[this.value].apply()" name="language" id="language">
<option value="Groups_ajaxSubscriptions" selected="selected">{$c->__('menu.subscriptions')}</option>
</select>
</div>
</div>
</form>
<span class="on_desktop icon"><i class="md md-pages"></i></span>
<h2>{$c->__('page.groups')}</h2>
</div>

1
app/widgets/Header/locales.ini

@ -3,7 +3,6 @@ menu.all = 'All'
menu.news = 'News'
menu.contacts = 'Contacts'
menu.refresh = 'Refresh all the streams'
menu.subscriptions = 'My Subscriptions'
[roster]
roster.search = 'Search'

2
app/widgets/Login/Login.php

@ -196,7 +196,7 @@ class Login extends WidgetBase
}
// We try to get the domain
$dns = dns_get_record('_xmpp-client._tcp.'.$login_arr[1]);
$dns = dns_get_record('_xmpp-client._tcp.'.$host);
if(isset($dns[0]['target']) && $dns[0]['target'] != null)
$domain = $dns[0]['target'];

2
app/widgets/Menu/menu.js

@ -7,11 +7,13 @@ var Menu = {
{
if(items[i].id != 'history') {
items[i].onclick = function(e) {
if(this.dataset.id) {
MovimTpl.showPanel();
Post_ajaxGetPost(this.dataset.id);
//Menu_ajaxGetNode(this.dataset.server, this.dataset.node);
Menu.reset(items);
movim_add_class(this, 'active');
}
}
}
i++;

2
app/widgets/Navigation/navigation.tpl

@ -24,7 +24,7 @@
</a>
<a class="classic" href="{$c->route('group')}">
<li {if="$page == 'group'"}class="active"{/if}>
<span class="icon"><i class="md md-receipt"></i></span>
<span class="icon"><i class="md md-pages"></i></span>
<span class="counter"></span>
<span>{$c->__('page.groups')}</span>
</li>

2
app/widgets/Node/Node.php

@ -129,7 +129,7 @@ class Node extends WidgetCommon
$g->setTo($server)
->setNode($node)
->setFrom($this->user->getLogin())
->setData($data)
//->setData($data)
->request();
}

4
app/widgets/Presence/_presence.tpl

@ -5,11 +5,11 @@
{$url = $me->getPhoto('s')}
{if="$url"}
<span
class="icon bubble status {$presencetxt[$presence->value]}"
class="icon bubble status {if="$presence->value != null"}{$presencetxt[$presence->value]}{/if}"
style="background-image: url({$me->getPhoto('m')})">
</span>
{else}
<span class="icon bubble color {$me->jid|stringToColor} status {$presencetxt[$presence->value]}">
<span class="icon bubble color {$me->jid|stringToColor} status {if="$presence->value != null"}{$presencetxt[$presence->value]}{/if}">
<i class="md md-person"></i>
</span>
{/if}

2
app/widgets/Rooms/Rooms.php

@ -139,7 +139,7 @@ class Rooms extends WidgetCommon
}
}
private function setBookmark($item = false)
public function setBookmark($item = false)
{
$arr = array();

9
app/widgets/Rooms/_rooms.tpl

@ -17,4 +17,13 @@
<p>{$value->conference}</p>
</li>
{/loop}
{if="$conferences == null"}
<li class="condensed">
<span class="icon green">
<i class="md md-people-outline"></i>
</span>
<p>{$c->__('rooms.empty_text1')} {$c->__('rooms.empty_text2')}</p>
</li>
{/if}
</ul>

2
app/widgets/Rooms/locales.ini

@ -1,4 +1,6 @@
rooms.add = 'Add a chatroom'
rooms.empty_text1 = "You don't have any chatroom yet."
rooms.empty_text2 = "Add one by clicking on the add button in the header."
[chatrooms]
chatrooms.title = 'Chatrooms'

6
linker.php

@ -45,7 +45,7 @@ $connector($config->websocketurl, array('xmpp'))->then(function($conn) use (&$st
$conn->on('message', function($message) use ($conn, $loop) {
if($message != '') {
#fwrite(STDERR, colorize($message, 'yellow')." : ".colorize('received', 'green')."\n");
fwrite(STDERR, colorize($message, 'yellow')." : ".colorize('received', 'green')."\n");
if($message == '</stream:stream>') {
$conn->close();
@ -76,7 +76,7 @@ $connector($config->websocketurl, array('xmpp'))->then(function($conn) use (&$st
}
if(!empty($xml)) {
#fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
$conn->send(trim($xml));
}
}
@ -118,7 +118,7 @@ $connector($config->websocketurl, array('xmpp'))->then(function($conn) use (&$st
\Moxl\API::clear();
if(!empty($xml)) {
#fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
$conn->send(trim($xml));
}

4
themes/material/css/form.css

@ -16,6 +16,10 @@ li > form > div:not(.control) { /* If we put the form in a list */
form > div > label {
position: absolute;
top: 2rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 100%;
}
form > div.icon {

5
themes/material/css/list.css

@ -141,6 +141,11 @@ ul li span {
white-space: nowrap;
}
ul li span.second {
opacity: 0.6;
padding-left: 0.5rem;
}
ul li img {
max-width: 100%;
}

52
themes/material/css/style.css

@ -724,6 +724,7 @@ main section > div:first-child:nth-last-child(2) ~ div .actions.fixed > div:last
.icon.explore { background-image: url(../img/placeholder/explore.png); }
.icon.plane { background-image: url(../img/placeholder/plane.png); }
.icon.file { background-image: url(../img/placeholder/file.png); }
.icon.pages { background-image: url(../img/icons/pages.svg); }
.icon.clipboard { background-image: url(../img/icons/assignment_turned_in.svg); }
/* Definition list */
@ -796,6 +797,57 @@ dl dd {
width: calc(100% - 9rem);
}
/* Spinner */
.spinner {
position: relative;
}
.spinner:before,
.spinner:after {
transition: top .3s ease-in-out;
content: '';
position: absolute;
left: calc(50% - 3.5rem);
border-radius: 50%;
top: -10rem;
}
.spinner.on:before,
.spinner.on:after {
top: 3rem;
}
.spinner:before {
z-index: 2;
width: 3.5rem;
height: 3.5rem;
margin: 1rem;
}
.spinner:not(:required):before {
content: '';
border: 0.75rem solid transparent;
border-top: 0.75rem solid #ddd;
animation: spinner 1s linear infinite;
-webkit-animation: spinner 1s linear infinite;
}
.spinner:after {
box-shadow: 0px 0.5rem 1.25rem rgba(0, 0, 0, 0.23), 0px 0.5rem 1.25rem rgba(0, 0, 0, 0.16);
background-color: white;
width: 7rem;
height: 7rem;
}
@keyframes spinner {
to {transform: rotate(360deg);}
}
@-webkit-keyframes spinner {
to {-webkit-transform: rotate(360deg);}
}
/* Display/hide */
.on_mobile {

Loading…
Cancel
Save