mirror of
https://github.com/YunoHost-Apps/movim_ynh.git
synced 2024-09-03 19:46:19 +02:00
update to movim upstream
This commit is contained in:
parent
de8ea29c5c
commit
882ecf654a
35 changed files with 444 additions and 114 deletions
|
@ -1,5 +1,8 @@
|
||||||
**Changelog**
|
**Changelog**
|
||||||
|
|
||||||
|
1.7 ?
|
||||||
|
- Update to movim 0.9 git2016-02-19
|
||||||
|
|
||||||
1.6.1 2016-02-12
|
1.6.1 2016-02-12
|
||||||
- Update to movim 0.9 git2016-01-27
|
- Update to movim 0.9 git2016-01-27
|
||||||
- Improve config/ and log/ protection (nginx)
|
- Improve config/ and log/ protection (nginx)
|
||||||
|
|
|
@ -5,7 +5,7 @@ Movim is a decentralized social network, written in PHP and HTML5 and based on t
|
||||||
|
|
||||||
It is recommended to use a "valid" certificate to use Movim, auto-signed is sometimes problematic. You might want to take a look a StartSSL or Let's Encrypt.
|
It is recommended to use a "valid" certificate to use Movim, auto-signed is sometimes problematic. You might want to take a look a StartSSL or Let's Encrypt.
|
||||||
|
|
||||||
Provided Movim version : 0.9 git2016-02-12
|
Provided Movim version : 0.9 git2016-02-19
|
||||||
|
|
||||||
Please read CHANGELOG.
|
Please read CHANGELOG.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ Movim Changelog
|
||||||
v0.9.1 (trunk)
|
v0.9.1 (trunk)
|
||||||
---------------------------
|
---------------------------
|
||||||
* CSS fixes
|
* CSS fixes
|
||||||
|
* Add Last Message Edition support
|
||||||
|
* Improve Post discovery in the News page
|
||||||
|
|
||||||
v0.9
|
v0.9
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class BlogController extends BaseController {
|
class BlogController extends BaseController {
|
||||||
function load() {
|
function load() {
|
||||||
$this->session_only = false;
|
$this->session_only = false;
|
||||||
|
$this->public = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatch() {
|
function dispatch() {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class NodeController extends BaseController {
|
class NodeController extends BaseController {
|
||||||
function load() {
|
function load() {
|
||||||
$this->session_only = false;
|
$this->session_only = false;
|
||||||
|
$this->public = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatch() {
|
function dispatch() {
|
||||||
|
|
|
@ -234,7 +234,11 @@ function explodeJid($jid)
|
||||||
if(isset($arr[1])) $resource = $arr[1];
|
if(isset($arr[1])) $resource = $arr[1];
|
||||||
else $resource = null;
|
else $resource = null;
|
||||||
|
|
||||||
list($username, $server) = explode('@', $jid);
|
$server = '';
|
||||||
|
|
||||||
|
$arr = explode('@', $jid);
|
||||||
|
$username = $arr[0];
|
||||||
|
if(isset($arr[1])) $server = $arr[1];
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'username' => $username,
|
'username' => $username,
|
||||||
|
@ -373,3 +377,14 @@ function purifyHTML($string)
|
||||||
function firstLetterCapitalize($string) {
|
function firstLetterCapitalize($string) {
|
||||||
return ucfirst(strtolower(mb_substr($string, 0, 2)));
|
return ucfirst(strtolower(mb_substr($string, 0, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates the given string at the specified length.
|
||||||
|
*
|
||||||
|
* @param string $str The input string.
|
||||||
|
* @param int $width The number of chars at which the string will be truncated.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function truncate($str, $width) {
|
||||||
|
return strtok(wordwrap($str, $width, "…\n"), "\n");
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
namespace modl;
|
namespace modl;
|
||||||
|
|
||||||
class Message extends Model {
|
class Message extends Model {
|
||||||
|
public $id;
|
||||||
|
public $newid;
|
||||||
|
|
||||||
public $session;
|
public $session;
|
||||||
public $jidto;
|
public $jidto;
|
||||||
public $jidfrom;
|
public $jidfrom;
|
||||||
|
@ -21,6 +24,7 @@ class Message extends Model {
|
||||||
|
|
||||||
public $color; // Only for chatroom purpose
|
public $color; // Only for chatroom purpose
|
||||||
public $publishedPrepared; // Only for chat purpose
|
public $publishedPrepared; // Only for chat purpose
|
||||||
|
public $edited;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -28,6 +32,8 @@ class Message extends Model {
|
||||||
{
|
{
|
||||||
"session" :
|
"session" :
|
||||||
{"type":"string", "size":128, "mandatory":true },
|
{"type":"string", "size":128, "mandatory":true },
|
||||||
|
"id" :
|
||||||
|
{"type":"string", "size":36},
|
||||||
"jidto" :
|
"jidto" :
|
||||||
{"type":"string", "size":128, "mandatory":true },
|
{"type":"string", "size":128, "mandatory":true },
|
||||||
"jidfrom" :
|
"jidfrom" :
|
||||||
|
@ -47,7 +53,9 @@ class Message extends Model {
|
||||||
"published" :
|
"published" :
|
||||||
{"type":"date"},
|
{"type":"date"},
|
||||||
"delivered" :
|
"delivered" :
|
||||||
{"type":"date"}
|
{"type":"date"},
|
||||||
|
"edited" :
|
||||||
|
{"type":"int", "size":1}
|
||||||
}';
|
}';
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
@ -59,6 +67,10 @@ class Message extends Model {
|
||||||
$jid = explode('/',(string)$stanza->attributes()->from);
|
$jid = explode('/',(string)$stanza->attributes()->from);
|
||||||
$to = current(explode('/',(string)$stanza->attributes()->to));
|
$to = current(explode('/',(string)$stanza->attributes()->to));
|
||||||
|
|
||||||
|
if(isset($stanza->attributes()->id)) {
|
||||||
|
$this->id = (string)$stanza->attributes()->id;
|
||||||
|
}
|
||||||
|
|
||||||
// This is not very beautiful
|
// This is not very beautiful
|
||||||
$user = new \User;
|
$user = new \User;
|
||||||
$this->session = $user->getLogin();
|
$this->session = $user->getLogin();
|
||||||
|
@ -87,6 +99,12 @@ class Message extends Model {
|
||||||
// $this->html = \prepareString($this->body, false, $images);
|
// $this->html = \prepareString($this->body, false, $images);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
if($stanza->replace) {
|
||||||
|
$this->newid = $this->id;
|
||||||
|
$this->id = (string)$stanza->replace->attributes()->id;
|
||||||
|
$this->edited = true;
|
||||||
|
}
|
||||||
|
|
||||||
if($stanza->delay)
|
if($stanza->delay)
|
||||||
$this->published = gmdate('Y-m-d H:i:s', strtotime($stanza->delay->attributes()->stamp));
|
$this->published = gmdate('Y-m-d H:i:s', strtotime($stanza->delay->attributes()->stamp));
|
||||||
elseif($parent && $parent->delay)
|
elseif($parent && $parent->delay)
|
||||||
|
|
|
@ -5,43 +5,27 @@ namespace modl;
|
||||||
class MessageDAO extends SQL {
|
class MessageDAO extends SQL {
|
||||||
function set(Message $message) {
|
function set(Message $message) {
|
||||||
$this->_sql = '
|
$this->_sql = '
|
||||||
insert into message
|
update message
|
||||||
(
|
set id = :thread,
|
||||||
session,
|
body = :body,
|
||||||
jidto,
|
html = :html,
|
||||||
jidfrom,
|
published = :published,
|
||||||
resource,
|
delivered = :delivered,
|
||||||
type,
|
edited = 1
|
||||||
subject,
|
|
||||||
thread,
|
where session = :session
|
||||||
body,
|
and id = :id
|
||||||
html,
|
and jidto = :jidto
|
||||||
published,
|
and jidfrom = :jidfrom';
|
||||||
delivered)
|
|
||||||
values(
|
|
||||||
:session,
|
|
||||||
:jidto,
|
|
||||||
:jidfrom,
|
|
||||||
:resource,
|
|
||||||
:type,
|
|
||||||
:subject,
|
|
||||||
:thread,
|
|
||||||
:body,
|
|
||||||
:html,
|
|
||||||
:published,
|
|
||||||
:delivered
|
|
||||||
)';
|
|
||||||
|
|
||||||
$this->prepare(
|
$this->prepare(
|
||||||
'Message',
|
'Message',
|
||||||
array(
|
array(
|
||||||
|
'thread' => $message->newid, // FIXME
|
||||||
|
'id' => $message->id,
|
||||||
'session' => $message->session,
|
'session' => $message->session,
|
||||||
'jidto' => $message->jidto,
|
'jidto' => $message->jidto,
|
||||||
'jidfrom' => $message->jidfrom,
|
'jidfrom' => $message->jidfrom,
|
||||||
'resource' => $message->resource,
|
|
||||||
'type' => $message->type,
|
|
||||||
'subject' => $message->subject,
|
|
||||||
'thread' => $message->thread,
|
|
||||||
'body' => $message->body,
|
'body' => $message->body,
|
||||||
'html' => $message->html,
|
'html' => $message->html,
|
||||||
'published' => $message->published,
|
'published' => $message->published,
|
||||||
|
@ -49,10 +33,85 @@ class MessageDAO extends SQL {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->run('Message');
|
||||||
|
|
||||||
|
if(!$this->_effective) {
|
||||||
|
$this->_sql = '
|
||||||
|
insert into message
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
session,
|
||||||
|
jidto,
|
||||||
|
jidfrom,
|
||||||
|
resource,
|
||||||
|
type,
|
||||||
|
subject,
|
||||||
|
thread,
|
||||||
|
body,
|
||||||
|
html,
|
||||||
|
published,
|
||||||
|
delivered)
|
||||||
|
values(
|
||||||
|
:id,
|
||||||
|
:session,
|
||||||
|
:jidto,
|
||||||
|
:jidfrom,
|
||||||
|
:resource,
|
||||||
|
:type,
|
||||||
|
:subject,
|
||||||
|
:thread,
|
||||||
|
:body,
|
||||||
|
:html,
|
||||||
|
:published,
|
||||||
|
:delivered
|
||||||
|
)';
|
||||||
|
|
||||||
|
$this->prepare(
|
||||||
|
'Message',
|
||||||
|
array(
|
||||||
|
'id' => $message->id,
|
||||||
|
'session' => $message->session,
|
||||||
|
'jidto' => $message->jidto,
|
||||||
|
'jidfrom' => $message->jidfrom,
|
||||||
|
'resource' => $message->resource,
|
||||||
|
'type' => $message->type,
|
||||||
|
'subject' => $message->subject,
|
||||||
|
'thread' => $message->thread,
|
||||||
|
'body' => $message->body,
|
||||||
|
'html' => $message->html,
|
||||||
|
'published' => $message->published,
|
||||||
|
'delivered' => $message->delivered
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->run('Message');
|
return $this->run('Message');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContact($jid, $limitf = false, $limitr = false) {
|
function getLastItem($to)
|
||||||
|
{
|
||||||
|
$this->_sql = '
|
||||||
|
select * from message
|
||||||
|
where session = :session
|
||||||
|
and jidto = :jidto
|
||||||
|
and jidfrom = :jidfrom
|
||||||
|
order by published desc
|
||||||
|
limit 1';
|
||||||
|
|
||||||
|
$this->prepare(
|
||||||
|
'Message',
|
||||||
|
array(
|
||||||
|
'session' => $this->_user,
|
||||||
|
'jidto' => $to,
|
||||||
|
'jidfrom' => $this->_user
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->run('Message', 'item');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContact($jid, $limitf = false, $limitr = false)
|
||||||
|
{
|
||||||
$this->_sql = '
|
$this->_sql = '
|
||||||
select * from message
|
select * from message
|
||||||
where session = :session
|
where session = :session
|
||||||
|
|
|
@ -123,7 +123,8 @@ class Postn extends Model {
|
||||||
else
|
else
|
||||||
$entry = $item;
|
$entry = $item;
|
||||||
|
|
||||||
$this->__set('origin', $from);
|
if($from != '')
|
||||||
|
$this->__set('origin', $from);
|
||||||
|
|
||||||
if($node)
|
if($node)
|
||||||
$this->__set('node', $node);
|
$this->__set('node', $node);
|
||||||
|
@ -358,9 +359,9 @@ class Postn extends Model {
|
||||||
public function getPublicUrl()
|
public function getPublicUrl()
|
||||||
{
|
{
|
||||||
if($this->isMicroblog()) {
|
if($this->isMicroblog()) {
|
||||||
return \Route::urlize('blog', array($this->origin));
|
return \Route::urlize('blog', array($this->origin, $this->nodeid));
|
||||||
} else {
|
} else {
|
||||||
return \Route::urlize('node', array($this->origin, $this->node));
|
return \Route::urlize('node', array($this->origin, $this->node, $this->nodeid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -577,6 +577,32 @@ class PostnDAO extends SQL {
|
||||||
return $this->run('Postn');
|
return $this->run('Postn');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLastBlogPublic($limitf = false, $limitr = false)
|
||||||
|
{
|
||||||
|
$this->_sql = '
|
||||||
|
select * from postn
|
||||||
|
left outer join contact on postn.aid = contact.jid
|
||||||
|
left outer join privacy on postn.nodeid = privacy.pkey
|
||||||
|
where
|
||||||
|
node = \'urn:xmpp:microblog:0\'
|
||||||
|
and postn.origin not in (select jid from rosterlink where session = :origin)
|
||||||
|
and privacy.value = 1
|
||||||
|
order by published desc
|
||||||
|
';
|
||||||
|
|
||||||
|
if($limitr)
|
||||||
|
$this->_sql = $this->_sql.' limit '.$limitr.' offset '.$limitf;
|
||||||
|
|
||||||
|
$this->prepare(
|
||||||
|
'Postn',
|
||||||
|
array(
|
||||||
|
'origin' => $this->_user
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->run('ContactPostn');
|
||||||
|
}
|
||||||
|
|
||||||
function exist($id) {
|
function exist($id) {
|
||||||
$this->_sql = '
|
$this->_sql = '
|
||||||
select count(*) from postn
|
select count(*) from postn
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<main>
|
<main>
|
||||||
<?php $this->widget('Header'); ?>
|
<?php $this->widget('Header');?>
|
||||||
<section>
|
<section>
|
||||||
<?php $this->widget('AdminLogin');?>
|
<?php $this->widget('AdminLogin');?>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Blog extends WidgetBase {
|
||||||
|
|
||||||
$description = stripTags($this->_messages[0]->contentcleaned);
|
$description = stripTags($this->_messages[0]->contentcleaned);
|
||||||
if(!empty($description)) {
|
if(!empty($description)) {
|
||||||
$this->description = $description;
|
$this->description = truncate($description, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
$attachements = $this->_messages[0]->getAttachements();
|
$attachements = $this->_messages[0]->getAttachements();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<span class="primary icon gray">
|
<span class="primary icon gray">
|
||||||
<i class="zmdi zmdi-edit"></i>
|
<i class="zmdi zmdi-edit"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="control icon">
|
<span class="control icon active">
|
||||||
<a
|
<a
|
||||||
href="{$c->route('feed', array($contact->jid))}"
|
href="{$c->route('feed', array($contact->jid))}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|
|
@ -10,6 +10,8 @@ use Moxl\Xec\Action\Muc\SetSubject;
|
||||||
|
|
||||||
use Respect\Validation\Validator;
|
use Respect\Validation\Validator;
|
||||||
|
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
|
||||||
class Chat extends WidgetBase
|
class Chat extends WidgetBase
|
||||||
{
|
{
|
||||||
private $_pagination = 30;
|
private $_pagination = 30;
|
||||||
|
@ -223,7 +225,7 @@ class Chat extends WidgetBase
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function ajaxSendMessage($to, $message, $muc = false, $resource = false) {
|
function ajaxSendMessage($to, $message, $muc = false, $resource = false, $replace = false) {
|
||||||
if($message == '')
|
if($message == '')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -232,6 +234,18 @@ class Chat extends WidgetBase
|
||||||
$m->jidto = echapJid($to);
|
$m->jidto = echapJid($to);
|
||||||
$m->jidfrom = $this->user->getLogin();
|
$m->jidfrom = $this->user->getLogin();
|
||||||
|
|
||||||
|
if($replace != false) {
|
||||||
|
$m->newid = Uuid::uuid4();
|
||||||
|
$m->id = $replace->id;
|
||||||
|
$m->edited = true;
|
||||||
|
$m->published = $replace->published;
|
||||||
|
$m->delivered = $replace->delivered;
|
||||||
|
} else {
|
||||||
|
$m->id = Uuid::uuid4();
|
||||||
|
$m->published = gmdate('Y-m-d H:i:s');
|
||||||
|
$m->delivered = gmdate('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
$session = \Sessionx::start();
|
$session = \Sessionx::start();
|
||||||
|
|
||||||
$m->type = 'chat';
|
$m->type = 'chat';
|
||||||
|
@ -250,10 +264,8 @@ class Chat extends WidgetBase
|
||||||
$m->jidfrom = $to;
|
$m->jidfrom = $to;
|
||||||
}
|
}
|
||||||
|
|
||||||
$m->body = rawurldecode($message);
|
$m->body = trim(rawurldecode($message));
|
||||||
//$m->html = prepareString($m->body, false, true);
|
//$m->html = prepareString($m->body, false, true);
|
||||||
$m->published = gmdate('Y-m-d H:i:s');
|
|
||||||
$m->delivered = gmdate('Y-m-d H:i:s');
|
|
||||||
|
|
||||||
if($resource != false) {
|
if($resource != false) {
|
||||||
$to = $to . '/' . $resource;
|
$to = $to . '/' . $resource;
|
||||||
|
@ -265,6 +277,13 @@ class Chat extends WidgetBase
|
||||||
//$p->setHTML($m->html);
|
//$p->setHTML($m->html);
|
||||||
$p->setContent($m->body);
|
$p->setContent($m->body);
|
||||||
|
|
||||||
|
if($replace != false) {
|
||||||
|
$p->setId($m->newid);
|
||||||
|
$p->setReplace($m->id);
|
||||||
|
} else {
|
||||||
|
$p->setId($m->id);
|
||||||
|
}
|
||||||
|
|
||||||
if($muc) {
|
if($muc) {
|
||||||
$p->setMuc();
|
$p->setMuc();
|
||||||
}
|
}
|
||||||
|
@ -284,6 +303,37 @@ class Chat extends WidgetBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a correction message
|
||||||
|
*
|
||||||
|
* @param string $to
|
||||||
|
* @param string $message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ajaxCorrect($to, $message)
|
||||||
|
{
|
||||||
|
$md = new \Modl\MessageDAO;
|
||||||
|
$m = $md->getLastItem($to);
|
||||||
|
|
||||||
|
if($m) {
|
||||||
|
$this->ajaxSendMessage($to, $message, false, false, $m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last message sent
|
||||||
|
*
|
||||||
|
* @param string $to
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ajaxLast($to)
|
||||||
|
{
|
||||||
|
$md = new \Modl\MessageDAO;
|
||||||
|
$m = $md->getLastItem($to);
|
||||||
|
|
||||||
|
RPC::call('Chat.setTextarea', $m->body);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a "composing" message
|
* @brief Send a "composing" message
|
||||||
*
|
*
|
||||||
|
|
|
@ -111,6 +111,10 @@
|
||||||
state = 0;
|
state = 0;
|
||||||
Chat.sendMessage(this.dataset.jid, {if="$muc"}true{else}false{/if});
|
Chat.sendMessage(this.dataset.jid, {if="$muc"}true{else}false{/if});
|
||||||
return false;
|
return false;
|
||||||
|
} else if(event.keyCode == 38) {
|
||||||
|
Chat_ajaxLast(this.dataset.jid);
|
||||||
|
} else if(event.keyCode == 40) {
|
||||||
|
Chat.clearReplace();
|
||||||
} else {
|
} else {
|
||||||
{if="!$muc"}
|
{if="!$muc"}
|
||||||
if(state == 0 || state == 2) {
|
if(state == 0 || state == 2) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ var Chat = {
|
||||||
previous: null,
|
previous: null,
|
||||||
date: null,
|
date: null,
|
||||||
lastScroll: null,
|
lastScroll: null,
|
||||||
|
edit: false,
|
||||||
addSmiley: function(element) {
|
addSmiley: function(element) {
|
||||||
var n = document.querySelector('#chat_textarea');
|
var n = document.querySelector('#chat_textarea');
|
||||||
n.value = n.value + element.dataset.emoji;
|
n.value = n.value + element.dataset.emoji;
|
||||||
|
@ -18,7 +19,12 @@ var Chat = {
|
||||||
n.value = "";
|
n.value = "";
|
||||||
n.focus();
|
n.focus();
|
||||||
movim_textarea_autoheight(n);
|
movim_textarea_autoheight(n);
|
||||||
Chat_ajaxSendMessage(jid, encodeURIComponent(text), muc);
|
if(Chat.edit) {
|
||||||
|
Chat.edit = false;
|
||||||
|
Chat_ajaxCorrect(jid, encodeURIComponent(text));
|
||||||
|
} else {
|
||||||
|
Chat_ajaxSendMessage(jid, encodeURIComponent(text), muc);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
focus: function()
|
focus: function()
|
||||||
{
|
{
|
||||||
|
@ -26,8 +32,15 @@ var Chat = {
|
||||||
document.querySelector('#chat_textarea').focus();
|
document.querySelector('#chat_textarea').focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
appendTextarea: function(value)
|
setTextarea: function(value)
|
||||||
{
|
{
|
||||||
|
Chat.edit = true;
|
||||||
|
document.querySelector('#chat_textarea').value = value;
|
||||||
|
},
|
||||||
|
clearReplace: function()
|
||||||
|
{
|
||||||
|
Chat.edit = false;
|
||||||
|
document.querySelector('#chat_textarea').value = '';
|
||||||
},
|
},
|
||||||
notify : function(title, body, image)
|
notify : function(title, body, image)
|
||||||
{
|
{
|
||||||
|
@ -70,6 +83,7 @@ var Chat = {
|
||||||
for(var i = 0, len = messages.length; i < len; ++i ) {
|
for(var i = 0, len = messages.length; i < len; ++i ) {
|
||||||
Chat.appendMessage(messages[i], false);
|
Chat.appendMessage(messages[i], false);
|
||||||
}
|
}
|
||||||
|
Chat.edit = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
appendMessage : function(message, prepend) {
|
appendMessage : function(message, prepend) {
|
||||||
|
@ -127,6 +141,12 @@ var Chat = {
|
||||||
id = message.jidfrom + '_conversation';
|
id = message.jidfrom + '_conversation';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(message.id != null) {
|
||||||
|
bubble.id = message.id;
|
||||||
|
if(message.newid != null)
|
||||||
|
bubble.id = message.newid;
|
||||||
|
}
|
||||||
|
|
||||||
if(message.body.match(/^\/me/)) {
|
if(message.body.match(/^\/me/)) {
|
||||||
bubble.querySelector('div.bubble').className = 'bubble quote';
|
bubble.querySelector('div.bubble').className = 'bubble quote';
|
||||||
message.body = message.body.substr(4);
|
message.body = message.body.substr(4);
|
||||||
|
@ -135,7 +155,12 @@ var Chat = {
|
||||||
if(bubble) {
|
if(bubble) {
|
||||||
bubble.querySelector('div.bubble > p').innerHTML = message.body.replace(/\r\n?|\n/g, '<br />');
|
bubble.querySelector('div.bubble > p').innerHTML = message.body.replace(/\r\n?|\n/g, '<br />');
|
||||||
|
|
||||||
bubble.querySelector('div.bubble > span.info').innerHTML = message.publishedPrepared;
|
var info = bubble.querySelector('div.bubble > span.info');
|
||||||
|
info.innerHTML = message.publishedPrepared;
|
||||||
|
|
||||||
|
if(message.edited) {
|
||||||
|
info.innerHTML = '<i class="zmdi zmdi-edit"></i> ' + info.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
if(prepend) {
|
if(prepend) {
|
||||||
Chat.date = message.published;
|
Chat.date = message.published;
|
||||||
|
@ -148,6 +173,10 @@ var Chat = {
|
||||||
var scrollDiff = discussion.scrollHeight - Chat.lastScroll;
|
var scrollDiff = discussion.scrollHeight - Chat.lastScroll;
|
||||||
discussion.scrollTop += scrollDiff;
|
discussion.scrollTop += scrollDiff;
|
||||||
Chat.lastScroll = discussion.scrollHeight;
|
Chat.lastScroll = discussion.scrollHeight;
|
||||||
|
} else if(message.edited) {
|
||||||
|
var elem = document.getElementById(message.id);
|
||||||
|
if(elem)
|
||||||
|
elem.parentElement.replaceChild(bubble, elem);
|
||||||
} else {
|
} else {
|
||||||
movim_append(id, bubble.outerHTML);
|
movim_append(id, bubble.outerHTML);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
#chats_widget_list:empty ~ .placeholder {
|
#chats_widget_list:empty ~ .placeholder {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<div>
|
<div>
|
||||||
<a href="{$c->route('main')}" class="classic">
|
<ul class="list middle">
|
||||||
<span id="menu" class="icon"><i class="zmdi zmdi-home"></i></span>
|
<li>
|
||||||
</a>
|
<span class="primary icon gray active">
|
||||||
<h2>{$c->__('page.about')}</h2>
|
<a href="{$c->route('main')}">
|
||||||
|
<i class="zmdi zmdi-arrow-back"></i>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<p>{$c->__('page.about')}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<div>
|
<div>
|
||||||
<ul class="list middle">
|
<ul class="list middle">
|
||||||
<li>
|
<li>
|
||||||
<a href="{$c->route('main')}" class="active classic">
|
<span class="primary icon active">
|
||||||
<span id="menu" class="icon"><i class="zmdi zmdi-home"></i></span>
|
<a href="{$c->route('main')}">
|
||||||
</a>
|
<i class="zmdi zmdi-arrow-back"></i>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<p>{$c->__('page.administration')}</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<div>
|
<div>
|
||||||
<a href="{$c->route('main')}" class="classic">
|
<ul class="list middle">
|
||||||
<span id="menu" class="icon"><i class="zmdi zmdi-home"></i></span>
|
<li>
|
||||||
</a>
|
<span class="primary icon active">
|
||||||
<h2>{$c->__('page.administration')}</h2>
|
<a href="{$c->route('main')}">
|
||||||
|
<i class="zmdi zmdi-arrow-back"></i>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<p>{$c->__('page.administration')}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -144,25 +144,27 @@ var Notification = {
|
||||||
|
|
||||||
Notification.document_title_init = document.title;
|
Notification.document_title_init = document.title;
|
||||||
|
|
||||||
MovimWebsocket.attach(function() {
|
if(typeof MovimWebsocket != 'undefined') {
|
||||||
if(typeof Favico != 'undefined') {
|
MovimWebsocket.attach(function() {
|
||||||
Notification.favicon = new Favico({
|
if(typeof Favico != 'undefined') {
|
||||||
animation: 'none',
|
Notification.favicon = new Favico({
|
||||||
fontStyle: 'normal',
|
animation: 'none',
|
||||||
bgColor: '#FF5722'
|
fontStyle: 'normal',
|
||||||
});
|
bgColor: '#FF5722'
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(typeof require !== 'undefined') {
|
if(typeof require !== 'undefined') {
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
Notification.electron = remote.getCurrentWindow();
|
Notification.electron = remote.getCurrentWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification.document_title = Notification.document_title_init;
|
Notification.document_title = Notification.document_title_init;
|
||||||
Notification.tab_counter1 = Notification.tab_counter2 = 0;
|
Notification.tab_counter1 = Notification.tab_counter2 = 0;
|
||||||
Notification_ajaxGet();
|
Notification_ajaxGet();
|
||||||
Notification.current(Notification.notifs_key);
|
Notification.current(Notification.notifs_key);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
document.onblur = function() {
|
document.onblur = function() {
|
||||||
Notification.focused = false;
|
Notification.focused = false;
|
||||||
|
|
|
@ -165,7 +165,8 @@ class Post extends WidgetBase
|
||||||
|
|
||||||
$nd = new \modl\PostnDAO();
|
$nd = new \modl\PostnDAO();
|
||||||
$view = $this->tpl();
|
$view = $this->tpl();
|
||||||
$view->assign('posts', $nd->getLastPublished(0, 10));
|
$view->assign('blogs', $nd->getLastBlogPublic(0, 6));
|
||||||
|
$view->assign('posts', $nd->getLastPublished(0, 4));
|
||||||
|
|
||||||
return $view->draw('_post_empty', true);
|
return $view->draw('_post_empty', true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if="($public && $post->isPublic()) || !$public"}
|
{if="($public && $post->isPublic()) || !$public"}
|
||||||
|
@ -239,8 +239,11 @@
|
||||||
</form>
|
</form>
|
||||||
</span>
|
</span>
|
||||||
<p class="line normal">
|
<p class="line normal">
|
||||||
|
{$c->__('post.public')}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
<a target="_blank" href="{$post->getPublicUrl()}">
|
<a target="_blank" href="{$post->getPublicUrl()}">
|
||||||
{$c->__('post.public')}
|
{$c->__('post.public_url')}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,6 +1,74 @@
|
||||||
<br />
|
<header>
|
||||||
<h2 class="thin">{$c->__('post.hot')}</h2>
|
<ul class="list middle">
|
||||||
<h4 class="gray">{$c->__('post.hot_text')}</h4><br />
|
<li>
|
||||||
|
<p>
|
||||||
|
{$c->__('post.hot')}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="primary icon gray">
|
||||||
|
<i class="zmdi zmdi-account"></i>
|
||||||
|
</span>
|
||||||
|
<p>
|
||||||
|
<h4 class="gray">{$c->__('post.blog_last')}</h4>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
<ul class="list flex card shadow active">
|
||||||
|
{loop="$blogs"}
|
||||||
|
{$attachements = $value->getAttachements()}
|
||||||
|
<li
|
||||||
|
class="block condensed"
|
||||||
|
data-id="{$value->nodeid}"
|
||||||
|
data-server="{$value->origin}"
|
||||||
|
data-node="{$value->node}">
|
||||||
|
{$picture = $value->getPicture()}
|
||||||
|
{if="$picture != null"}
|
||||||
|
<span class="primary icon thumb" style="background-image: url({$picture});"></span>
|
||||||
|
{else}
|
||||||
|
{$url = $value->getContact()->getPhoto('l')}
|
||||||
|
{if="$url"}
|
||||||
|
<span class="primary icon thumb" style="background-image: url({$url});">
|
||||||
|
</span>
|
||||||
|
{else}
|
||||||
|
<span class="primary icon thumb color {$value->getContact()->jid|stringToColor}">
|
||||||
|
<i class="zmdi zmdi-account"></i>
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
<p class="line">
|
||||||
|
{if="isset($value->title)"}
|
||||||
|
{$value->title}
|
||||||
|
{else}
|
||||||
|
{$value->node}
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="{$c->route('contact', $value->getContact()->jid)}">
|
||||||
|
<i class="zmdi zmdi-account"></i> {$value->getContact()->getTrueName()}
|
||||||
|
</a> –
|
||||||
|
{$value->published|strtotime|prepareDate}
|
||||||
|
{if="$value->published != $value->updated"}<i class="zmdi zmdi-edit"></i>{/if}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{$value->contentcleaned|strip_tags}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{/loop}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list thick">
|
||||||
|
<li>
|
||||||
|
<span class="primary icon gray">
|
||||||
|
<i class="zmdi zmdi-pages"></i>
|
||||||
|
</span>
|
||||||
|
<p>
|
||||||
|
<h4 class="gray">{$c->__('post.hot_text')}</h4>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<ul class="list flex card shadow active">
|
<ul class="list flex card shadow active">
|
||||||
{loop="$posts"}
|
{loop="$posts"}
|
||||||
{if="!filter_var($value->origin, FILTER_VALIDATE_EMAIL)"}
|
{if="!filter_var($value->origin, FILTER_VALIDATE_EMAIL)"}
|
||||||
|
|
|
@ -9,10 +9,12 @@ hot_text = Posts recently published in Groups that you are not subscribed
|
||||||
new = New post
|
new = New post
|
||||||
repost = This is a re-post from %s
|
repost = This is a re-post from %s
|
||||||
repost_profile = See %s profile
|
repost_profile = See %s profile
|
||||||
|
blog_last = Public posts from users
|
||||||
|
|
||||||
public = Publish this post publicly?
|
public = Publish this post publicly?
|
||||||
public_yes = This post is now public
|
public_yes = This post is now public
|
||||||
public_no = This post is now private
|
public_no = This post is now private
|
||||||
|
public_url = Public URL of this post
|
||||||
|
|
||||||
delete_title = Delete this post
|
delete_title = Delete this post
|
||||||
delete_text = You are going to delete this post, please confirm your action
|
delete_text = You are going to delete this post, please confirm your action
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
#roster form div {
|
|
||||||
min-height: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#roster form div input {
|
|
||||||
padding-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#roster ul#rosterlist > div > li {
|
#roster ul#rosterlist > div > li {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
"forxer/Gravatar": "~1.2",
|
"forxer/Gravatar": "~1.2",
|
||||||
"respect/validation": "1.0.*",
|
"respect/validation": "1.0.*",
|
||||||
"ezyang/htmlpurifier": "^4.7"
|
"ezyang/htmlpurifier": "^4.7",
|
||||||
|
"ramsey/uuid": "^3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ $stdin_behaviour = function ($data) use (&$conn, $loop, &$buffer, &$connector, &
|
||||||
} elseif($msg->func == 'unregister') {
|
} elseif($msg->func == 'unregister') {
|
||||||
\Moxl\Stanza\Stream::end();
|
\Moxl\Stanza\Stream::end();
|
||||||
} elseif($msg->func == 'register') {
|
} elseif($msg->func == 'register') {
|
||||||
if(is_resource($conn->stream)) {
|
if(isset($conn)
|
||||||
|
&& is_resource($conn->stream)) {
|
||||||
$conn->stream->close();
|
$conn->stream->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class AjaxController extends BaseController
|
||||||
{
|
{
|
||||||
protected $funclist = array();
|
protected $funclist = array();
|
||||||
protected static $instance;
|
protected static $instance;
|
||||||
|
protected $widgetlist = array();
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -49,11 +50,20 @@ class AjaxController extends BaseController
|
||||||
return $buffer . "</script>\n";
|
return $buffer . "</script>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the widget is registered
|
||||||
|
*/
|
||||||
|
public function isRegistered($widget)
|
||||||
|
{
|
||||||
|
return array_key_exists($widget, $this->widgetlist);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a new function.
|
* Defines a new function.
|
||||||
*/
|
*/
|
||||||
public function defun($widget, $funcname, array $params)
|
public function defun($widget, $funcname, array $params)
|
||||||
{
|
{
|
||||||
|
array_push($this->widgetlist, $widget);
|
||||||
$this->funclist[$widget.$funcname] = array(
|
$this->funclist[$widget.$funcname] = array(
|
||||||
'object' => $widget,
|
'object' => $widget,
|
||||||
'funcname' => $funcname,
|
'funcname' => $funcname,
|
||||||
|
|
|
@ -4,17 +4,11 @@ class BaseController {
|
||||||
public $name = 'main'; // The name of the current page
|
public $name = 'main'; // The name of the current page
|
||||||
protected $session_only = false;// The page is protected by a session ?
|
protected $session_only = false;// The page is protected by a session ?
|
||||||
protected $raw = false; // Display only the content ?
|
protected $raw = false; // Display only the content ?
|
||||||
|
protected $public = false; // It's a public page
|
||||||
protected $page;
|
protected $page;
|
||||||
|
|
||||||
function __construct() {
|
function __construct() {
|
||||||
$this->page = new TplPageBuilder();
|
$this->page = new TplPageBuilder();
|
||||||
$this->page->addScript('movim_hash.js');
|
|
||||||
$this->page->addScript('movim_utils.js');
|
|
||||||
$this->page->addScript('movim_base.js');
|
|
||||||
$this->page->addScript('movim_tpl.js');
|
|
||||||
$this->page->addScript('movim_websocket.js');
|
|
||||||
$this->page->addScript('movim_map.js');
|
|
||||||
$this->page->addScript('pako_inflate.js');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +57,17 @@ class BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
function display() {
|
function display() {
|
||||||
|
$this->page->addScript('movim_hash.js');
|
||||||
|
$this->page->addScript('movim_utils.js');
|
||||||
|
$this->page->addScript('movim_base.js');
|
||||||
|
|
||||||
|
if(!$this->public) {
|
||||||
|
$this->page->addScript('movim_tpl.js');
|
||||||
|
$this->page->addScript('movim_websocket.js');
|
||||||
|
$this->page->addScript('movim_map.js');
|
||||||
|
$this->page->addScript('pako_inflate.js');
|
||||||
|
}
|
||||||
|
|
||||||
if($this->session_only) {
|
if($this->session_only) {
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$content = new TplPageBuilder($user);
|
$content = new TplPageBuilder($user);
|
||||||
|
|
|
@ -14,7 +14,6 @@ class TplPageBuilder
|
||||||
{
|
{
|
||||||
private $theme = 'movim';
|
private $theme = 'movim';
|
||||||
private $_view = '';
|
private $_view = '';
|
||||||
private $_color = 'green';
|
|
||||||
private $title = '';
|
private $title = '';
|
||||||
private $menu = array();
|
private $menu = array();
|
||||||
private $content = '';
|
private $content = '';
|
||||||
|
|
|
@ -56,19 +56,21 @@ class WidgetBase
|
||||||
// Put default widget init here.
|
// Put default widget init here.
|
||||||
$this->ajax = AjaxController::getInstance();
|
$this->ajax = AjaxController::getInstance();
|
||||||
|
|
||||||
// Generating Ajax calls.
|
if(!$this->ajax->isRegistered($this->name)) {
|
||||||
$refl = new ReflectionClass($this->name);
|
// Generating Ajax calls.
|
||||||
$meths = $refl->getMethods();
|
$refl = new ReflectionClass($this->name);
|
||||||
|
$meths = $refl->getMethods();
|
||||||
|
|
||||||
foreach($meths as $method) {
|
foreach($meths as $method) {
|
||||||
if(preg_match('#^ajax#', $method->name)) {
|
if(preg_match('#^ajax#', $method->name)) {
|
||||||
$pars = $method->getParameters();
|
$pars = $method->getParameters();
|
||||||
$params = array();
|
$params = array();
|
||||||
foreach($pars as $param) {
|
foreach($pars as $param) {
|
||||||
$params[] = $param->name;
|
$params[] = $param->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ajax->defun($this->name, $method->name, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->ajax->defun($this->name, $method->name, $params);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
main > header a,
|
main > header a,
|
||||||
.icon:not(.placeholder) a,
|
.icon:not(.placeholder):not(.active) a,
|
||||||
.color input {
|
.color input {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,3 +27,16 @@ header.fixed + div {
|
||||||
margin-top: 7rem;
|
margin-top: 7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header ul:first-child > li:first-child {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific forms in header */
|
||||||
|
header form > div:not(.clear):not(.control) {
|
||||||
|
min-height: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header form > div > input:not([type=submit]) {
|
||||||
|
padding-top: 2rem;
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,11 @@ ul.list li.subheader p {
|
||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.list li .primary > a,
|
||||||
|
ul.list li .control > a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
/* Truncated content */
|
/* Truncated content */
|
||||||
|
|
||||||
ul.list li.subheader > p,
|
ul.list li.subheader > p,
|
||||||
|
@ -276,8 +281,8 @@ ul li span.counter.bottom {
|
||||||
/* Bubble */
|
/* Bubble */
|
||||||
|
|
||||||
ul li div.bubble {
|
ul li div.bubble {
|
||||||
padding: 1rem 2rem;
|
padding: 1.25rem 2rem 0.75rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.5rem;
|
||||||
line-height: 2.75rem;
|
line-height: 2.75rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -303,6 +308,7 @@ ul li.oppose div.bubble {
|
||||||
margin-right: 9rem;
|
margin-right: 9rem;
|
||||||
float: right;
|
float: right;
|
||||||
position: initial;
|
position: initial;
|
||||||
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul li div.bubble span.info {
|
ul li div.bubble span.info {
|
||||||
|
@ -341,6 +347,7 @@ ul li:not(.same) div.bubble:before {
|
||||||
ul li.oppose:not(.same) div.bubble:before {
|
ul li.oppose:not(.same) div.bubble:before {
|
||||||
left: calc(100% - 10.5rem);
|
left: calc(100% - 10.5rem);
|
||||||
top: 1.5rem;
|
top: 1.5rem;
|
||||||
|
border-top-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icon */
|
/* Icon */
|
||||||
|
|
Loading…
Add table
Reference in a new issue