1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/movim_ynh.git synced 2024-09-03 19:46:19 +02:00

update to movim 0.9 git-2015-12-15

This commit is contained in:
Xavier ROOT 2015-12-15 11:54:49 +01:00
parent 506a3cdf95
commit c36a234b7f
977 changed files with 3500 additions and 2899 deletions

View file

@ -1,7 +1,7 @@
Movim Installation Movim Installation
=================== ===================
* Movim deployment tutorial: http://wiki.movim.eu/en:install * Movim deployment tutorial: https://github.com/edhelas/movim/wiki/Install-Movim
You can also follow the Jappix project documentation for a full stack deployment: You can also follow the Jappix project documentation for a full stack deployment:

View file

@ -7,7 +7,7 @@ Movim is a decentralized social network, written in PHP and HTML5 and based on t
Installation Installation
------------ ------------
Please refer to the installation instructions that are available on the official Wiki : https://wiki.movim.eu . Please refer to the installation instructions that are available on the GitHub Wiki : https://github.com/edhelas/movim/wiki .
Translations Translations
@ -26,6 +26,12 @@ You can also use Movim on our official Pods :
* https://pod.movim.eu/ server hosted in France * https://pod.movim.eu/ server hosted in France
* https://nl.movim.eu/ server hosted in The Netherlands * https://nl.movim.eu/ server hosted in The Netherlands
### Librairies
Movim also contains two specific librairies :
* https://github.com/edhelas/moxl Moxl (for Movim XMPP Library) is a PHP XMPP library especially made for the Movim project
* https://github.com/edhelas/modl Modl (for Movim Data Layer) is a light PHP Database layer using DAO pattern
Support Us Support Us
---------- ----------
You can support us on : You can support us on :

View file

@ -26,6 +26,7 @@ var MovimWebsocket = {
attached: new Array(), attached: new Array(),
registered: new Array(), registered: new Array(),
unregistered: false, unregistered: false,
attempts: 1,
launchAttached : function() { launchAttached : function() {
for(var i = 0; i < MovimWebsocket.attached.length; i++) { for(var i = 0; i < MovimWebsocket.attached.length; i++) {
@ -50,6 +51,7 @@ var MovimWebsocket = {
this.connection.onopen = function(e) { this.connection.onopen = function(e) {
console.log("Connection established!"); console.log("Connection established!");
MovimWebsocket.attempts = 1;
MovimWebsocket.launchAttached(); MovimWebsocket.launchAttached();
}; };
@ -87,14 +89,25 @@ var MovimWebsocket = {
}; };
this.connection.onerror = function(e) { this.connection.onerror = function(e) {
console.log(e.code);
console.log(e);
console.log("Connection error!"); console.log("Connection error!");
setTimeout(function () {
// We've tried to reconnect so increment the attempts by 1
MovimWebsocket.attempts++;
// Connection has closed so try to reconnect every 10 seconds.
MovimWebsocket.init();
}, MovimWebsocket.generateInterval());
// We prevent the onclose launch // We prevent the onclose launch
this.onclose = null; this.onclose = null;
}; };
}, },
send : function(widget, func, params) { send : function(widget, func, params) {
if(this.connection.readyState != 0) { if(this.connection.readyState == 1) {
this.connection.send( this.connection.send(
JSON.stringify( JSON.stringify(
{'func' : 'message', 'body' : {'func' : 'message', 'body' :
@ -151,6 +164,17 @@ var MovimWebsocket = {
unregister : function(reload) { unregister : function(reload) {
if(reload == false) this.unregistered = true; if(reload == false) this.unregistered = true;
this.connection.unregister(); this.connection.unregister();
},
generateInterval :function() {
var maxInterval = (Math.pow(2, MovimWebsocket.attempts) - 1) * 1000;
if (maxInterval > 30*1000) {
maxInterval = 30*1000; // If the generated interval is more than 30 seconds, truncate it down to 30 seconds.
}
// generate the interval to a random number between 0 and the maxInterval determined from above
return Math.random() * maxInterval;
} }
} }
@ -164,6 +188,14 @@ function remoteUnregisterReload()
MovimWebsocket.unregister(true); MovimWebsocket.unregister(true);
} }
document.addEventListener("visibilitychange", function () {
if(!document.hidden) {
if(MovimWebsocket.connection.readyState == 3) {
MovimWebsocket.init();
}
}
});
window.onbeforeunload = function() { window.onbeforeunload = function() {
MovimWebsocket.connection.onclose = function () {}; // disable onclose handler first MovimWebsocket.connection.onclose = function () {}; // disable onclose handler first
MovimWebsocket.connection.close() MovimWebsocket.connection.close()

View file

@ -0,0 +1,11 @@
<?php
class NodeController extends BaseController {
function load() {
$this->session_only = false;
}
function dispatch() {
$this->page->setTitle(__('page.groups'));
}
}

View file

@ -0,0 +1,11 @@
<?php
class TagController extends BaseController {
function load() {
$this->session_only = false;
}
function dispatch() {
$this->page->setTitle(__('page.tag'));
}
}

View file

@ -23,7 +23,7 @@ class MovimEmoji
public function replace($string, $large = false) public function replace($string, $large = false)
{ {
$this->_emoji->setAssetUrlFormat($this->getPath($large)); $this->_emoji->setAssetUrlFormat($this->getPath());
$string = $this->_emoji->replaceEmojiWithImages($string); $string = $this->_emoji->replaceEmojiWithImages($string);
$this->_emoji->setAssetUrlFormat($this->getPath()); $this->_emoji->setAssetUrlFormat($this->getPath());
@ -32,10 +32,7 @@ class MovimEmoji
private function getPath($large = false) private function getPath($large = false)
{ {
$path = BASE_URI . 'themes/' . $this->_theme . '/img/emojis/'; return BASE_URI . 'themes/' . $this->_theme . '/img/emojis/svg/%s.svg';
if($large) $path .= 'large/';
return $path.'%s.png';
} }
public static function getInstance() public static function getInstance()
@ -78,6 +75,18 @@ function addUrls($string, $preview = false) {
); );
} }
function addHFR($string) {
// HFR EasterEgg
return preg_replace_callback(
'/\[:([\w\s-]+)([:\d])*\]/', function ($match) {
$num = '';
if(count($match) == 3)
$num = $match[2].'/';
return '<img class="hfr" title="'.$match[0].'" alt="'.$match[0].'" src="http://forum-images.hardware.fr/images/perso/'.$num.$match[1].'.gif">';
}, $string
);
}
/** /**
* @desc Prepare the string (add the a to the links and show the smileys) * @desc Prepare the string (add the a to the links and show the smileys)
* *
@ -346,6 +355,10 @@ function purifyHTML($string)
'muted' => 'Bool', 'muted' => 'Bool',
'controls' => 'Bool', 'controls' => 'Bool',
)); ));
$def->addElement('source', 'Block', 'Flow', 'Common', array(
'src' => 'URI',
'type' => 'Text',
));
} }
$purifier = new \HTMLPurifier($config); $purifier = new \HTMLPurifier($config);

View file

@ -197,7 +197,7 @@ class Contact extends Model {
$p->fromBase($this->photobin); $p->fromBase($this->photobin);
$p->set($this->jid); $p->set($this->jid);
if(isset($this->email)) { if(isset($this->email) && $this->email != '') {
\createEmailPic(strtolower($this->jid), $this->email); \createEmailPic(strtolower($this->jid), $this->email);
} }
} }
@ -214,7 +214,7 @@ class Contact extends Model {
public function getPhoto($size = 'l', $jid = false) { public function getPhoto($size = 'l', $jid = false) {
if($size == 'email') { if($size == 'email') {
return BASE_URI.'cache/'.strtolower($this->jid).'_email.jpg'; return BASE_URI.'cache/'.strtolower($this->jid).'_email.png';
} else { } else {
$sizes = array( $sizes = array(
'wall' => array(1920, 1080), 'wall' => array(1920, 1080),
@ -355,8 +355,10 @@ class Contact extends Model {
&& !filter_var($this->name, FILTER_VALIDATE_EMAIL) && !filter_var($this->name, FILTER_VALIDATE_EMAIL)
) )
$truename = $this->name; $truename = $this->name;
else else {
$truename = $this->jid; $truename = explodeJid($this->jid);
$truename = $truename['username'];
}
return $truename; return $truename;
} }

View file

@ -412,21 +412,6 @@ class ContactDAO extends SQL {
return (int)$results[0]; return (int)$results[0];
} }
function cleanRoster() {
$this->_sql = '
delete from rosterlink
where session = :session';
$this->prepare(
'RosterLink',
array(
'session' => $this->_user
)
);
return $this->run('RosterLink');
}
function getRoster() { function getRoster() {
$this->_sql = ' $this->_sql = '
select select
@ -495,30 +480,6 @@ class ContactDAO extends SQL {
return $this->run('RosterContact'); return $this->run('RosterContact');
} }
function getRosterChat() {
$this->_sql = '
select * from rosterlink
left outer join (
select * from presence
order by presence.priority desc
) as presence
on rosterlink.jid = presence.jid
left outer join contact
on rosterlink.jid = contact.jid
where rosterlink.session = :session
and rosterlink.chaton > 0
order by rosterlink.groupname, rosterlink.jid, presence.value';
$this->prepare(
'RosterLink',
array(
'session' => $this->_user
)
);
return $this->run('RosterContact');
}
function getRosterFrom() { function getRosterFrom() {
$this->_sql = ' $this->_sql = '
select * from rosterlink select * from rosterlink
@ -621,27 +582,6 @@ class ContactDAO extends SQL {
return $this->run('PresenceContact'); return $this->run('PresenceContact');
} }
function getMe($item = false) {
$this->_sql = '
select * from contact
left outer join presence on contact.jid = presence.jid
where contact.jid = :jid
and presence.session = :session';
$this->prepare(
'RosterLink',
array(
'session' => $this->_user,
'jid' => $this->_user
)
);
if($item)
return $this->run('RosterContact');
else
return $this->run('RosterContact', 'item');
}
function getTop($limit = 6) { function getTop($limit = 6) {
$this->_sql = ' $this->_sql = '
select *, jidfrom from ( select *, jidfrom from (
@ -681,22 +621,4 @@ class ContactDAO extends SQL {
return $this->run('RosterContact'); return $this->run('RosterContact');
} }
function getStatistics() {
$this->_sql = '
select
(select count(*) from postn where postn.session = :session ) as post,
(select count(*) from rosterlink where rosterlink.session= :session ) as rosterlink,
(select count(*) from presence where presence.session= :session ) as presence,
(select count(*) from message where message.session = :session) as message;';
$this->prepare(
'Postn',
array(
'session' => $this->_user
)
);
return $this->run(null, 'array');
}
} }

View file

@ -20,6 +20,7 @@ class Message extends Model {
public $delivered; public $delivered;
public $color; // Only for chatroom purpose public $color; // Only for chatroom purpose
public $publishedPrepared; // Only for chat purpose
public function __construct() public function __construct()
{ {
@ -99,7 +100,7 @@ class Message extends Model {
public function convertEmojis() public function convertEmojis()
{ {
$emoji = \MovimEmoji::getInstance(); $emoji = \MovimEmoji::getInstance();
$this->body = $emoji->replace($this->body); $this->body = addHFR($emoji->replace($this->body));
} }
public function addUrls() public function addUrls()

View file

@ -94,6 +94,30 @@ class MessageDAO extends SQL {
return $this->run('Message'); return $this->run('Message');
} }
function getHistory($jid, $date, $limit = 30) {
$this->_sql = '
select * from message
where session = :session
and (jidfrom = :jidfrom
or jidto = :jidto)
and published < :published
order by published desc';
$this->_sql .= ' limit '.(string)$limit;
$this->prepare(
'Message',
array(
'session' => $this->_user,
'jidfrom' => $jid,
'jidto' => $jid,
'published' => $date
)
);
return $this->run('Message');
}
function getRoomSubject($room) { function getRoomSubject($room) {
$this->_sql = ' $this->_sql = '
select * from message select * from message
@ -126,21 +150,4 @@ class MessageDAO extends SQL {
return $this->run('Message'); return $this->run('Message');
} }
function getStatistics() {
$this->_sql = '
select count(*) as count, extract(month from published) as month, extract(year from published) as year
from message
where session = :session
group by month, year order by year, month';
$this->prepare(
'Message',
array(
'session' => $this->_user
)
);
return $this->run(null, 'array');
}
} }

View file

@ -24,7 +24,6 @@ class Postn extends Model {
public $updated; // public $updated; //
public $delay; // public $delay; //
public $tags; // Store the tags
public $picture; // Tell if the post contain embeded pictures public $picture; // Tell if the post contain embeded pictures
public $lat; public $lat;
@ -36,6 +35,8 @@ class Postn extends Model {
public $hash; public $hash;
private $youtube;
public function __construct() { public function __construct() {
$this->hash = md5(openssl_random_pseudo_bytes(5)); $this->hash = md5(openssl_random_pseudo_bytes(5));
@ -80,8 +81,6 @@ class Postn extends Model {
{"type":"text" }, {"type":"text" },
"picture" : "picture" :
{"type":"int", "size":4 }, {"type":"int", "size":4 },
"tags" :
{"type":"text" },
"hash" : "hash" :
{"type":"string", "size":128 } {"type":"string", "size":128 }
}'; }';
@ -96,7 +95,7 @@ class Postn extends Model {
case 'html': case 'html':
case 'xhtml': case 'xhtml':
$dom = new \DOMDocument('1.0', 'utf-8'); $dom = new \DOMDocument('1.0', 'utf-8');
$import = dom_import_simplexml($c->children()); $import = @dom_import_simplexml($c->children());
if($import == null) { if($import == null) {
$import = dom_import_simplexml($c); $import = dom_import_simplexml($c);
} }
@ -186,18 +185,23 @@ class Postn extends Model {
// Tags parsing // Tags parsing
if($entry->entry->category) { if($entry->entry->category) {
$this->tags = array(); $td = new \Modl\TagDAO;
if($entry->entry->category->count() == 1 if($entry->entry->category->count() == 1
&& isset($entry->entry->category->attributes()->term)) && isset($entry->entry->category->attributes()->term)) {
array_push($this->tags, (string)$entry->entry->category->attributes()->term); $tag = new \Modl\Tag;
else $tag->nodeid = $this->__get('nodeid');
foreach($entry->entry->category as $cat) $tag->tag = (string)$entry->entry->category->attributes()->term;
array_push($this->tags, (string)$cat->attributes()->term); $td->set($tag);
} else {
foreach($entry->entry->category as $cat) {
$tag = new \Modl\Tag;
$tag->nodeid = $this->__get('nodeid');
$tag->tag = (string)$cat->attributes()->term;
$td->set($tag);
}
}
} }
if(!empty($this->tags))
$this->__set('tags', serialize($this->tags));
if($contentimg != '') if($contentimg != '')
$content .= '<br />'.$contentimg; $content .= '<br />'.$contentimg;
@ -206,7 +210,6 @@ class Postn extends Model {
$this->__set('commentplace', $this->origin); $this->__set('commentplace', $this->origin);
$this->__set('content', trim($content)); $this->__set('content', trim($content));
$this->contentcleaned = purifyHTML(html_entity_decode($this->content)); $this->contentcleaned = purifyHTML(html_entity_decode($this->content));
if($entry->entry->geoloc) { if($entry->entry->geoloc) {
@ -221,6 +224,10 @@ class Postn extends Model {
return in_array($type, array('image/jpeg', 'image/png', 'image/jpg')); return in_array($type, array('image/jpeg', 'image/png', 'image/jpg'));
} }
private function typeIsLink($type) {
return $type == 'text/html';
}
private function setAttachements($links) { private function setAttachements($links) {
$contentimg = ''; $contentimg = '';
@ -252,24 +259,29 @@ class Postn extends Model {
public function getAttachements() public function getAttachements()
{ {
$attachements = null; $attachements = null;
$this->picture = null;
if(isset($this->links)) { if(isset($this->links)) {
$attachements = array('pictures' => array(), 'files' => array(), 'links' => array()); $attachements = array('pictures' => array(), 'files' => array(), 'links' => array());
$links = unserialize($this->links); $links = unserialize($this->links);
foreach($links as $l) { foreach($links as $l) {
switch($l['rel']) { if(isset($l['type']) && $this->typeIsPicture($l['type'])) {
case 'enclosure' : if($this->picture == null) {
if($this->typeIsPicture($l['type'])) { $this->picture = $l['href'];
array_push($attachements['pictures'], $l);
} else {
array_push($attachements['files'], $l);
} }
break; array_push($attachements['pictures'], $l);
case 'related' : } elseif((isset($l['type']) && $this->typeIsLink($l['type'])
case 'alternate' : || in_array($l['rel'], array('related', 'alternate')))
&& Validator::url()->validate($l['href'])) {
if($this->youtube == null
&& preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $l['href'], $match)) {
$this->youtube = $match[1];
}
array_push($attachements['links'], array('href' => $l['href'], 'url' => parse_url($l['href']))); array_push($attachements['links'], array('href' => $l['href'], 'url' => parse_url($l['href'])));
break; } elseif(isset($l['rel']) && $l['rel'] == 'enclosure') {
array_push($attachements['files'], $l);
} }
} }
} }
@ -284,50 +296,39 @@ class Postn extends Model {
public function getAttachement() public function getAttachement()
{ {
$attachements = $this->getAttachements(); $attachements = $this->getAttachements();
if(isset($attachements['pictures'])) { if(isset($attachements['pictures']) && !isset($attachements['links'])) {
return $attachements['pictures'][0]; return $attachements['pictures'][0];
} }
if(isset($attachements['files'])) { if(isset($attachements['files'])) {
return $attachements['files'][0]; return $attachements['files'][0];
} }
if(isset($attachements['links'])) { if(isset($attachements['links'])) {
foreach($attachements['links'] as $link) { return $attachements['links'][0];
if(Validator::url()->validate($link['href'])) {
return $link;
}
}
return false;
} }
return false; return false;
} }
public function getPicture() public function getPicture()
{ {
$attachements = $this->getAttachements(); return $this->picture;
if(is_array($attachements)
&& array_key_exists('pictures', $attachements)) {
return $attachements['pictures'][0]['href'];
} }
public function getYoutube()
{
return $this->youtube;
} }
public function getPlace() public function getPlace()
{ {
if(isset($this->lat, $this->lon) && $this->lat != '' && $this->lon != '') { return (isset($this->lat, $this->lon) && $this->lat != '' && $this->lon != '');
return true;
}
else
return false;
} }
public function isMine() public function isMine()
{ {
$user = new \User(); $user = new \User();
if($this->aid == $user->getLogin() return ($this->aid == $user->getLogin()
|| $this->origin == $user->getLogin()) || $this->origin == $user->getLogin());
return true;
else
return false;
} }
public function getUUID() public function getUUID()
@ -341,11 +342,7 @@ class Postn extends Model {
public function isMicroblog() public function isMicroblog()
{ {
if($this->node == "urn:xmpp:microblog:0") { return ($this->node == "urn:xmpp:microblog:0");
return true;
} else {
return false;
}
} }
public function isEditable() public function isEditable()
@ -355,7 +352,7 @@ class Postn extends Model {
public function isShort() public function isShort()
{ {
return (strlen($this->contentcleaned) < 500); return (strlen($this->contentcleaned) < 700);
} }
public function getPublicUrl() public function getPublicUrl()
@ -363,15 +360,29 @@ class Postn extends Model {
if($this->isMicroblog()) { if($this->isMicroblog()) {
return \Route::urlize('blog', array($this->origin)); return \Route::urlize('blog', array($this->origin));
} else { } else {
return \Route::urlize('grouppublic', array($this->origin, $this->node)); return \Route::urlize('node', array($this->origin, $this->node));
}
}
public function getTags()
{
$td = new \Modl\TagDAO;
$tags = $td->getTags($this->nodeid);
if(is_array($tags)) {
return array_map(function($tag) { return $tag->tag; }, $tags);
}
}
public function getTagsImploded()
{
$tags = $this->getTags();
if(is_array($tags)) {
return implode(', ', $tags);
} }
} }
public function isPublic() { public function isPublic() {
if(isset($this->privacy) && $this->privacy) { return (isset($this->privacy) && $this->privacy);
return true;
}
return false;
} }
} }

View file

@ -26,7 +26,6 @@ class PostnDAO extends SQL {
links = :links, links = :links,
picture = :picture, picture = :picture,
tags = :tags,
hash = :hash hash = :hash
@ -57,7 +56,6 @@ class PostnDAO extends SQL {
'links' => $post->links, 'links' => $post->links,
'picture' => $post->picture, 'picture' => $post->picture,
'tags' => $post->tags,
'hash' => $post->hash, 'hash' => $post->hash,
@ -97,7 +95,6 @@ class PostnDAO extends SQL {
links, links,
picture, picture,
tags,
hash) hash)
values( values(
@ -125,7 +122,6 @@ class PostnDAO extends SQL {
:links, :links,
:picture, :picture,
:tags,
:hash :hash
)'; )';
@ -153,7 +149,6 @@ class PostnDAO extends SQL {
'links' => $post->links, 'links' => $post->links,
'picture' => $post->picture, 'picture' => $post->picture,
'tags' => $post->tags,
'hash' => $post->hash, 'hash' => $post->hash,
@ -210,8 +205,8 @@ class PostnDAO extends SQL {
and postn.node != \'urn:xmpp:microblog:0\' and postn.node != \'urn:xmpp:microblog:0\'
order by postn.published desc'; order by postn.published desc';
if($limitr) if($limitr !== false)
$this->_sql = $this->_sql.' limit '.$limitr.' offset '.$limitf; $this->_sql = $this->_sql.' limit '.(int)$limitr.' offset '.(int)$limitf;
$this->prepare( $this->prepare(
'Postn', 'Postn',
@ -225,6 +220,28 @@ class PostnDAO extends SQL {
return $this->run('ContactPostn'); return $this->run('ContactPostn');
} }
function getPublicTag($tag, $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 nodeid in (select nodeid from tag where tag = :title)
and privacy.value = 1
order by postn.published desc';
if($limitr !== false)
$this->_sql = $this->_sql.' limit '.(int)$limitr.' offset '.(int)$limitf;
$this->prepare(
'Postn',
array(
'title' => $tag # Hack
)
);
return $this->run('ContactPostn');
}
function getNodeUnfiltered($from, $node, $limitf = false, $limitr = false) { function getNodeUnfiltered($from, $node, $limitf = false, $limitr = false) {
$this->_sql = ' $this->_sql = '
select *, postn.aid, privacy.value as privacy from postn select *, postn.aid, privacy.value as privacy from postn
@ -248,20 +265,21 @@ class PostnDAO extends SQL {
return $this->run('ContactPostn'); return $this->run('ContactPostn');
} }
function getGallery($from) { function getGallery($from, $limitf = false, $limitr = false) {
$this->_sql = ' $this->_sql = '
select *, postn.aid, privacy.value as privacy from postn select *, postn.aid, privacy.value as privacy from postn
left outer join contact on postn.aid = contact.jid left outer join contact on postn.aid = contact.jid
left outer join privacy on postn.nodeid = privacy.pkey left outer join privacy on postn.nodeid = privacy.pkey
where (postn.origin in (select jid from rosterlink where session = :origin and rostersubscription in (\'both\', \'to\'))) where postn.aid = :aid
and postn.origin = :aid
and postn.picture = 1 and postn.picture = 1
order by postn.published desc'; order by postn.published desc';
if($limitr !== false)
$this->_sql = $this->_sql.' limit '.(int)$limitr.' offset '.(int)$limitf;
$this->prepare( $this->prepare(
'Postn', 'Postn',
array( array(
'origin' => $this->_user,
'aid' => $from // Another hack 'aid' => $from // Another hack
) )
); );
@ -410,7 +428,7 @@ class PostnDAO extends SQL {
return $this->run('ContactPostn'); return $this->run('ContactPostn');
} }
function getPublicItem($origin, $node, $nodeid, $limitf = false, $limitr = false) { function getPublicItem($origin, $node, $nodeid) {
$this->_sql = ' $this->_sql = '
select *, postn.aid, privacy.value as privacy from postn select *, postn.aid, privacy.value as privacy from postn
left outer join contact on postn.aid = contact.jid left outer join contact on postn.aid = contact.jid
@ -421,9 +439,6 @@ class PostnDAO extends SQL {
and postn.nodeid = :nodeid and postn.nodeid = :nodeid
order by postn.published desc'; order by postn.published desc';
if($limitr)
$this->_sql = $this->_sql.' limit '.$limitr.' offset '.$limitf;
$this->prepare( $this->prepare(
'Postn', 'Postn',
array( array(
@ -483,24 +498,6 @@ class PostnDAO extends SQL {
return $this->run('Postn'); return $this->run('Postn');
} }
// TODO: fixme
function getStatistics() {
$this->_sql = '
select count(*) as count, extract(month from published) as month, extract(year from published) as year
from postn
where session = :session
group by month, year order by year desc, month desc';
$this->prepare(
'Postn',
array(
'session' => $this->_user
)
);
return $this->run(null, 'array');
}
function getCountSince($date) { function getCountSince($date) {
$this->_sql = ' $this->_sql = '
select count(*) from postn select count(*) from postn

View file

@ -137,25 +137,6 @@ class RosterLinkDAO extends SQL {
$this->set($r); $this->set($r);
} }
function setChat($jid, $chaton) {
$this->_sql = '
update rosterlink
set chaton = :chaton
where session = :session
and jid = :jid';
$this->prepare(
'RosterLink',
array(
'session' => $this->_user,
'jid' => $jid,
'chaton' => $chaton
)
);
return $this->run('RosterLink');
}
function get($jid) { function get($jid) {
$this->_sql = ' $this->_sql = '
select * select *
@ -223,23 +204,6 @@ class RosterLinkDAO extends SQL {
return $this->run('RosterLink'); return $this->run('RosterLink');
} }
function getChats() {
$this->_sql = '
select *
from rosterlink
where session=:session
and chaton > 0';
$this->prepare(
'RosterLink',
array(
'session' => $this->_user
)
);
return $this->run('RosterLink');
}
function clearRosterLink() { function clearRosterLink() {
$this->_sql = ' $this->_sql = '
delete from rosterlink delete from rosterlink

View file

@ -0,0 +1,20 @@
<?php
namespace modl;
class Tag extends Model {
public $tag;
public $nodeid;
public function __construct() {
$this->_struct = '
{
"tag" :
{"type":"string", "size":64, "mandatory":true, "key":true },
"nodeid" :
{"type":"string", "size":96, "mandatory":true, "key":true }
}';
parent::__construct();
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace modl;
class TagDAO extends SQL {
function set(Tag $t) {
$this->_sql = '
update tag
set nodeid = :nodeid,
tag = :tag
where nodeid = :nodeid
and tag = :tag';
$this->prepare(
'Tag',
array(
'nodeid' => $t->nodeid,
'tag' => $t->tag
)
);
$this->run('Tag');
if(!$this->_effective) {
$this->_sql = '
insert into tag
(nodeid, tag)
values (:nodeid, :tag)';
$this->prepare(
'Tag',
array(
'nodeid' => $t->nodeid,
'tag' => $t->tag
)
);
$this->run('Tag');
}
}
function getTags($nodeid) {
$this->_sql = '
select * from tag
where nodeid = :nodeid';
$this->prepare(
'Tag',
array(
'nodeid' => $nodeid
)
);
return $this->run('Tag');
}
}

View file

@ -0,0 +1,7 @@
<main>
<section>
<div style="background-color: #EEE;">
<?php $this->widget('Blog');?>
</div>
</section>
</main>

View file

@ -1,26 +1,19 @@
<?php /* -*- mode: html -*- */ <!DOCTYPE html>
$cd = new \Modl\ConfigDAO();
$config = $cd->get();
?><!DOCTYPE html>
<html ng-app="roster"> <html ng-app="roster">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title><?php $this->title();?></title> <title><?php $this->title();?></title>
<meta name="description" content="<?php echo $config->description; ?>" />
<meta name="theme-color" content="#1C1D5B" /> <meta name="theme-color" content="#1C1D5B" />
<link rel="shortcut icon" href="<?php $this->linkFile('img/favicon.ico');?>" /> <?php $this->meta();?>
<!--<link rel="stylesheet" href="<?php echo BASE_URI; ?>app/assets/js/leaflet.css" />
<script src="<?php echo BASE_URI; ?>app/assets/js/leaflet.js"></script>-->
<script src="<?php echo BASE_URI; ?>app/assets/js/favico.js"></script>
<!-- OTR --> <meta name="application-name" content="Movim">
<!--<script src="<?php echo BASE_URI; ?>app/assets/js/otr/dep/bigint.js"></script> <link rel="shortcut icon" href="<?php $this->linkFile('img/favicon.ico');?>" />
<script src="<?php echo BASE_URI; ?>app/assets/js/otr/dep/crypto.js"></script> <link rel="icon" type="image/png" href="<?php $this->linkFile('img/app/48.png');?>" sizes="48x48">
<script src="<?php echo BASE_URI; ?>app/assets/js/otr/dep/eventemitter.js"></script> <link rel="icon" type="image/png" href="<?php $this->linkFile('img/app/96.png');?>" sizes="96x96">
<script src="<?php echo BASE_URI; ?>app/assets/js/otr/otr.js"></script> <link rel="icon" type="image/png" href="<?php $this->linkFile('img/app/128.png');?>" sizes="128x128">
<script src="<?php echo BASE_URI; ?>app/assets/js/cycle.js"></script>--> <script src="<?php echo BASE_URI; ?>app/assets/js/favico.js"></script>
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
@ -55,10 +48,6 @@
<?php $this->widget('Dialog');?> <?php $this->widget('Dialog');?>
<?php $this->widget('Notification');?> <?php $this->widget('Notification');?>
<?php $this->content();?> <?php $this->content();?>
<?php
$this->displayFooterDebug();
?>
<script type="text/javascript">movim_onload();</script> <script type="text/javascript">movim_onload();</script>
</body> </body>
</html> </html>

View file

@ -0,0 +1,7 @@
<main>
<section>
<div style="background-color: #EEE;">
<?php $this->widget('Blog');?>
</div>
</section>
</main>

View file

@ -56,7 +56,7 @@ class Account extends WidgetBase
function ajaxChangePassword($form) function ajaxChangePassword($form)
{ {
$validate = Validator::string()->length(6, 40); $validate = Validator::stringType()->length(6, 40);
$p1 = $form->password->value; $p1 = $form->password->value;
$p2 = $form->password_confirmation->value; $p2 = $form->password_confirmation->value;
@ -113,7 +113,7 @@ class Account extends WidgetBase
private function validateServer($server) private function validateServer($server)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 80); $validate_server = Validator::stringType()->noWhitespace()->length(6, 80);
if(!$validate_server->validate($server)) return false; if(!$validate_server->validate($server)) return false;
else return true; else return true;
} }

View file

@ -1,7 +1,6 @@
<?php <?php
use Moxl\Xec\Action\Disco\Request; use Moxl\Xec\Action\Disco\Request;
use Moxl\Xec\Action\Register\Get;
use Moxl\Xec\Action\Register\Set; use Moxl\Xec\Action\Register\Set;
class AccountNext extends WidgetBase { class AccountNext extends WidgetBase {
@ -30,6 +29,13 @@ class AccountNext extends WidgetBase {
{ {
$form = $package->content; $form = $package->content;
if($package->from == 'movim.eu') {
$movimview = $this->tpl();
$movimview->assign('submitdata', $this->call('ajaxRegister', "movim_form_to_json('data')"));
$html = $movimview->draw('_accountnext_movim', true);
RPC::call('movim_fill', 'subscription_form', $html);
} else {
$xtf = new \XMPPtoForm(); $xtf = new \XMPPtoForm();
if(!empty($form->x)){ if(!empty($form->x)){
switch($form->x->attributes()->xmlns) { switch($form->x->attributes()->xmlns) {
@ -58,6 +64,7 @@ class AccountNext extends WidgetBase {
$formh = $xtf->getHTML($form->asXML()); $formh = $xtf->getHTML($form->asXML());
} }
} }
}
function onRegistered($packet) function onRegistered($packet)
{ {
@ -68,7 +75,7 @@ class AccountNext extends WidgetBase {
$html = $view->draw('_accountnext_registered', true); $html = $view->draw('_accountnext_registered', true);
RPC::call('movim_fill', 'subscription_form', $html); RPC::call('movim_fill', 'subscribe', $html);
RPC::call('setUsername', $data->username->value); RPC::call('setUsername', $data->username->value);
} }
@ -103,6 +110,12 @@ class AccountNext extends WidgetBase {
function ajaxRegister($form) function ajaxRegister($form)
{ {
if(isset($form->re_password)
&& $form->re_password->value != $form->password->value) {
Notification::append(null, $this->__('account.password_not_same'));
return;
}
$s = new Set; $s = new Set;
$s->setData($form)->request(); $s->setData($form)->request();
} }

View file

@ -1,4 +1,3 @@
<br />
<form name="data"> <form name="data">
{$formh} {$formh}
<a <a

View file

@ -0,0 +1,20 @@
<form name="data">
<div id="movim">
<span>@movim.eu</span>
<label for="username">{$c->__('input.username')}</label>
<input name="username" type="text" placeholder="username">
</div>
<div>
<label for="password">{$c->__('input.password')}</label>
<input name="password" type="password" placeholder="{$c->__('input.password')}">
</div>
<div class="compact">
<input name="re_password" type="password" placeholder="{$c->__('credentials.re_password')}">
</div>
<a
class="button color green oppose"
onclick="{$submitdata}"
>
{$c->__('button.validate')}
</a>
</form>

View file

@ -1,4 +1,4 @@
<ul class="thick"> <ul id="obb" class="thick">
<li class="condensed"> <li class="condensed">
<span class="icon bubble color blue"> <span class="icon bubble color blue">
<i class="zmdi zmdi-chevron-right"></i> <i class="zmdi zmdi-chevron-right"></i>

View file

@ -1,3 +1,30 @@
#subscription_form form > div { #subscription_form form > div {
left: 2rem; left: 1rem;
}
#subscription_form form {
padding-top: 5rem;
}
#subscription_form ul#obb {
padding-top: 10rem;
}
#subscription_form div#movim input {
width: calc(100% - 15rem);
text-align: right;
}
#subscription_form div#movim span {
color: gray;
font-weight: bold;
text-align: left;
font-size: 2rem;
top: 4rem;
float: right;
position: relative;
line-height: 3rem;
padding: 1rem;
width: 15rem;
box-sizing: border-box;
} }

View file

@ -1,5 +1,13 @@
<div id="subscribe"> <div id="subscribe">
<div id="subscription_form" class="padded_right"> <div class="flex">
<div class="block on_desktop">
<div class="placeholder icon account">
<h4>{$c->__('create.title')}</h4>
<h4>{$c->__('create.placeholder')}</h4>
</div>
</div>
<div id="subscription_form" class="block">
<ul class="simple thick"> <ul class="simple thick">
<li> <li>
<span>{$c->__('create.title')} {$c->__('create.server_on')} {$host}</span> <span>{$c->__('create.title')} {$c->__('create.server_on')} {$host}</span>
@ -7,6 +15,7 @@
</li> </li>
</ul> </ul>
</div> </div>
</div>
<script type="text/javascript"> <script type="text/javascript">
MovimWebsocket.attach(function() MovimWebsocket.attach(function()
{ {

View file

@ -4,6 +4,7 @@ notfound = No account creation form found on the server
server_on = on server_on = on
successfull = Your acccount has been successfully registered successfull = Your acccount has been successfully registered
loading = Loading loading = Loading
placeholder = …and start playing
[error] [error]
not_acceptable = Not Acceptable not_acceptable = Not Acceptable

View file

@ -6,7 +6,19 @@
<div id="preview" class="block"> <div id="preview" class="block">
<div> <div>
<form name="avatarform" id="avatarform"> <form name="avatarform" id="avatarform">
{if="isset($photobin) && $photobin != ''"}
<img src="data:image/jpeg;base64,{$photobin}"> <img src="data:image/jpeg;base64,{$photobin}">
{else}
<img src="#" class="error">
<ul class="thick">
<li>
<span class="icon bubble color {$me->jid|stringToColor}">
<i class="zmdi zmdi-account"></i>
</span>
<p>{$c->__('avatar.missing')}</p>
</li>
</ul>
{/if}
<input type="hidden" name="photobin" value="{$photobin}"/> <input type="hidden" name="photobin" value="{$photobin}"/>
</form> </form>
</div> </div>

View file

@ -14,3 +14,7 @@
border-radius: 0.25rem; border-radius: 0.25rem;
margin: 0 auto; margin: 0 auto;
} }
#avatar_form div#preview img.error {
display: none;
}

View file

@ -34,7 +34,14 @@ var Avatar = {
var base64 = canvas.toDataURL('image/jpeg', 0.7); var base64 = canvas.toDataURL('image/jpeg', 0.7);
var preview = document.querySelector('form[name=avatarform] img'); var preview = document.querySelector('form[name=avatarform] img');
var list = document.querySelector('form[name=avatarform] ul');
if(list) list.style.display = 'none';
var input = document.querySelector('input[name="photobin"]'); var input = document.querySelector('input[name="photobin"]');
if(preview.className == 'error') preview.className = '';
preview.src = base64; preview.src = base64;
var bin = base64.split(","); var bin = base64.split(",");

View file

@ -6,3 +6,4 @@ cheese = Cheese !
snapshot = Take a webcam snapshot snapshot = Take a webcam snapshot
updated = Avatar Updated updated = Avatar Updated
not_updated = Avatar Not Updated not_updated = Avatar Not Updated
missing = No avatar defined yet

View file

@ -2,68 +2,132 @@
use Respect\Validation\Validator; use Respect\Validation\Validator;
include_once WIDGETS_PATH.'Post/Post.php';
class Blog extends WidgetBase { class Blog extends WidgetBase {
public $_paging = 10; public $_paging = 10;
private $_from;
private $_node;
private $_item;
private $_id;
private $_contact;
private $_messages;
private $_page;
private $_mode;
private $_tag;
function load() function load()
{ {
if($this->_view == 'node') {
$this->_from = $this->get('s');
$this->_node = $this->get('n');
} if(!$this->validateServerNode($this->_from, $this->_node)) return;
function display()
{
if($this->_view == 'grouppublic') {
$from = $this->get('s');
$node = $this->get('n');
if(!$this->validateServerNode($from, $node)) return;
$this->view->assign('mode', 'group');
$this->view->assign('server', $from);
$this->view->assign('node', $node);
$pd = new \Modl\ItemDAO; $pd = new \Modl\ItemDAO;
$this->view->assign('item', $pd->getItem($from, $node)); $this->_item = $pd->getItem($this->_from, $this->_node);
$this->_mode = 'group';
$this->url = Route::urlize('node', array($this->_from, $this->_node));
} elseif($this->_view == 'tag' && $this->validateTag($this->get('t'))) {
$this->_mode = 'tag';
$this->_tag = $this->get('t');
$this->title = '#'.$this->_tag;
} else { } else {
$from = $this->get('f'); $this->_from = $this->get('f');
$cd = new \modl\ContactDAO(); $cd = new \modl\ContactDAO();
$c = $cd->get($from, true); $this->_contact = $cd->get($this->_from, true);
$this->view->assign('contact', $c); if(filter_var($this->_from, FILTER_VALIDATE_EMAIL)) {
if(filter_var($from, FILTER_VALIDATE_EMAIL)) { $this->_node = 'urn:xmpp:microblog:0';
$node = 'urn:xmpp:microblog:0';
} else { } else {
return; return;
} }
$this->view->assign('mode', 'blog'); $this->_mode = 'blog';
$this->url = Route::urlize('blog', $this->_from);
} }
$pd = new \modl\PostnDAO(); $pd = new \modl\PostnDAO();
if($id = $this->get('i')) { if($this->_id = $this->get('i')) {
if(Validator::int()->between(0, 100)->validate($id)) { if(Validator::intType()->between(0, 100)->validate($this->_id)) {
$messages = $pd->getNodeUnfiltered($from, $node, $id * $this->_paging, $this->_paging + 1); if(isset($this->_tag)) {
$page = $id + 1; $this->_messages = $pd->getPublicTag($this->get('t'), $this->_id * $this->_paging, $this->_paging + 1);
} elseif(Validator::string()->length(5, 100)->validate($id)) { } else {
$messages = $pd->getPublicItem($from, $node, $id); $this->_messages = $pd->getNodeUnfiltered($this->_from, $this->_node, $this->_id * $this->_paging, $this->_paging + 1);
}
$this->_page = $this->_id + 1;
} elseif(Validator::stringType()->length(5, 100)->validate($this->_id)) {
$this->_messages = $pd->getPublicItem($this->_from, $this->_node, $this->_id);
if(is_object($this->_messages[0])) {
$this->title = $this->_messages[0]->title;
$description = stripTags($this->_messages[0]->contentcleaned);
if(!empty($description)) {
$this->description = $description;
}
$attachements = $this->_messages[0]->getAttachements();
if($attachements && array_key_exists('pictures', $attachements)) {
$this->image = urldecode($attachements['pictures'][0]['href']);
}
}
if($this->_view == 'node') {
$this->url = Route::urlize('node', array($this->_from, $this->_node, $this->_id));
} else {
$this->url = Route::urlize('blog', array($this->_from, $this->_id));
}
} }
} else { } else {
$page = 1; $this->_page = 1;
$messages = $pd->getNodeUnfiltered($from, $node, 0, $this->_paging + 1); if(isset($this->_tag)) {
$this->_messages = $pd->getPublicTag($this->get('t'), 0, $this->_paging + 1);
} else {
$this->_messages = $pd->getNodeUnfiltered($this->_from, $this->_node, 0, $this->_paging + 1);
}
} }
if(count($messages) == $this->_paging + 1) { if(count($this->_messages) == $this->_paging + 1) {
array_pop($messages); array_pop($this->_messages);
$this->view->assign('more', $page);
} }
$this->view->assign('posts', $messages); $this->user = new User($this->_from);
$cssurl = $this->user->getDumpedConfig('cssurl');
if(isset($cssurl)
&& $cssurl != ''
&& Validator::url()->validate($cssurl)) {
$this->addrawcss($cssurl);
}
}
public function preparePost($p) {
$pw = new Post;
return $pw->preparePost($p, true, true);
}
function display()
{
$this->view->assign('server', $this->_from);
$this->view->assign('node', $this->_node);
$this->view->assign('item', $this->_item);
$this->view->assign('contact', $this->_contact);
$this->view->assign('mode', $this->_mode);
$this->view->assign('more', $this->_page);
$this->view->assign('posts', $this->_messages);
$this->view->assign('tag', $this->_tag);
} }
private function validateServerNode($server, $node) private function validateServerNode($server, $node)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 40); $validate_server = Validator::stringType()->noWhitespace()->length(6, 40);
$validate_node = Validator::string()->length(3, 100); $validate_node = Validator::stringType()->length(3, 100);
if(!$validate_server->validate($server) if(!$validate_server->validate($server)
|| !$validate_node->validate($node) || !$validate_node->validate($node)
@ -71,6 +135,11 @@ class Blog extends WidgetBase {
else return true; else return true;
} }
private function validateTag($tag)
{
return Validator::stringType()->notEmpty()->alnum()->validate($tag);
}
function getComments($post) function getComments($post)
{ {
$pd = new \Modl\PostnDAO(); $pd = new \Modl\PostnDAO();

View file

@ -31,6 +31,17 @@
<p>{$contact->description}</p> <p>{$contact->description}</p>
{/if} {/if}
</li> </li>
{elseif="$mode == 'tag'"}
<li class="condensed">
<span class="icon gray">
<i class="zmdi zmdi-tag"></i>
</span>
<h2>
<a href="{$c->route('tag', array($tag))}">
#{$tag}
</a>
</h2>
</li>
{else} {else}
<li class="condensed action"> <li class="condensed action">
<div class="action"> <div class="action">
@ -45,7 +56,7 @@
<i class="zmdi zmdi-pages"></i> <i class="zmdi zmdi-pages"></i>
</span> </span>
<h2> <h2>
<a href="{$c->route('group', array($server, $node))}"> <a href="{$c->route('node', array($server, $node))}">
{if="$item != null"} {if="$item != null"}
{if="$item->name"} {if="$item->name"}
{$item->name} {$item->name}
@ -67,149 +78,7 @@
</ul> </ul>
{loop="$posts"} {loop="$posts"}
<article class="block"> {$c->preparePost($value)}
<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->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-account"></i>
</span>
{/if}
<h2>
<a href="
{if="$value->isMicroblog()"}
{$c->route('blog', array($value->origin, $value->nodeid))}
{else}
{$c->route('group', array($value->origin, $value->node, $value->nodeid))}
{/if}
">
{if="$value->title != null"}
{$value->title}
{else}
{$c->__('post.default_title')}
{/if}
</a>
</h2>
<p>
{if="$value->getContact()->getTrueName() != '' && $value->privacy"}
<i class="zmdi zmdi-account"></i> {$value->getContact()->getTrueName()}
{/if}
{$value->published|strtotime|prepareDate}
</p>
</li>
</ul>
</header>
{if="!$value->isPublic()"}
<ul class="thick">
<li>
<span class="icon color gray bubble">
<i class="zmdi zmdi-lock"></i>
</span>
<p class="center"> {$c->__('blog.private')} - <a href="{$c->route('main')}">{$c->__('page.login')}</a></p>
</li>
</ul>
<br />
{else}
{$attachements = $value->getAttachements()}
<section>
<content>
{if="strlen($value->contentcleaned) < 500 && isset($attachements.pictures)"}
{loop="$attachements.pictures"}
<a href="{$value.href}" class="alternate" target="_blank">
<img class="big_picture" type="{$value.type}" src="{$value.href|urldecode}"/>
</a>
{/loop}
{/if}
{$value->contentcleaned}
</content>
</section>
<footer>
<ul class="middle divided spaced">
{if="isset($attachements.links)"}
{loop="$attachements.links"}
{if="substr($value.href, 0, 5) != 'xmpp:' && filter_var($value.href, FILTER_VALIDATE_URL)"}
<li>
<span class="icon">
<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>
{/if}
{/loop}
{/if}
{if="isset($attachements.files)"}
{loop="$attachements.files"}
<li>
<a
href="{$value.href}"
class="enclosure"
type="{$value.type}"
target="_blank">
<span class="icon gray">
<span class="zmdi zmdi-attachment-alt"></span>
</span>
<span>{$value.href|urldecode}</span>
</a>
</li>
{/loop}
{/if}
</ul>
{if="strlen($value->contentcleaned) >= 500 && isset($attachements.pictures)"}
<ul class="flex middle">
{loop="$attachements.pictures"}
<li class="block pic">
<span class="icon gray">
<i class="zmdi zmdi-image"></i>
</span>
<a href="{$value.href}" class="alternate" target="_blank">
<img type="{$value.type}" src="{$value.href|urldecode}"/>
</a>
</li>
{/loop}
</ul>
{/if}
</footer>
{$comments = $c->getComments($value)}
{if="$comments"}
<ul class="spaced middle">
<li class="subheader">
{$c->__('post.comments')}
<span class="info">{$comments|count}</span>
</li>
{loop="$comments"}
<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->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-account"></i>
</span>
{/if}
<span class="info">{$value->published|strtotime|prepareDate}</span>
<span>
{$value->getContact()->getTrueName()}
</span>
<p class="all">
{$value->contentraw}
</p>
</li>
{/loop}
</ul>
{/if}
<br />
{/if}
</article>
{/loop} {/loop}
{if="isset($more)"} {if="isset($more)"}
<article> <article>

View file

@ -12,6 +12,8 @@ use Respect\Validation\Validator;
class Chat extends WidgetBase class Chat extends WidgetBase
{ {
private $_pagination = 30;
function load() function load()
{ {
$this->addjs('chat.js'); $this->addjs('chat.js');
@ -314,6 +316,30 @@ class Chat extends WidgetBase
$mp->setTo($to)->request(); $mp->setTo($to)->request();
} }
/**
* @brief Get the chat history
*
* @param string jid
* @param string time
*/
function ajaxGetHistory($jid, $date)
{
if(!$this->validateJid($jid)) return;
$md = new \Modl\MessageDAO();
$messages = $md->getHistory(echapJid($jid), date(DATE_ISO8601, strtotime($date)), $this->_pagination);
if(count($messages) > 0) {
Notification::append(false, $this->__('message.history', count($messages)));
}
foreach($messages as $message) {
if(!preg_match('#^\?OTR#', $message->body)) {
RPC::call('Chat.appendMessage', $this->prepareMessage($message), true);
}
}
}
/** /**
* @brief Configure a room * @brief Configure a room
* *
@ -368,7 +394,7 @@ class Chat extends WidgetBase
{ {
if(!$this->validateJid($room)) return; if(!$this->validateJid($room)) return;
$validate_subject = Validator::string()->length(0, 200); $validate_subject = Validator::stringType()->length(0, 200);
if(!$validate_subject->validate($form->subject->value)) return; if(!$validate_subject->validate($form->subject->value)) return;
$p = new SetSubject; $p = new SetSubject;
@ -451,7 +477,7 @@ class Chat extends WidgetBase
if(!$this->validateJid($jid)) return; if(!$this->validateJid($jid)) return;
$md = new \Modl\MessageDAO(); $md = new \Modl\MessageDAO();
$messages = $md->getContact(echapJid($jid), 0, 30); $messages = $md->getContact(echapJid($jid), 0, $this->_pagination);
if(is_array($messages)) { if(is_array($messages)) {
$messages = array_reverse($messages); $messages = array_reverse($messages);
@ -501,7 +527,7 @@ class Chat extends WidgetBase
$message->color = stringToColor($message->session.$message->resource.$message->jidfrom.$message->type); $message->color = stringToColor($message->session.$message->resource.$message->jidfrom.$message->type);
} }
$message->published = prepareDate(strtotime($message->published)); $message->publishedPrepared = prepareDate(strtotime($message->published));
return $message; return $message;
} }
@ -523,7 +549,7 @@ class Chat extends WidgetBase
*/ */
private function validateJid($jid) private function validateJid($jid)
{ {
$validate_jid = Validator::string()->noWhitespace()->length(6, 60); $validate_jid = Validator::stringType()->noWhitespace()->length(6, 60);
if(!$validate_jid->validate($jid)) return false; if(!$validate_jid->validate($jid)) return false;
else return true; else return true;
} }

View file

@ -7,7 +7,7 @@
<ul class="thin"> <ul class="thin">
<li class="action"> <li class="action">
<span class="icon gray emojis_open" onclick="Chat_ajaxSmiley()"> <span class="icon gray emojis_open" onclick="Chat_ajaxSmiley()">
{$c->ajaxSmileyGet('😃')} <img alt=":smiley:" class="emoji large" src="{$c->getSmileyPath('1f603')}">
</span> </span>
<div class="action" data-jid="{$jid}" onclick="Chat.sendMessage(this.dataset.jid, {if="$muc"}true{else}false{/if})"> <div class="action" data-jid="{$jid}" onclick="Chat.sendMessage(this.dataset.jid, {if="$muc"}true{else}false{/if})">
<i class="zmdi zmdi-mail-send"></i> <i class="zmdi zmdi-mail-send"></i>

View file

@ -4,7 +4,9 @@
</div> </div>
<ul class="flex middle active"> <ul class="flex middle active">
{if="$top"}
<li class="subheader block large">{$c->__('chat.frequent')}</li> <li class="subheader block large">{$c->__('chat.frequent')}</li>
{/if}
{loop="$top"} {loop="$top"}
<li class="condensed block {if="$value->last > 60"} inactive{/if}" <li class="condensed block {if="$value->last > 60"} inactive{/if}"
onclick="Chats_ajaxOpen('{$value->jid}'); Chat_ajaxGet('{$value->jid}');"> onclick="Chats_ajaxOpen('{$value->jid}'); Chat_ajaxGet('{$value->jid}');">

View file

@ -2,76 +2,76 @@
<table class="emojis"> <table class="emojis">
<tbody> <tbody>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="😂"><img alt=":joy:" class="emoji" src="{$c->getSmileyPath('1f602')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😂"><img alt=":joy:" class="emoji large" src="{$c->getSmileyPath('1f602')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😃"><img alt=":smiley:" class="emoji" src="{$c->getSmileyPath('1f603')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😃"><img alt=":smiley:" class="emoji large" src="{$c->getSmileyPath('1f603')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😄"><img alt=":smile:" class="emoji" src="{$c->getSmileyPath('1f604')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😄"><img alt=":smile:" class="emoji large" src="{$c->getSmileyPath('1f604')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😆"><img alt=":laughing:" class="emoji" src="{$c->getSmileyPath('1f606')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😆"><img alt=":laughing:" class="emoji large" src="{$c->getSmileyPath('1f606')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😍"><img alt=":heart_eyes:" class="emoji" src="{$c->getSmileyPath('1f60d')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😍"><img alt=":heart_eyes:" class="emoji large" src="{$c->getSmileyPath('1f60d')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😉"><img alt=":wink:" class="emoji" src="{$c->getSmileyPath('1f609')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😉"><img alt=":wink:" class="emoji large" src="{$c->getSmileyPath('1f609')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="😠"><img alt=":angry:" class="emoji" src="{$c->getSmileyPath('1f620')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😠"><img alt=":angry:" class="emoji large" src="{$c->getSmileyPath('1f620')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😜"><img alt=":stuck_out_tongue_winking_eye:" class="emoji" src="{$c->getSmileyPath('1f61c')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😜"><img alt=":stuck_out_tongue_winking_eye:" class="emoji large" src="{$c->getSmileyPath('1f61c')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😝"><img alt=":stuck_out_tongue_closed_eyes:" class="emoji" src="{$c->getSmileyPath('1f61d')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😝"><img alt=":stuck_out_tongue_closed_eyes:" class="emoji large" src="{$c->getSmileyPath('1f61d')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😒"><img alt=":unamused:" class="emoji" src="{$c->getSmileyPath('1f612')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😒"><img alt=":unamused:" class="emoji large" src="{$c->getSmileyPath('1f612')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😓"><img alt=":sweat:" class="emoji" src="{$c->getSmileyPath('1f613')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😓"><img alt=":sweat:" class="emoji large" src="{$c->getSmileyPath('1f613')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😖"><img alt=":confounded:" class="emoji" src="{$c->getSmileyPath('1f616')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😖"><img alt=":confounded:" class="emoji large" src="{$c->getSmileyPath('1f616')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="😢"><img alt=":cry:" class="emoji" src="{$c->getSmileyPath('1f622')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😢"><img alt=":cry:" class="emoji large" src="{$c->getSmileyPath('1f622')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😤"><img alt=":triumph:" class="emoji" src="{$c->getSmileyPath('1f624')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😤"><img alt=":triumph:" class="emoji large" src="{$c->getSmileyPath('1f624')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😥"><img alt=":disappointed_relieved:" class="emoji" src="{$c->getSmileyPath('1f625')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😥"><img alt=":disappointed_relieved:" class="emoji large" src="{$c->getSmileyPath('1f625')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😪"><img alt=":sleepy:" class="emoji" src="{$c->getSmileyPath('1f62a')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😪"><img alt=":sleepy:" class="emoji large" src="{$c->getSmileyPath('1f62a')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😭"><img alt=":sob:" class="emoji" src="{$c->getSmileyPath('1f62d')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😭"><img alt=":sob:" class="emoji large" src="{$c->getSmileyPath('1f62d')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="😱"><img alt=":scream:" class="emoji" src="{$c->getSmileyPath('1f631')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="😱"><img alt=":scream:" class="emoji large" src="{$c->getSmileyPath('1f631')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="🍌"><img alt=":banana:" class="emoji" src="{$c->getSmileyPath('1f34c')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍌"><img alt=":banana:" class="emoji large" src="{$c->getSmileyPath('1f34c')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍎"><img alt=":apple:" class="emoji" src="{$c->getSmileyPath('1f34e')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍎"><img alt=":apple:" class="emoji large" src="{$c->getSmileyPath('1f34e')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🌼"><img alt=":blossom:" class="emoji" src="{$c->getSmileyPath('1f33c')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🌼"><img alt=":blossom:" class="emoji large" src="{$c->getSmileyPath('1f33c')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🌵"><img alt=":cactus:" class="emoji" src="{$c->getSmileyPath('1f335')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🌵"><img alt=":cactus:" class="emoji large" src="{$c->getSmileyPath('1f335')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🌹"><img alt=":rose:" class="emoji" src="{$c->getSmileyPath('1f339')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🌹"><img alt=":rose:" class="emoji large" src="{$c->getSmileyPath('1f339')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍄"><img alt=":mushroom:" class="emoji" src="{$c->getSmileyPath('1f344')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍄"><img alt=":mushroom:" class="emoji large" src="{$c->getSmileyPath('1f344')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="🍔"><img alt=":hamburger:" class="emoji" src="{$c->getSmileyPath('1f354')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍔"><img alt=":hamburger:" class="emoji large" src="{$c->getSmileyPath('1f354')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍕"><img alt=":pizza:" class="emoji" src="{$c->getSmileyPath('1f355')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍕"><img alt=":pizza:" class="emoji large" src="{$c->getSmileyPath('1f355')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍗"><img alt=":poultry_leg:" class="emoji" src="{$c->getSmileyPath('1f357')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍗"><img alt=":poultry_leg:" class="emoji large" src="{$c->getSmileyPath('1f357')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍚"><img alt=":rice:" class="emoji" src="{$c->getSmileyPath('1f35a')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍚"><img alt=":rice:" class="emoji large" src="{$c->getSmileyPath('1f35a')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍜"><img alt=":ramen:" class="emoji" src="{$c->getSmileyPath('1f35c')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍜"><img alt=":ramen:" class="emoji large" src="{$c->getSmileyPath('1f35c')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🍣"><img alt=":sushi:" class="emoji" src="{$c->getSmileyPath('1f363')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🍣"><img alt=":sushi:" class="emoji large" src="{$c->getSmileyPath('1f363')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="🛀"><img alt=":bath:" class="emoji" src="{$c->getSmileyPath('1f6c0')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🛀"><img alt=":bath:" class="emoji large" src="{$c->getSmileyPath('1f6c0')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🎧"><img alt=":headphones:" class="emoji" src="{$c->getSmileyPath('1f3a7')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🎧"><img alt=":headphones:" class="emoji large" src="{$c->getSmileyPath('1f3a7')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🎮"><img alt=":video_game:" class="emoji" src="{$c->getSmileyPath('1f3ae')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🎮"><img alt=":video_game:" class="emoji large" src="{$c->getSmileyPath('1f3ae')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🎫"><img alt=":ticket:" class="emoji" src="{$c->getSmileyPath('1f3ab')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🎫"><img alt=":ticket:" class="emoji large" src="{$c->getSmileyPath('1f3ab')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="💼"><img alt=":briefcase:" class="emoji" src="{$c->getSmileyPath('1f4bc')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="💼"><img alt=":briefcase:" class="emoji large" src="{$c->getSmileyPath('1f4bc')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🎒"><img alt=":school_satchel:" class="emoji" src="{$c->getSmileyPath('1f392')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🎒"><img alt=":school_satchel:" class="emoji large" src="{$c->getSmileyPath('1f392')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="💡"><img alt=":bulb:" class="emoji" src="{$c->getSmileyPath('1f4a1')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="💡"><img alt=":bulb:" class="emoji large" src="{$c->getSmileyPath('1f4a1')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="📞"><img alt=":telephone_receiver:" class="emoji" src="{$c->getSmileyPath('1f4de')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="📞"><img alt=":telephone_receiver:" class="emoji large" src="{$c->getSmileyPath('1f4de')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🔥"><img alt=":fire:" class="emoji" src="{$c->getSmileyPath('1f525')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🔥"><img alt=":fire:" class="emoji large" src="{$c->getSmileyPath('1f525')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🕐"><img alt=":clock1:" class="emoji" src="{$c->getSmileyPath('1f550')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🕐"><img alt=":clock1:" class="emoji large" src="{$c->getSmileyPath('1f550')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="✉"><img alt=":email:" class="emoji" src="{$c->getSmileyPath('2709')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="✉"><img alt=":email:" class="emoji large" src="{$c->getSmileyPath('2709')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="✏"><img alt=":pencil2:" class="emoji" src="{$c->getSmileyPath('270f')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="✏"><img alt=":pencil2:" class="emoji large" src="{$c->getSmileyPath('270f')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="💋"><img alt=":kiss:" class="emoji" src="{$c->getSmileyPath('1f48b')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="💋"><img alt=":kiss:" class="emoji large" src="{$c->getSmileyPath('1f48b')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="♥"><img alt=":hearts:" class="emoji" src="{$c->getSmileyPath('2665')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="♥"><img alt=":hearts:" class="emoji large" src="{$c->getSmileyPath('2665')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="💊"><img alt=":pill:" class="emoji" src="{$c->getSmileyPath('1f48a')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="💊"><img alt=":pill:" class="emoji large" src="{$c->getSmileyPath('1f48a')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="💩"><img alt=":hankey:" class="emoji" src="{$c->getSmileyPath('1f4a9')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="💩"><img alt=":hankey:" class="emoji large" src="{$c->getSmileyPath('1f4a9')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="☕"><img alt=":coffee:" class="emoji" src="{$c->getSmileyPath('2615')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="☕"><img alt=":coffee:" class="emoji large" src="{$c->getSmileyPath('2615')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="⏰"><img alt=":alarm_clock:" class="emoji" src="{$c->getSmileyPath('23f0')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="⏰"><img alt=":alarm_clock:" class="emoji large" src="{$c->getSmileyPath('23f0')}"></td>
</tr> </tr>
<tr class="active"> <tr class="active">
<td onclick="Chat.addSmiley(this);" data-emoji="🐷"><img alt=":pig:" class="emoji" src="{$c->getSmileyPath('1f437')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐷"><img alt=":pig:" class="emoji large" src="{$c->getSmileyPath('1f437')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🐵"><img alt=":monkey_face:" class="emoji" src="{$c->getSmileyPath('1f435')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐵"><img alt=":monkey_face:" class="emoji large" src="{$c->getSmileyPath('1f435')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🐶"><img alt=":dog:" class="emoji" src="{$c->getSmileyPath('1f436')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐶"><img alt=":dog:" class="emoji large" src="{$c->getSmileyPath('1f436')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🐸"><img alt=":frog:" class="emoji" src="{$c->getSmileyPath('1f438')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐸"><img alt=":frog:" class="emoji large" src="{$c->getSmileyPath('1f438')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🐹"><img alt=":hamster:" class="emoji" src="{$c->getSmileyPath('1f439')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐹"><img alt=":hamster:" class="emoji large" src="{$c->getSmileyPath('1f439')}"></td>
<td onclick="Chat.addSmiley(this);" data-emoji="🐻"><img alt=":bear:" class="emoji" src="{$c->getSmileyPath('1f43b')}"></td> <td onclick="Chat.addSmiley(this);" data-emoji="🐻"><img alt=":bear:" class="emoji large" src="{$c->getSmileyPath('1f43b')}"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View file

@ -49,11 +49,6 @@
margin-bottom: 1rem; margin-bottom: 1rem;
} }
#chat_widget .emojis_open img {
width: 36px;
margin: 0.2rem;
}
/* Chatroom */ /* Chatroom */
#chat_widget li span.icon { #chat_widget li span.icon {
@ -61,16 +56,16 @@
margin-top: 0.85rem; margin-top: 0.85rem;
} }
#chat_widget li img:not(.emoji) { #chat_widget li img:not(.emoji):not(.hfr) {
max-height: 30rem; max-height: 30rem;
max-width: 100%; max-width: 100%;
display: block; display: block;
} }
/*
#chat_widget li img.emoji { #chat_widget li img.emoji {
padding: 0 0.25rem; padding: 0.25rem;
} }
*/
#chat_widget li.room { #chat_widget li.room {
min-height: 3rem; min-height: 3rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;

View file

@ -3,6 +3,8 @@ var Chat = {
right: null, right: null,
room: null, room: null,
previous: null, previous: null,
date: null,
lastScroll: null,
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;
@ -47,15 +49,28 @@ var Chat = {
Chat.right = div.firstChild.cloneNode(true); Chat.right = div.firstChild.cloneNode(true);
div.innerHTML = room; div.innerHTML = room;
Chat.room = div.firstChild.cloneNode(true); Chat.room = div.firstChild.cloneNode(true);
Chat.setScrollBehaviour();
},
setScrollBehaviour : function() {
var discussion = document.querySelector('#chat_widget div.contained');
discussion.onscroll = function() {
if(this.scrollTop < 1) {
var chat = document.querySelector('#chat_widget');
Chat.lastScroll = this.scrollHeight;
Chat_ajaxGetHistory(chat.dataset.jid, Chat.date);
}
};
}, },
appendMessages : function(messages) { appendMessages : function(messages) {
if(messages) { if(messages) {
Chat.date = messages[0].published;
for(var i = 0, len = messages.length; i < len; ++i ) { for(var i = 0, len = messages.length; i < len; ++i ) {
Chat.appendMessage(messages[i]); Chat.appendMessage(messages[i], false);
} }
} }
}, },
appendMessage : function(message) { appendMessage : function(message, prepend) {
if(message.body == '') return; if(message.body == '') return;
var bubble = null; var bubble = null;
@ -74,7 +89,7 @@ var Chat = {
} }
bubble.querySelector('div').innerHTML = message.body; bubble.querySelector('div').innerHTML = message.body;
bubble.querySelector('span.info').innerHTML = message.published; bubble.querySelector('span.info').innerHTML = message.publishedPrepared;
bubble.querySelector('span.user').className = 'user ' + message.color; bubble.querySelector('span.user').className = 'user ' + message.color;
bubble.querySelector('span.user').onclick = function(n) { bubble.querySelector('span.user').onclick = function(n) {
@ -117,21 +132,37 @@ var Chat = {
if(bubble) { if(bubble) {
bubble.querySelector('div.bubble div').innerHTML = message.body; bubble.querySelector('div.bubble div').innerHTML = message.body;
bubble.querySelector('div.bubble span.info').innerHTML = message.published; bubble.querySelector('div.bubble span.info').innerHTML = message.publishedPrepared;
if(prepend) {
Chat.date = message.published;
var discussion = document.querySelector('#chat_widget div.contained');
// We prepend
movim_prepend(id, bubble.outerHTML);
// And we scroll where we were
var scrollDiff = discussion.scrollHeight - Chat.lastScroll;
discussion.scrollTop += scrollDiff;
Chat.lastScroll = discussion.scrollHeight;
} else {
movim_append(id, bubble.outerHTML); movim_append(id, bubble.outerHTML);
}
bubble.querySelector('div.bubble').className = 'bubble'; bubble.querySelector('div.bubble').className = 'bubble';
if(bubble.className.indexOf('oppose') > -1) MovimTpl.scrollPanel(); if(bubble.className.indexOf('oppose') > -1
&& prepend == null) MovimTpl.scrollPanel();
} }
} }
if(scrolled) MovimTpl.scrollPanel(); if(scrolled && prepend == null) MovimTpl.scrollPanel();
} }
} }
MovimWebsocket.attach(function() { MovimWebsocket.attach(function() {
var jid = document.querySelector('#chat_widget').dataset.jid; var chat = document.querySelector('#chat_widget');
var jid = chat.dataset.jid;
if(jid) { if(jid) {
MovimTpl.showPanel(); MovimTpl.showPanel();
Chat_ajaxGet(jid); Chat_ajaxGet(jid);

View file

@ -4,6 +4,7 @@ encrypted = Encrypted message
composing = Composing... composing = Composing...
paused = Paused... paused = Paused...
gone = Contact gone gone = Contact gone
history = %s messages retrieved
[chat] [chat]
attention = %s needs your attention attention = %s needs your attention

View file

@ -32,13 +32,6 @@ class Chats extends WidgetBase
} }
$this->ajaxOpen($from, false); $this->ajaxOpen($from, false);
/*
$chats = Cache::c('chats');
if(!array_key_exists($from, $chats)) {
$this->ajaxOpen($from);
} else {
RPC::call('Chats.prepend', $from, $this->prepareChat($from));
}*/
} }
} }
@ -217,7 +210,7 @@ class Chats extends WidgetBase
private function validateJid($jid) private function validateJid($jid)
{ {
$validate_jid = Validator::string()->noWhitespace()->length(6, 40); $validate_jid = Validator::stringType()->noWhitespace()->length(6, 40);
if($validate_jid->validate($jid)) return true; if($validate_jid->validate($jid)) return true;
else return false; else return false;

View file

@ -16,6 +16,7 @@ var Chats = {
Chats.reset(items); Chats.reset(items);
Notification_ajaxClear('chat|' + this.dataset.jid); Notification_ajaxClear('chat|' + this.dataset.jid);
Notification.current('chat|' + this.dataset.jid); Notification.current('chat|' + this.dataset.jid);
document.querySelector('#chat_widget').dataset.jid = this.dataset.jid;
movim_add_class(this, 'active'); movim_add_class(this, 'active');
} }
@ -24,6 +25,7 @@ var Chats = {
Notification_ajaxClear('chat|' + this.dataset.jid); Notification_ajaxClear('chat|' + this.dataset.jid);
Notification.current('chat'); Notification.current('chat');
Chats_ajaxClose(this.dataset.jid); Chats_ajaxClose(this.dataset.jid);
delete document.querySelector('#chat_widget').dataset.jid;
MovimTpl.hidePanel(); MovimTpl.hidePanel();
} }
} }

View file

@ -19,6 +19,7 @@
*/ */
use Moxl\Xec\Action\Storage\Set; use Moxl\Xec\Action\Storage\Set;
use Respect\Validation\Validator;
class Config extends WidgetBase class Config extends WidgetBase
{ {
@ -59,15 +60,19 @@ class Config extends WidgetBase
$data = (array)$package->content; $data = (array)$package->content;
$this->user->setConfig($data); $this->user->setConfig($data);
$html = $this->prepareConfigForm(); $this->refreshConfig();
RPC::call('movim_fill', 'config_widget', $html);
RPC::call('Config.load');
Notification::append(null, $this->__('config.updated')); Notification::append(null, $this->__('config.updated'));
} }
function ajaxSubmit($data) function ajaxSubmit($data)
{ {
if(!$this->validateForm($data)) {
$this->refreshConfig();
Notification::append(null, $this->__('config.not_valid'));
return;
}
$config = $this->user->getConfig(); $config = $this->user->getConfig();
if(isset($config)) if(isset($config))
$data = array_merge($config, $data); $data = array_merge($config, $data);
@ -78,6 +83,25 @@ class Config extends WidgetBase
->request(); ->request();
} }
private function refreshConfig()
{
$html = $this->prepareConfigForm();
RPC::call('movim_fill', 'config_widget', $html);
RPC::call('Config.load');
}
private function validateForm($data)
{
$l = Movim\i18n\Locale::start();
if(Validator::in(array_keys($l->getList()))->validate($data['language'])
&& Validator::in(array('show', 'hide'))->validate($data['roster'])
&& ($data['cssurl'] == '' || Validator::url()->validate($data['cssurl'])))
return true;
return false;
}
function display() function display()
{ {
$this->view->assign('form', $this->prepareConfigForm()); $this->view->assign('form', $this->prepareConfigForm());

View file

@ -38,107 +38,13 @@
<label for="roster">{$c->__('config.roster')}</label> <label for="roster">{$c->__('config.roster')}</label>
</div> </div>
<div class="clear"></div>
<br /> <br />
<!-- <h3>{$c->__('config.advanced')}</h3>
<h3>{$c->__('config.notifications')}</h3>
<div class="block"> <div class="block">
<div class="checkbox"> <input name="cssurl" class="content" placeholder="http://myserver.com/style.css" value="{$conf.cssurl}" type="url">
<input <label for="cssurl">{$c->__('cssurl.label')}</label>
type="checkbox"
id="privacy"
name="privacy"
{if="$me->privacy"}
checked
{/if}
onchange="{$privacy}">
<label for="privacy"></label>
</div> </div>
<label for="language">{$c->__('notifications.message')}</label>
</div>
<div class="block">
<div class="checkbox">
<input
type="checkbox"
id="privacy"
name="privacy"
{if="$me->privacy"}
checked
{/if}
onchange="{$privacy}">
<label for="privacy"></label>
</div>
<label for="language">{$c->__('notifications.desktop')}</label>
</div>-->
<!--
<h3>{$c->__('config.appearence')}</h3>-->
<!--<div class="block large" id="nav_color">
<a
type="button"
style="width: 45%; float: right;"
class="button flat">
{$c->__('button.reset')}
</a>
<input
style="box-shadow: none; width: 50%; float: left;"
name="color"
class="color"
value="
{if="isset($color)"}
{$color}
{else}
082D50
{/if}
">
<label for="color"><i class="fa fa-adjust"></i> {$c->__('config.background_color')}</label>
</div>-->
<!--
<div class="block large" id="font_size">
<label for="size"><i class="fa fa-font"></i> {$c->__('config.font_size')}</label>
<a
type="button"
class="button flat">
{$c->__('button.reset')}
</a>
<span>
12
<input
id="slide"
type="range"
min="12"
max="16"
step="0.5"
value="
{if="isset($size)"}
{$size}
{else}
14
{/if}
"
name="size"
style="width: 45%;"
/>
16
</span>
<span id="currentsize">
{if="isset($size)"}
{$size}
{else}
14
{/if}
px
</span>
</div>
-->
<!--<label id="lock" for="soundnotif">{$c->t('Enable Sound Notification:'); ?></label>
<input type="checkbox" name="soundnotif" value="soundnotif" checked="checked" /><br /> -->
<!--<input value="{$c->t('Submit'); ?>" onclick="<?php echo $submit; ?>" type="button" class="button icon yes merged right" style="float: right;">
<input type="reset" value="{$c->t('Reset'); ?>" class="button icon no merged left" style="float: right;">-->
<div class="clear padded"></div> <div class="clear padded"></div>
<a <a
@ -148,5 +54,3 @@
</a> </a>
<div class="clear"></div> <div class="clear"></div>
</form> </form>
<!--
<div class="message info">{$c->__('config.info')}</div>-->

View file

@ -5,9 +5,13 @@ roster = Roster display
roster_show = Show the offline contacts roster_show = Show the offline contacts
roster_hide = Hide the offline contacts roster_hide = Hide the offline contacts
appearence = Appearence appearence = Appearence
info = This configuration is shared wherever you are connected
updated = Configuration updated updated = Configuration updated
not_valid = Configuration invalid
advanced = Advanced Configuration
[notifications] [notifications]
message = Notify on incoming message message = Notify on incoming message
desktop = Use desktop notifications desktop = Use desktop notifications
[cssurl]
label = Custom CSS URL for your blog

View file

@ -178,7 +178,7 @@ class Contact extends WidgetBase
function ajaxPublic($page = 0) function ajaxPublic($page = 0)
{ {
$validate_page = Validator::int(); $validate_page = Validator::intType();
if(!$validate_page->validate($page)) return; if(!$validate_page->validate($page)) return;
RPC::call('MovimTpl.fill', '#public_list', $this->preparePublic($page)); RPC::call('MovimTpl.fill', '#public_list', $this->preparePublic($page));
@ -221,7 +221,7 @@ class Contact extends WidgetBase
$view = $this->tpl(); $view = $this->tpl();
$pd = new \Modl\PostnDAO; $pd = new \Modl\PostnDAO;
$gallery = $pd->getGallery($jid); $gallery = $pd->getGallery($jid, 0, 12);
$blog = $pd->getPublic($jid, 'urn:xmpp:microblog:0', 0, 4); $blog = $pd->getPublic($jid, 'urn:xmpp:microblog:0', 0, 4);
$presencestxt = getPresencesTxt(); $presencestxt = getPresencesTxt();
@ -289,7 +289,7 @@ class Contact extends WidgetBase
*/ */
private function validateJid($jid) private function validateJid($jid)
{ {
$validate_jid = Validator::string()->noWhitespace()->length(6, 60); $validate_jid = Validator::stringType()->noWhitespace()->length(6, 60);
if(!$validate_jid->validate($jid)) return false; if(!$validate_jid->validate($jid)) return false;
else return true; else return true;
} }

View file

@ -176,7 +176,7 @@
<span class="info">{$value->published|strtotime|prepareDate}</span> <span class="info">{$value->published|strtotime|prepareDate}</span>
</li> </li>
{/loop} {/loop}
<a href="{$c->route('blog', array($jid))}" target="_blank" class="block large"> <a href="{$c->route('blog', array($contact->jid))}" target="_blank" class="block large">
<li class="action"> <li class="action">
<div class="action"> <div class="action">
<i class="zmdi zmdi-chevron-right"></i> <i class="zmdi zmdi-chevron-right"></i>
@ -315,7 +315,7 @@
<li style="background-image: url('{$attachements['pictures'][0]['href']}');" <li style="background-image: url('{$attachements['pictures'][0]['href']}');"
onclick="movim_reload('{$c->route('news', $value->nodeid)}')"> onclick="movim_reload('{$c->route('news', $value->nodeid)}')">
<nav> <nav>
{$attachements['pictures'][0]['title']} <span>{$value->title}</span>
</nav> </nav>
</li> </li>
{/loop} {/loop}

View file

@ -381,6 +381,11 @@ class Group extends WidgetBase
return $html; return $html;
} }
public function preparePost($p) {
$pw = new Post;
return $pw->preparePost($p, true);
}
private function prepareHeader($server, $node) private function prepareHeader($server, $node)
{ {
$pd = new \Modl\ItemDAO; $pd = new \Modl\ItemDAO;
@ -416,8 +421,8 @@ class Group extends WidgetBase
private function validateServerNode($server, $node) private function validateServerNode($server, $node)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 40); $validate_server = Validator::stringType()->noWhitespace()->length(6, 40);
$validate_node = Validator::string()->length(3, 100); $validate_node = Validator::stringType()->length(3, 100);
if(!$validate_server->validate($server) if(!$validate_server->validate($server)
|| !$validate_node->validate($node) || !$validate_node->validate($node)

View file

@ -1,4 +1,6 @@
{loop="$posts"} {loop="$posts"}
{$c->preparePost($value)}
<!--
{$attachements = $value->getAttachements()} {$attachements = $value->getAttachements()}
<article id="{$value->nodeid}" class="block"> <article id="{$value->nodeid}" class="block">
{if="isset($attachements.pictures)"} {if="isset($attachements.pictures)"}
@ -36,6 +38,9 @@
- -
{/if} {/if}
{$value->published|strtotime|prepareDate} {$value->published|strtotime|prepareDate}
{if="$value->published != $value->updated"}
- <i class="zmdi zmdi-edit"></i> {$value->updated|strtotime|prepareDate}
{/if}
</p> </p>
</li> </li>
</ul> </ul>
@ -53,6 +58,19 @@
</content> </content>
</section> </section>
<footer> <footer>
{$tags = $value->getTags()}
{if="isset($tags)"}
<ul class="middle">
<li>
<span class="icon zmdi zmdi-tag gray"></span>
<span>
{loop="$tags"}
<a target="_blank" href="{$c->route('tag', array($value))}">#{$value}</a>
{/loop}
</span>
</li>
</ul>
{/if}
<ul class="thin"> <ul class="thin">
{if="isset($attachements.links)"} {if="isset($attachements.links)"}
{loop="$attachements.links"} {loop="$attachements.links"}
@ -171,7 +189,7 @@
</ul> </ul>
{/if} {/if}
<br /> <br />
</article> </article>-->
{/loop} {/loop}
{if="$posts != null && count($posts) >= $paging-1"} {if="$posts != null && count($posts) >= $paging-1"}
<ul class="active thick"> <ul class="active thick">

View file

@ -118,7 +118,7 @@ class Groups extends WidgetBase
{ {
if(!$this->validateServer($server)) return; if(!$this->validateServer($server)) return;
$validate_name = Validator::string()->length(4, 80); $validate_name = Validator::stringType()->length(4, 80);
if(!$validate_name->validate($form->name->value)) { if(!$validate_name->validate($form->name->value)) {
Notification::append(null, $this->__('groups.name_error')); Notification::append(null, $this->__('groups.name_error'));
return; return;
@ -191,7 +191,7 @@ class Groups extends WidgetBase
*/ */
private function validateServer($server) private function validateServer($server)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 40); $validate_server = Validator::stringType()->noWhitespace()->length(6, 40);
if(!$validate_server->validate($server)) return false; if(!$validate_server->validate($server)) return false;
else return true; else return true;
} }

View file

@ -1,6 +1,6 @@
{if="$subscriptions == null"} {if="$subscriptions == null"}
<ul class="thick"> <ul class="thick">
<div class="placeholder icon pages"> <div class="placeholder icon bookmark">
<h1>{$c->__('groups.empty_title')}</h1> <h1>{$c->__('groups.empty_title')}</h1>
<h4>{$c->__('groups.empty_text1')}</h4> <h4>{$c->__('groups.empty_text1')}</h4>
<h4>{$c->__('groups.empty_text2')}</h4> <h4>{$c->__('groups.empty_text2')}</h4>

View file

@ -4,7 +4,7 @@
{$a = '1f600'} {$a = '1f600'}
<li> <li>
<h2>{$c->__('hello.enter_title')}</h2> <h2>{$c->__('hello.enter_title')}</h2>
<p>{$c->__('hello.enter_paragraph')} <img alt=":smiley:" class="emoji" src="{$a|getSmileyPath:false}"></p> <p class="all">{$c->__('hello.enter_paragraph')} <img alt=":smiley:" class="emoji" src="{$a|getSmileyPath}"></p>
</li> </li>
</ul> </ul>
<ul class="middle"> <ul class="middle">
@ -14,7 +14,7 @@
<i class="zmdi zmdi-cloud-outline on_desktop"></i> <i class="zmdi zmdi-cloud-outline on_desktop"></i>
</span> </span>
<span>{$c->__('hello.menu_title')}</span> <span>{$c->__('hello.menu_title')}</span>
<p>{$c->__('hello.menu_paragraph')}</p> <p class="all">{$c->__('hello.menu_paragraph')}</p>
</li> </li>
</ul> </ul>
{/if} {/if}
@ -77,6 +77,7 @@
</li> </li>
{/if} {/if}
{loop="$news"} {loop="$news"}
{$attachements = $value->getAttachements()}
<li class="block condensed" <li class="block condensed"
data-id="{$value->nodeid}" data-id="{$value->nodeid}"
{if="$value->title != null"} {if="$value->title != null"}

View file

@ -4,7 +4,23 @@ class Help extends WidgetBase
{ {
function load() function load()
{ {
$this->addjs('help.js'); }
function ajaxAddChatroom()
{
$r = new Rooms;
$r->ajaxChatroomAdd(
array(
'jid' => 'movim@conference.movim.eu',
'name'=> 'Movim Chatroom',
'nick' => false,
'autojoin' => 0
)
);
$r->ajaxJoin('movim@conference.movim.eu');
RPC::call('movim_redirect', $this->route('chat'));
} }
function display() function display()

View file

@ -1,9 +1,9 @@
<div class="tabelem" title="{$c->__('page.help')}" id="help_widget"> <div class="tabelem" title="{$c->__('page.help')}" id="help_widget">
<ul class="thick active"> <ul class="thick active">
<li class="condensed action"> <li class="condensed action">
<a href="http://wiki.movim.eu" target="_blank"> <a href="https://github.com/edhelas/movim/wiki" target="_blank">
<span class="icon bubble color blue"> <span class="icon bubble color blue">
<i class="zmdi zmdi-format-subject"></i> <i class="zmdi zmdi-github-alt"></i>
</span> </span>
<span>{$c->__('wiki.question')}</span> <span>{$c->__('wiki.question')}</span>
<p>{$c->__('wiki.button')}</p> <p>{$c->__('wiki.button')}</p>
@ -13,7 +13,7 @@
</div> </div>
</li> </li>
<li class="condensed action"> <li class="condensed action">
<a href="http://wiki.movim.eu/en:mailing_list" target="_blank"> <a href="https://github.com/edhelas/movim/wiki/Mailing-List" target="_blank">
<span class="icon bubble color orange"> <span class="icon bubble color orange">
<i class="zmdi zmdi-email"></i> <i class="zmdi zmdi-email"></i>
</span> </span>
@ -24,12 +24,15 @@
<i class="zmdi zmdi-chevron-right"></i> <i class="zmdi zmdi-chevron-right"></i>
</div> </div>
</li> </li>
<li class="condensed"> <li class="condensed action" onclick="Help_ajaxAddChatroom()">
<span class="icon bubble color green"> <span class="icon bubble color green">
<i class="zmdi zmdi-comment-text-alt"></i> <i class="zmdi zmdi-comment-text-alt"></i>
</span> </span>
<span>{$c->__('chatroom.question')}</span> <span>{$c->__('chatroom.question')}</span>
<p>{$c->__('chatroom.button')}<br/>movim@conference.movim.eu</p> <p>{$c->__('chatroom.button')}<br/>movim@conference.movim.eu</p>
<div class="action">
<i class="zmdi zmdi-accounts-add"></i>
</div>
</li> </li>
</ul> </ul>
<!-- <!--

View file

@ -20,4 +20,4 @@ button = Join the Mailing List
[chatroom] [chatroom]
question = Chat with the team ? question = Chat with the team ?
button = Join the Chatroom button = Add the chatroom

View file

@ -167,7 +167,7 @@ class Login extends WidgetBase
// First we check the form // First we check the form
$validate_login = Validator::email()->length(6, 40); $validate_login = Validator::email()->length(6, 40);
$validate_password = Validator::string()->length(4, 40); $validate_password = Validator::stringType()->length(4, 40);
if(!$validate_login->validate($login)) { if(!$validate_login->validate($login)) {
$this->showErrorBlock('login_format'); $this->showErrorBlock('login_format');

View file

@ -24,10 +24,10 @@
</ul> </ul>
</section> </section>
<div> <div>
<a class="button flat" href="{$c->route('about')}"> <a class="button flat" href="{$c->route('about')}" title="{$c->__('page.about')}">
<i class="zmdi zmdi-help"></i> <i class="zmdi zmdi-help"></i>
</a> </a>
<a class="button flat" href="{$c->route('admin')}"> <a class="button flat" href="{$c->route('admin')}" title="{$c->__('page.administration')}">
<i class="zmdi zmdi-pages"></i> <i class="zmdi zmdi-pages"></i>
</a> </a>
<span class="button flat" onclick="Login.toForm()">{$c->__('form.another_account')}</span> <span class="button flat" onclick="Login.toForm()">{$c->__('form.another_account')}</span>

View file

@ -21,7 +21,7 @@
name="login"> name="login">
<div> <div>
<input type="email" name="login" id="login" autofocus required disabled <input type="email" name="login" id="login" autofocus required disabled
placeholder="{$c->__('form.username')}"/> placeholder="username@server.com"/>
<label for="login">{$c->__('form.username')}</label> <label for="login">{$c->__('form.username')}</label>
</div> </div>
<div> <div>

View file

@ -27,7 +27,7 @@ class LoginAnonymous extends WidgetBase
function ajaxLogin($username) function ajaxLogin($username)
{ {
$validate_user = Validator::string()->length(4, 40); $validate_user = Validator::stringType()->length(4, 40);
if(!$validate_user->validate($username)) { if(!$validate_user->validate($username)) {
Notification::append(null, $this->__('login_anonymous.bad_username')); Notification::append(null, $this->__('login_anonymous.bad_username'));
return; return;

View file

@ -5,6 +5,7 @@
{/if} {/if}
{loop="$items"} {loop="$items"}
{$attachements = $value->getAttachements()}
<li <li
tabindex="{$page*$paging+$key+1}" tabindex="{$page*$paging+$key+1}"
class="block large condensed " class="block large condensed "
@ -55,6 +56,7 @@
</a> </a>
{/if} {/if}
{$value->published|strtotime|prepareDate} {$value->published|strtotime|prepareDate}
{if="$value->published != $value->updated"}<i class="zmdi zmdi-edit"></i>{/if}
</p> </p>
{if="$value->privacy"} {if="$value->privacy"}

View file

@ -7,6 +7,7 @@ var Notification = {
tab_counter2 : 0, tab_counter2 : 0,
tab_counter1_key : 'chat', tab_counter1_key : 'chat',
tab_counter2_key : 'news', tab_counter2_key : 'news',
document_title_init : null,
document_title : document.title, document_title : document.title,
notifs_key : '', notifs_key : '',
favicon : null, favicon : null,
@ -141,6 +142,8 @@ var Notification = {
} }
} }
Notification.document_title_init = document.title;
MovimWebsocket.attach(function() { MovimWebsocket.attach(function() {
if(typeof Favico != 'undefined') { if(typeof Favico != 'undefined') {
Notification.favicon = new Favico({ Notification.favicon = new Favico({
@ -155,7 +158,8 @@ MovimWebsocket.attach(function() {
Notification.electron = remote.getCurrentWindow(); Notification.electron = remote.getCurrentWindow();
} }
Notification.document_title = document.title; Notification.document_title = Notification.document_title_init;
Notification.tab_counter1 = Notification.tab_counter2 = 0;
Notification_ajaxGet(); Notification_ajaxGet();
Notification.current(Notification.notifs_key); Notification.current(Notification.notifs_key);
}); });

View file

@ -20,6 +20,7 @@
use Moxl\Xec\Action\Pubsub\PostPublish; use Moxl\Xec\Action\Pubsub\PostPublish;
use Moxl\Xec\Action\Pubsub\PostDelete; use Moxl\Xec\Action\Pubsub\PostDelete;
use Moxl\Xec\Action\Pubsub\GetItem;
use Moxl\Xec\Action\Microblog\CommentsGet; use Moxl\Xec\Action\Microblog\CommentsGet;
use Moxl\Xec\Action\Microblog\CommentCreateNode; use Moxl\Xec\Action\Microblog\CommentCreateNode;
use Moxl\Xec\Action\Microblog\CommentPublish; use Moxl\Xec\Action\Microblog\CommentPublish;
@ -96,7 +97,16 @@ class Post extends WidgetBase
function ajaxGetPost($id) function ajaxGetPost($id)
{ {
$html = $this->preparePost($id); $pd = new \Modl\PostnDAO;
$p = $pd->getItem($id);
$gi = new GetItem;
$gi->setTo($p->origin)
->setNode($p->node)
->setId($p->nodeid)
->request();
$html = $this->preparePost($p);
$header = $this->prepareHeader($id); $header = $this->prepareHeader($id);
Header::fill($header); Header::fill($header);
@ -137,8 +147,8 @@ class Post extends WidgetBase
{ {
$comment = trim($form->comment->value); $comment = trim($form->comment->value);
$validate_comment = Validator::string()->notEmpty(); $validate_comment = Validator::stringType()->notEmpty();
$validate_id = Validator::string()->length(6, 128)->noWhitespace(); $validate_id = Validator::stringType()->length(6, 128)->noWhitespace();
if(!$validate_comment->validate($comment) if(!$validate_comment->validate($comment)
|| !$validate_id->validate($id)) return; || !$validate_id->validate($id)) return;
@ -178,19 +188,18 @@ class Post extends WidgetBase
return $view->draw('_post_header', true); return $view->draw('_post_header', true);
} }
function preparePost($id) function preparePost($p, $external = false, $public = false)
{ {
$pd = new \Modl\PostnDAO;
$p = $pd->getItem($id);
$view = $this->tpl(); $view = $this->tpl();
if(isset($p)) { if(isset($p)) {
if(isset($p->commentplace)) { if(isset($p->commentplace) && !$external) {
$this->ajaxGetComments($p->commentplace, $p->nodeid); $this->ajaxGetComments($p->commentplace, $p->nodeid);
} }
$view->assign('recycled', false); $view->assign('recycled', false);
$view->assign('external', $external);
$view->assign('public', $public);
// Is it a recycled post ? // Is it a recycled post ?
if($p->getContact()->jid if($p->getContact()->jid
@ -203,13 +212,13 @@ class Post extends WidgetBase
$view->assign('post', $p); $view->assign('post', $p);
$view->assign('attachements', $p->getAttachements()); $view->assign('attachements', $p->getAttachements());
return $view->draw('_post', true); return $view->draw('_post', true);
} else { } elseif(!$external) {
return $this->prepareEmpty(); return $this->prepareEmpty();
} }
} }
function ajaxTogglePrivacy($id) { function ajaxTogglePrivacy($id) {
$validate = Validator::string()->length(6, 128); $validate = Validator::stringType()->length(6, 128);
if(!$validate->validate($id)) if(!$validate->validate($id))
return; return;
@ -232,9 +241,15 @@ class Post extends WidgetBase
} }
} }
function getComments($post)
{
$pd = new \Modl\PostnDAO();
return $pd->getComments($post);
}
function display() function display()
{ {
$validate_nodeid = Validator::string()->length(10, 100); $validate_nodeid = Validator::stringType()->length(10, 100);
$this->view->assign('nodeid', false); $this->view->assign('nodeid', false);
if($validate_nodeid->validate($this->get('n'))) { if($validate_nodeid->validate($this->get('n'))) {

View file

@ -1,9 +1,11 @@
<article class="block"> <article class="block">
{if="isset($attachements.pictures)"} {if="isset($attachements.pictures)"}
{if="($public && $post->isPublic()) || !$public"}
<header <header
class="big" class="big"
style=" style="
background-image: linear-gradient(to bottom, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 100%), url('{$attachements['pictures'][0]['href']}');"> background-image: linear-gradient(to bottom, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 100%), url('{$attachements['pictures'][0]['href']}');">
{/if}
{else} {else}
<header> <header>
{/if} {/if}
@ -34,30 +36,58 @@
</a> </a>
{/if} {/if}
<h2 {if="$post->title != null"}title="{$post->title|strip_tags}"{/if}> <h2 {if="$post->title != null"}title="{$post->title|strip_tags}"{/if}>
<a {if="$public"}
{if="$post->isMicroblog()"}
href="{$c->route('blog', array($post->origin, $post->nodeid))}"
{else}
href="{$c->route('node', array($post->origin, $post->node, $post->nodeid))}"
{/if}
{else}
href="{$c->route('news', $post->nodeid)}"
{/if}
>
{if="$post->title != null"} {if="$post->title != null"}
{$post->title} {$post->title}
{else} {else}
{$c->__('post.default_title')} {$c->__('post.default_title')}
{/if} {/if}
</a>
</h2> </h2>
<p> <p>
{if="$contact->getTrueName() != ''"} {if="$contact->getTrueName() != ''"}
{if="!$public"}
<a href="{$c->route('contact', $contact->jid)}"> <a href="{$c->route('contact', $contact->jid)}">
{/if}
<i class="zmdi zmdi-account"></i> {$contact->getTrueName()} <i class="zmdi zmdi-account"></i> {$contact->getTrueName()}
</a> {if="!$public"}</a>{/if}
{/if} {/if}
{if="$post->node != 'urn:xmpp:microblog:0'"} {if="$post->node != 'urn:xmpp:microblog:0'"}
{$post->origin} / {$post->origin} /
{if="!$public"}
<a href="{$c->route('group', array($post->origin, $post->node))}"> <a href="{$c->route('group', array($post->origin, $post->node))}">
{/if}
<i class="zmdi zmdi-pages"></i> {$post->node} <i class="zmdi zmdi-pages"></i> {$post->node}
</a> {if="!$public"}</a>{/if}
{/if} {/if}
{$post->published|strtotime|prepareDate} {$post->published|strtotime|prepareDate}
{if="$post->published != $post->updated"}
- <i class="zmdi zmdi-edit"></i> {$post->updated|strtotime|prepareDate}
{/if}
</p> </p>
</li> </li>
</ul> </ul>
</header> </header>
{if="$public && !$post->isPublic()"}
<ul class="thick">
<li>
<span class="icon color gray bubble">
<i class="zmdi zmdi-lock"></i>
</span>
<p class="center"> {$c->__('blog.private')} - <a href="{$c->route('main')}">{$c->__('page.login')}</a></p>
</li>
</ul>
<br />
{else}
<section> <section>
<content> <content>
{if="$post->isShort() && isset($attachements.pictures)"} {if="$post->isShort() && isset($attachements.pictures)"}
@ -66,12 +96,29 @@
<img class="big_picture" type="{$value.type}" src="{$value.href|urldecode}"/> <img class="big_picture" type="{$value.type}" src="{$value.href|urldecode}"/>
</a> </a>
{/loop} {/loop}
{elseif="$post->getYoutube()"}
<div class="video_embed">
<iframe src="https://www.youtube.com/embed/{$post->getYoutube()}" frameborder="0" allowfullscreen></iframe>
</div>
{/if} {/if}
{$post->contentcleaned} {$post->contentcleaned}
</content> </content>
</section> </section>
<footer> <footer>
{$tags = $post->getTags()}
{if="isset($tags)"}
<ul class="middle">
<li>
<span class="icon zmdi zmdi-tag gray"></span>
<span>
{loop="$tags"}
<a target="_blank" href="{$c->route('tag', array($value))}">#{$value}</a>
{/loop}
</span>
</li>
</ul>
{/if}
<ul class="middle divided spaced"> <ul class="middle divided spaced">
{if="isset($attachements.links)"} {if="isset($attachements.links)"}
{loop="$attachements.links"} {loop="$attachements.links"}
@ -118,7 +165,7 @@
{/loop} {/loop}
</ul> </ul>
{/if} {/if}
{if="$post->isMine()"} {if="$post->isMine() && !$public"}
<ul class="middle"> <ul class="middle">
<li class="action"> <li class="action">
<form> <form>
@ -131,7 +178,12 @@
{if="$post->privacy"} {if="$post->privacy"}
checked checked
{/if} {/if}
onclick="Post_ajaxTogglePrivacy('{$post->nodeid}')"> {if="$external"}
onclick="Group_ajaxTogglePrivacy('{$post->nodeid}')"
{else}
onclick="Post_ajaxTogglePrivacy('{$post->nodeid}')"
{/if}
>
<label for="privacy"></label> <label for="privacy"></label>
</div> </div>
</div> </div>
@ -174,5 +226,43 @@
</a> </a>
{/if} {/if}
{if="$external"}
{$comments = $c->getComments($post)}
{if="$comments"}
<ul class="spaced middle">
<li class="subheader">
{$c->__('post.comments')}
<span class="info">{$comments|count}</span>
</li>
{loop="$comments"}
<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->getContact()->jid|stringToColor}">
<i class="zmdi zmdi-account"></i>
</span>
{/if}
<span class="info">{$value->published|strtotime|prepareDate}</span>
<span>
{$value->getContact()->getTrueName()}
</span>
<p class="all">
{if="$value->title"}
{$value->title}
{else}
{$value->contentraw}
{/if}
</p>
</li>
{/loop}
</ul><br />
{/if}
{else}
<div id="comments"></div> <div id="comments"></div>
{/if}
{/if}
</article> </article>

View file

@ -29,7 +29,11 @@
</a> </a>
</span> </span>
<p class="all"> <p class="all">
{if="$value->contentraw"}
{$value->contentraw} {$value->contentraw}
{else}
{$value->title}
{/if}
</p> </p>
</li> </li>
{/loop} {/loop}

View file

@ -3,6 +3,7 @@
<ul class="flex card shadow active"> <ul class="flex card shadow active">
{loop="$posts"} {loop="$posts"}
{if="!filter_var($value->origin, FILTER_VALIDATE_EMAIL)"} {if="!filter_var($value->origin, FILTER_VALIDATE_EMAIL)"}
{$attachements = $value->getAttachements()}
<li <li
class="block condensed" class="block condensed"
data-id="{$value->nodeid}" data-id="{$value->nodeid}"

View file

@ -67,20 +67,20 @@ class Publish extends WidgetBase
{ {
if(!$this->validateServerNode($server, $node)) return; if(!$this->validateServerNode($server, $node)) return;
$item = false; $post = false;
if($id) { if($id) {
$pd = new \modl\PostnDAO(); $pd = new \modl\PostnDAO();
$p = $pd->getItem($id); $p = $pd->getItem($id);
if($p->isEditable()) { if($p->isEditable()) {
$item = $p; $post = $p;
} }
} }
$view = $this->tpl(); $view = $this->tpl();
$view->assign('to', $server); $view->assign('to', $server);
$view->assign('node', $node); $view->assign('node', $node);
$view->assign('item', $item); $view->assign('item', $post);
RPC::call('MovimTpl.fill', 'main section > div:nth-child(2)', $view->draw('_publish_create', true)); RPC::call('MovimTpl.fill', 'main section > div:nth-child(2)', $view->draw('_publish_create', true));
@ -90,6 +90,7 @@ class Publish extends WidgetBase
$view = $this->tpl(); $view = $this->tpl();
$view->assign('server', $server); $view->assign('server', $server);
$view->assign('node', $node); $view->assign('node', $node);
$view->assign('post', $post);
$view->assign('item', $item); $view->assign('item', $item);
Header::fill($view->draw('_publish_header', true)); Header::fill($view->draw('_publish_header', true));
@ -160,7 +161,7 @@ class Publish extends WidgetBase
$p = new PostPublish; $p = new PostPublish;
$p->setFrom($this->user->getLogin()) $p->setFrom($this->user->getLogin())
->setTo($form->to->value) ->setTo($form->to->value)
->setTitle($form->title->value) ->setTitle(htmlspecialchars($form->title->value))
->setNode($form->node->value); ->setNode($form->node->value);
//->setLocation($geo) //->setLocation($geo)
//->enableComments() //->enableComments()
@ -179,6 +180,26 @@ class Publish extends WidgetBase
if($form->id->value != '') { if($form->id->value != '') {
$p->setId($form->id->value); $p->setId($form->id->value);
$pd = new \modl\PostnDAO();
$post = $pd->getItem($form->id->value);
if(isset($post)) {
$p->setPublished(strtotime($post->published));
}
}
if(Validator::stringType()->notEmpty()->alnum(',')->validate($form->tags->value)) {
$p->setTags(array_unique(
array_filter(
array_map(
function($value) {
return trim(strtolower($value));
},
explode(',', $form->tags->value)
)
)
));
} }
if($form->embed->value != '' && filter_var($form->embed->value, FILTER_VALIDATE_URL)) { if($form->embed->value != '' && filter_var($form->embed->value, FILTER_VALIDATE_URL)) {
@ -186,10 +207,12 @@ class Publish extends WidgetBase
$embed = Embed\Embed::create($form->embed->value); $embed = Embed\Embed::create($form->embed->value);
$p->setLink($form->embed->value); $p->setLink($form->embed->value);
if($embed->type == 'photo') { if(in_array($embed->type, array('photo', 'rich'))) {
$key = key($embed->images); $key = key($embed->images);
$p->setImage($embed->images[0]['value'], $embed->title, $embed->images[0]['mime']); $p->setImage($embed->images[0]['value'], $embed->title, $embed->images[0]['mime']);
} else { }
if($embed->type !== 'photo') {
$content_xhtml .= $this->prepareEmbed($embed); $content_xhtml .= $this->prepareEmbed($embed);
} }
} catch(Exception $e) { } catch(Exception $e) {
@ -198,11 +221,11 @@ class Publish extends WidgetBase
} }
if($content != '') { if($content != '') {
$p->setContent($content); $p->setContent(htmlspecialchars($content));
} }
if($content_xhtml != '') { if($content_xhtml != '') {
$p->setContentXhtml(rawurldecode($content_xhtml)); $p->setContentXhtml($content_xhtml);
} }
$p->request(); $p->request();
@ -225,12 +248,15 @@ class Publish extends WidgetBase
$embed = Embed\Embed::create($url); $embed = Embed\Embed::create($url);
$html = $this->prepareEmbed($embed); $html = $this->prepareEmbed($embed);
if($embed->type == 'photo') {
RPC::call('movim_fill', 'gallery', $this->prepareGallery($embed));
RPC::call('movim_fill', 'preview', ''); RPC::call('movim_fill', 'preview', '');
} else {
RPC::call('movim_fill', 'preview', $html);
RPC::call('movim_fill', 'gallery', ''); RPC::call('movim_fill', 'gallery', '');
if(in_array($embed->type, array('photo', 'rich'))) {
RPC::call('movim_fill', 'gallery', $this->prepareGallery($embed));
}
if($embed->type !== 'photo') {
RPC::call('movim_fill', 'preview', $html);
} }
} catch(Exception $e) { } catch(Exception $e) {
error_log($e->getMessage()); error_log($e->getMessage());
@ -253,8 +279,8 @@ class Publish extends WidgetBase
private function validateServerNode($server, $node) private function validateServerNode($server, $node)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 40); $validate_server = Validator::stringType()->noWhitespace()->length(6, 40);
$validate_node = Validator::string()->length(3, 100); $validate_node = Validator::stringType()->length(3, 100);
if(!$validate_server->validate($server) if(!$validate_server->validate($server)
|| !$validate_node->validate($node) || !$validate_node->validate($node)

View file

@ -48,4 +48,18 @@
</li> </li>
{/if} {/if}
</ul> </ul>
<div>
{if="$item != false"}
{$tags = $item->getTagsImploded()}
{/if}
<input
type="text"
name="tags"
placeholder="write, comma separated, tags"
{if="isset($tags)"}
value="{$tags}"
{/if}>
<label for="title">{$c->__('post.tags')}</label>
</div>
</form> </form>

View file

@ -1,12 +1,12 @@
<div class="quote" cite="{$embed->url}"> <div class="quote" cite="{$embed->url|htmlspecialchars}">
<ul> <ul>
<li> <li>
<span> <span>
<a href="{$embed->url|htmlspecialchars}" target="_blank">{$embed->title}</a> <a href="{$embed->url|htmlspecialchars}" target="_blank">{$embed->title|htmlspecialchars}</a>
</span> </span>
<p>{$embed->description}</p> <p>{$embed->description|htmlspecialchars}</p>
<p> <p>
<a href="{$embed->providerUrl|htmlspecialchars}" target="_blank">{$embed->providerName}</a> <a href="{$embed->providerUrl|htmlspecialchars}" target="_blank">{$embed->providerName|htmlspecialchars}</a>
</p> </p>
</li> </li>
{if="$embed->images != null"} {if="$embed->images != null"}

View file

@ -6,7 +6,7 @@
<div class="return active r3 condensed" <div class="return active r3 condensed"
onclick="Publish.headerBack('{$server}', '{$node}', false)"> onclick="Publish.headerBack('{$server}', '{$node}', false)">
<span id="back" class="icon" ><i class="zmdi zmdi-arrow-back"></i></span> <span id="back" class="icon" ><i class="zmdi zmdi-arrow-back"></i></span>
{if="$item != false"} {if="$post != false"}
<h2>{$c->__('publish.edit')}</h2> <h2>{$c->__('publish.edit')}</h2>
{else} {else}
<h2>{$c->__('publish.new')}</h2> <h2>{$c->__('publish.new')}</h2>

View file

@ -203,9 +203,9 @@ class Rooms extends WidgetBase
array_push($arr, array_push($arr,
array( array(
'type' => 'conference', 'type' => 'conference',
'name' => htmlentities($c->name), 'name' => $c->name,
'autojoin' => $c->autojoin, 'autojoin' => $c->autojoin,
'nick' => htmlentities($c->nick), 'nick' => $c->nick,
'jid' => $c->conference)); 'jid' => $c->conference));
} }
@ -272,7 +272,7 @@ class Rooms extends WidgetBase
*/ */
private function validateRoom($room) private function validateRoom($room)
{ {
$validate_server = Validator::string()->noWhitespace()->length(6, 80); $validate_server = Validator::stringType()->noWhitespace()->length(6, 80);
if(!$validate_server->validate($room)) return false; if(!$validate_server->validate($room)) return false;
else return true; else return true;
} }
@ -284,7 +284,7 @@ class Rooms extends WidgetBase
*/ */
private function validateResource($resource) private function validateResource($resource)
{ {
$validate_resource = Validator::string()->length(2, 40); $validate_resource = Validator::stringType()->length(2, 40);
if(!$validate_resource->validate($resource)) return false; if(!$validate_resource->validate($resource)) return false;
else return true; else return true;
} }

View file

@ -144,9 +144,9 @@ class Vcard4 extends WidgetBase
$c->date = $vcard->date->value; $c->date = $vcard->date->value;
} }
if(Validator::string()->length(0, 40)->validate($vcard->name->value)) if(Validator::stringType()->length(0, 40)->validate($vcard->name->value))
$c->name = $vcard->name->value; $c->name = $vcard->name->value;
if(Validator::string()->length(0, 40)->validate($vcard->fn->value)) if(Validator::stringType()->length(0, 40)->validate($vcard->fn->value))
$c->fn = $vcard->fn->value; $c->fn = $vcard->fn->value;
if(Validator::url()->validate($vcard->url->value)) if(Validator::url()->validate($vcard->url->value))
@ -167,7 +167,7 @@ class Vcard4 extends WidgetBase
$c->skype = $vcard->skype->value; $c->skype = $vcard->skype->value;
$c->yahoo = $vcard->yahoo->value; $c->yahoo = $vcard->yahoo->value;
if(Validator::string()->validate($vcard->desc->value)) if(Validator::stringType()->validate($vcard->desc->value))
$c->description = trim($vcard->desc->value); $c->description = trim($vcard->desc->value);
$cd = new \Modl\ContactDAO(); $cd = new \Modl\ContactDAO();

View file

@ -316,6 +316,7 @@ class Bootstrap {
Modl\Utils::loadModel('Message'); Modl\Utils::loadModel('Message');
Modl\Utils::loadModel('Sessionx'); Modl\Utils::loadModel('Sessionx');
Modl\Utils::loadModel('Conference'); Modl\Utils::loadModel('Conference');
Modl\Utils::loadModel('Tag');
if(file_exists(DOCUMENT_ROOT.'/config/db.inc.php')) { if(file_exists(DOCUMENT_ROOT.'/config/db.inc.php')) {
require DOCUMENT_ROOT.'/config/db.inc.php'; require DOCUMENT_ROOT.'/config/db.inc.php';

View file

@ -12,7 +12,7 @@
"michelf/php-markdown": "1.4.*@dev", "michelf/php-markdown": "1.4.*@dev",
"movim/modl": "dev-master", "movim/modl": "dev-master",
"movim/sasl2": "dev-master", "movim/sasl2": "dev-master",
"movim/moxl": "dev-ws", "movim/moxl": "dev-master",
"embed/embed": "dev-master", "embed/embed": "dev-master",
"heyupdate/emoji": "0.2.*@dev", "heyupdate/emoji": "0.2.*@dev",
@ -22,7 +22,7 @@
"react/socket-client": "0.4.3", "react/socket-client": "0.4.3",
"forxer/Gravatar": "~1.2", "forxer/Gravatar": "~1.2",
"respect/validation": "0.8.*", "respect/validation": "1.0.*",
"ezyang/htmlpurifier": "^4.7" "ezyang/htmlpurifier": "^4.7"
} }
} }

View file

@ -281,7 +281,7 @@ class XMPPtoForm{
$opt->setAttribute('value', $option->value); $opt->setAttribute('value', $option->value);
if( if(
in_array( in_array(
(string)$opt->nodeValue, (string)$option->value,
array_map( array_map(
function($sxml) { function($sxml) {
return (string)$sxml; return (string)$sxml;
@ -297,8 +297,9 @@ class XMPPtoForm{
} }
else{ else{
foreach($s->value as $option){ foreach($s->value as $option){
$label = $option['label'];
$option = $this->html->createElement('option', $option); $option = $this->html->createElement('option', $option);
$option->setAttribute('value', $option['label']); $option->setAttribute('value', $label);
$option->setAttribute('selected', 'selected'); $option->setAttribute('selected', 'selected');
$select->appendChild($option); $select->appendChild($option);
} }

View file

@ -6,6 +6,8 @@ require_once(DOCUMENT_ROOT.'/bootstrap.php');
gc_enable(); gc_enable();
//memprof_enable();
$bootstrap = new Bootstrap(); $bootstrap = new Bootstrap();
$booted = $bootstrap->boot(); $booted = $bootstrap->boot();
@ -99,6 +101,7 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
$stdin->on('data', $stdin_behaviour); $stdin->on('data', $stdin_behaviour);
// We define a huge buffer to prevent issues with SSL streams, see https://bugs.php.net/bug.php?id=65137 // We define a huge buffer to prevent issues with SSL streams, see https://bugs.php.net/bug.php?id=65137
$conn->bufferSize = 1024*32;
$conn->on('data', function($message) use (&$conn, $loop, $parser) { $conn->on('data', function($message) use (&$conn, $loop, $parser) {
if(!empty($message)) { if(!empty($message)) {
$restart = false; $restart = false;
@ -136,14 +139,10 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
\Moxl\API::clear(); \Moxl\API::clear();
\RPC::clear(); \RPC::clear();
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." before : ".\sizeToCleanSize(memory_get_usage())."\n");
if(!$parser->parse($message)) { if(!$parser->parse($message)) {
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." ".$parser->getError()."\n"); fwrite(STDERR, colorize(getenv('sid'), 'yellow')." ".$parser->getError()."\n");
} }
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." after : ".\sizeToCleanSize(memory_get_usage())."\n");
if($restart) { if($restart) {
$session = \Sessionx::start(); $session = \Sessionx::start();
\Moxl\Stanza\Stream::init($session->host); \Moxl\Stanza\Stream::init($session->host);
@ -170,7 +169,11 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
\Moxl\API::clear(); \Moxl\API::clear();
$loop->tick();
gc_collect_cycles(); gc_collect_cycles();
//fwrite(STDERR, colorize(getenv('sid'), 'yellow')." end data : ".\sizeToCleanSize(memory_get_usage())."\n");
//memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));
} }
}); });
@ -188,6 +191,8 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
$obj = new \StdClass; $obj = new \StdClass;
$obj->func = 'registered'; $obj->func = 'registered';
fwrite(STDERR, 'registered');
//fwrite(STDERR, colorize(json_encode($obj).' '.strlen($obj), 'yellow')." : ".colorize('obj sent to browser', 'green')."\n"); //fwrite(STDERR, colorize(json_encode($obj).' '.strlen($obj), 'yellow')." : ".colorize('obj sent to browser', 'green')."\n");
echo base64_encode(gzcompress(json_encode($obj), 9)).""; echo base64_encode(gzcompress(json_encode($obj), 9))."";

View file

@ -31,6 +31,7 @@ visio = Visio-conference
pods = Pods pods = Pods
share = Share share = Share
room = Room room = Room
tag = Tag
[error] [error]
error = Error: %s error = Error: %s

View file

@ -10,10 +10,12 @@ class Core implements MessageComponentInterface {
public $loop; public $loop;
public $baseuri; public $baseuri;
private $cleanerdelay = 60; // in minutes private $cleanerdelay = 2; // in hours
public function __construct($loop, $baseuri, $port) public function __construct($loop, $baseuri, $port)
{ {
$baseuri = rtrim($baseuri, '/') . '/';
echo colorize("Movim daemon launched\n", 'green'); echo colorize("Movim daemon launched\n", 'green');
echo colorize("Base URI :", 'green')." {$baseuri}\n"; echo colorize("Base URI :", 'green')." {$baseuri}\n";
$ws = $this->setWebsocket($baseuri, $port); $ws = $this->setWebsocket($baseuri, $port);
@ -110,7 +112,9 @@ class Core implements MessageComponentInterface {
{ {
$this->loop->addPeriodicTimer(5, function() { $this->loop->addPeriodicTimer(5, function() {
foreach($this->sessions as $sid => $session) { foreach($this->sessions as $sid => $session) {
if(time()-$session->timestamp > $this->cleanerdelay*60) { if((time()-$session->timestamp > $this->cleanerdelay*3600)
|| ($session->countClients() == 0
&& $session->registered == null)) {
$session->killLinker(); $session->killLinker();
$this->closeEmptySession($sid); $this->closeEmptySession($sid);
} }
@ -122,7 +126,7 @@ class Core implements MessageComponentInterface {
{ {
// No WebSockets and no linker ? We close the whole session // No WebSockets and no linker ? We close the whole session
if($this->sessions[$sid]->countClients() == 0 if($this->sessions[$sid]->countClients() == 0
&& $this->sessions[$sid]->process == null) { && ($this->sessions[$sid]->process == null)) {
$sd = new \Modl\SessionxDAO(); $sd = new \Modl\SessionxDAO();
$sd->delete($sid); $sd->delete($sid);

View file

@ -10,6 +10,8 @@ class Session {
protected $baseuri; protected $baseuri;
public $process; public $process;
public $registered;
protected $buffer; protected $buffer;
public function __construct($loop, $sid, $baseuri) public function __construct($loop, $sid, $baseuri)
@ -77,9 +79,15 @@ class Session {
$sd->delete($this->sid); $sd->delete($this->sid);
}); });
$self = $this;
// Debug only, if the linker output some errors // Debug only, if the linker output some errors
$this->process->stderr->on('data', function($output) use ($me) { $this->process->stderr->on('data', function($output) use ($me, $self) {
if(strpos($output, 'registered') !== false) {
$self->registered = true;
} else {
echo $output; echo $output;
}
}); });
} }

View file

@ -81,7 +81,13 @@ class Locale {
&& array_key_exists($arr[1], $this->hash[$arr[0]])) { && array_key_exists($arr[1], $this->hash[$arr[0]])) {
$skey = $this->hash[$arr[0]][$arr[1]]; $skey = $this->hash[$arr[0]][$arr[1]];
if(is_array($this->translations) if($this->language == 'en') {
if(is_string($skey)) {
$string = $skey;
} else {
$string = $skey[0];
}
} elseif(is_array($this->translations)
&& array_key_exists($skey, $this->translations) && array_key_exists($skey, $this->translations)
&& isset($this->translations[$skey])) { && isset($this->translations[$skey])) {
$string = $this->translations[$skey]; $string = $this->translations[$skey];

View file

@ -10,12 +10,13 @@ class Route extends \BaseController {
'accountnext' => array('s', 'err'), 'accountnext' => array('s', 'err'),
'admin' => false, 'admin' => false,
'blog' => array('f', 'i'), 'blog' => array('f', 'i'),
'tag' => array('t', 'i'),
'chat' => array('f'), 'chat' => array('f'),
'conf' => false, 'conf' => false,
'contact' => array('f'), 'contact' => array('f'),
'disconnect' => array('err'), 'disconnect' => array('err'),
'feed' => array('s', 'n'), 'feed' => array('s', 'n'),
'grouppublic' => array('s', 'n', 'i'), 'node' => array('s', 'n', 'i'),
'group' => array('s', 'n', 'i'), 'group' => array('s', 'n', 'i'),
'help' => false, 'help' => false,
'infos' => false, 'infos' => false,
@ -34,7 +35,8 @@ class Route extends \BaseController {
public function find() { public function find() {
$this->fix($_GET, $_SERVER['QUERY_STRING']); $this->fix($_GET, $_SERVER['QUERY_STRING']);
$uri = reset(array_keys($_GET)); $gets = array_keys($_GET);
$uri = reset($gets);
unset($_GET[$uri]); unset($_GET[$uri]);
$request = explode('/', $uri); $request = explode('/', $uri);

View file

@ -15,8 +15,6 @@
* See COPYING for licensing information. * See COPYING for licensing information.
*/ */
class User { class User {
private $xmppSession;
public $username = ''; public $username = '';
private $password = ''; private $password = '';
private $config = array(); private $config = array();
@ -32,12 +30,18 @@ class User {
* Class constructor. Reloads the user's session or attempts to authenticate * Class constructor. Reloads the user's session or attempts to authenticate
* the user. * the user.
*/ */
function __construct() function __construct($username = false)
{ {
$session = \Sessionx::start(); if($username) {
if($session->active) { $this->username = $username;
$this->username = $session->user.'@'.$session->host; }
$session = \Sessionx::start();
if($session->active && $this->username == null) {
$this->username = $session->user.'@'.$session->host;
}
if($this->username != null) {
$this->userdir = DOCUMENT_ROOT.'/users/'.$this->username.'/'; $this->userdir = DOCUMENT_ROOT.'/users/'.$this->username.'/';
$this->useruri = BASE_URI.'users/'.$this->username.'/'; $this->useruri = BASE_URI.'users/'.$this->username.'/';
} }
@ -157,6 +161,9 @@ class User {
{ {
$session = \Sessionx::start(); $session = \Sessionx::start();
$session->config = $config; $session->config = $config;
file_put_contents($this->userdir.'config.dump', serialize($config));
$this->reload(); $this->reload();
} }
@ -168,6 +175,16 @@ class User {
return $this->config[$key]; return $this->config[$key];
} }
function getDumpedConfig($key = false)
{
$config = unserialize(file_get_contents($this->userdir.'config.dump'));
if($key == false)
return $config;
if(isset($config[$key]))
return $config[$key];
}
function isSupported($key) function isSupported($key)
{ {
$this->reload(); $this->reload();

View file

@ -636,11 +636,9 @@ function requestURL($url, $timeout = 10, $post = false) {
/* /*
* @desc Get the URI of a smiley * @desc Get the URI of a smiley
*/ */
function getSmileyPath($id, $large = true) function getSmileyPath($id)
{ {
$folder = ''; return BASE_URI.'/themes/material/img/emojis/svg/'.$id.'.svg';
if($large) $folder = 'large/';
return BASE_URI.'/themes/material/img/emojis/'.$folder.$id.'.png';
} }
/* /*

View file

@ -2,15 +2,22 @@
function createEmailPic($jid, $email) { function createEmailPic($jid, $email) {
if(file_exists(DOCUMENT_ROOT.'/cache/'.$jid.'_email.jpg')) $cachefile = DOCUMENT_ROOT.'/cache/'.$jid.'_email.png';
unlink(DOCUMENT_ROOT.'/cache/'.$jid.'_email.jpg');
$thumb = imagecreatetruecolor(250, 20); if(file_exists(DOCUMENT_ROOT.'/cache/'.$jid.'_email.png'))
$white = imagecolorallocate($thumb, 255, 255, 255); unlink(DOCUMENT_ROOT.'/cache/'.$jid.'_email.png');
imagefill($thumb, 0, 0, $white);
$text_color = imagecolorallocate ($thumb, 0, 0,0);//black text $draw = new ImagickDraw();
imagestring ($thumb, 4, 0, 0, $email, $text_color); $draw->setFontSize(13);
$draw->setGravity(Imagick::GRAVITY_CENTER);
imagejpeg($thumb, DOCUMENT_ROOT.'/cache/'.$jid.'_email.jpg', 95); $canvas = new Imagick();
$metrics = $canvas->queryFontMetrics($draw, $email);
$canvas->newImage($metrics['textWidth'], $metrics['textHeight'], "transparent", "png");
$canvas->annotateImage($draw, 0, 0, 0, $email);
$canvas->setImageFormat('PNG');
$canvas->writeImage($cachefile);
} }

View file

@ -39,7 +39,7 @@ class AjaxController extends BaseController
} }
$buffer = '<script type="text/javascript">'; $buffer = '<script type="text/javascript">';
foreach($this->funclist as $funcdef) { foreach($this->funclist as $key => $funcdef) {
$parlist = implode(', ', $funcdef['params']); $parlist = implode(', ', $funcdef['params']);
$buffer .= "function " . $funcdef['object'] . '_' $buffer .= "function " . $funcdef['object'] . '_'
@ -54,7 +54,7 @@ class AjaxController extends BaseController
*/ */
public function defun($widget, $funcname, array $params) public function defun($widget, $funcname, array $params)
{ {
$this->funclist[] = array( $this->funclist[$widget.$funcname] = array(
'object' => $widget, 'object' => $widget,
'funcname' => $funcname, 'funcname' => $funcname,
'params' => $params, 'params' => $params,

View file

@ -30,7 +30,7 @@ class FrontController extends BaseController
else { else {
$log = new Logger('movim'); $log = new Logger('movim');
$log->pushHandler(new SyslogHandler('movim')); $log->pushHandler(new SyslogHandler('movim'));
$log->addError(t("Requested controller '%s' doesn't exist.", $class_name)); $log->addError(__("Requested controller '%s' doesn't exist.", $class_name));
exit; exit;
} }

View file

@ -99,9 +99,97 @@ class TplPageBuilder
*/ */
function title() function title()
{ {
$widgets = WidgetWrapper::getInstance();
if(isset($widgets->title)) {
$this->title .= ' - ' . $widgets->title;
}
echo $this->title; echo $this->title;
} }
/**
* Display some meta tag defined in the widgets using Facebook OpenGraph
*/
function meta()
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$metas = $dom->createElement('xml');
$dom->appendChild($metas);
$widgets = WidgetWrapper::getInstance();
if(isset($widgets->title)) {
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'og:title');
$meta->setAttribute('content', $widgets->title);
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('name', 'twitter:title');
$meta->setAttribute('content', $widgets->title);
$metas->appendChild($meta);
}
if(isset($widgets->image)) {
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'og:image');
$meta->setAttribute('content', $widgets->image);
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('name', 'twitter:image');
$meta->setAttribute('content', $widgets->image);
$metas->appendChild($meta);
}
if(isset($widgets->description)) {
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'og:description');
$meta->setAttribute('content', $widgets->description);
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('name', 'twitter:description');
$meta->setAttribute('content', $widgets->description);
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('name', 'description');
$meta->setAttribute('content', $widgets->description);
$metas->appendChild($meta);
} else {
$cd = new \Modl\ConfigDAO();
$config = $cd->get();
$meta = $dom->createElement('meta');
$meta->setAttribute('name', 'description');
$meta->setAttribute('content', $config->description);
$metas->appendChild($meta);
}
if(isset($widgets->url)) {
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'og:url');
$meta->setAttribute('content', $widgets->url);
$metas->appendChild($meta);
}
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'og:type');
$meta->setAttribute('content', 'article');
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'twitter:card');
$meta->setAttribute('content', 'summary_large_image');
$metas->appendChild($meta);
$meta = $dom->createElement('meta');
$meta->setAttribute('property', 'twitter:site');
$meta->setAttribute('content', 'MovimNetwork');
$metas->appendChild($meta);
echo strip_tags($dom->saveXML($dom->documentElement), '<meta>');
}
function addScript($script) function addScript($script)
{ {
$this->scripts[] = BASE_URI . 'app/assets/js/' . $script; $this->scripts[] = BASE_URI . 'app/assets/js/' . $script;
@ -168,9 +256,4 @@ class TplPageBuilder
echo $widgets->runWidget($name, 'build'); echo $widgets->runWidget($name, 'build');
} }
function displayFooterDebug()
{
//\system\Logs\Logger::displayFooterDebug();
}
} }

View file

@ -22,6 +22,7 @@ class WidgetBase
{ {
protected $js = array(); /*< Contains javascripts. */ protected $js = array(); /*< Contains javascripts. */
protected $css = array(); /*< Contains CSS files. */ protected $css = array(); /*< Contains CSS files. */
protected $rawcss = array(); /*< Contains raw CSS files links. */
protected $ajax; /*< Contains ajax client code. */ protected $ajax; /*< Contains ajax client code. */
protected $user; protected $user;
protected $name; protected $name;
@ -31,6 +32,11 @@ class WidgetBase
public $events; public $events;
public $filters; public $filters;
// Meta tags
public $title;
public $image;
public $description;
/** /**
* Initialises Widget stuff. * Initialises Widget stuff.
*/ */
@ -38,6 +44,8 @@ class WidgetBase
{ {
if($view != null) $this->_view = $view; if($view != null) $this->_view = $view;
$this->user = new User;
$this->load(); $this->load();
$this->name = get_class($this); $this->name = get_class($this);
@ -48,10 +56,8 @@ class WidgetBase
// Put default widget init here. // Put default widget init here.
$this->ajax = AjaxController::getInstance(); $this->ajax = AjaxController::getInstance();
$this->user = new User;
// Generating Ajax calls. // Generating Ajax calls.
$refl = new ReflectionClass(get_class($this)); $refl = new ReflectionClass($this->name);
$meths = $refl->getMethods(); $meths = $refl->getMethods();
foreach($meths as $method) { foreach($meths as $method) {
@ -62,7 +68,7 @@ class WidgetBase
$params[] = $param->name; $params[] = $param->name;
} }
$this->ajax->defun(get_class($this), $method->name, $params); $this->ajax->defun($this->name, $method->name, $params);
} }
} }
@ -84,7 +90,9 @@ class WidgetBase
function __destruct() function __destruct()
{ {
unset($this->view); unset($this->view);
unset($this->ajax);
unset($this->user); unset($this->user);
unset($this->_view);
} }
function __() function __()
@ -238,19 +246,27 @@ class WidgetBase
} }
/** /**
* @brief Adds a javascript file to this widget. * @brief Adds a CSS file to this widget.
*/ */
protected function addcss($filename) protected function addcss($filename)
{ {
$this->css[] = $this->respath($filename); $this->css[] = $this->respath($filename);
} }
/**
* @brief Adds a CSS to the page.
*/
protected function addrawcss($url)
{
$this->rawcss[] = $url;
}
/** /**
* @brief returns the list of javascript files to be loaded for the widget. * @brief returns the list of javascript files to be loaded for the widget.
*/ */
public function loadcss() public function loadcss()
{ {
return $this->css; return array_merge($this->css, $this->rawcss);
} }
/* /*

View file

@ -32,6 +32,11 @@ class WidgetWrapper
private $css = array(); // All the css loaded by the widgets so far. private $css = array(); // All the css loaded by the widgets so far.
private $js = array(); // All the js loaded by the widgets so far. private $js = array(); // All the js loaded by the widgets so far.
public $title = null; // If a widget has defined a particular title
public $image = null; // If a widget has defined a particular image
public $description = null; // If a widget has defined a particular description
public $url = null; // If a widget has defined a particular url
private function __construct() private function __construct()
{ {
} }
@ -107,7 +112,6 @@ class WidgetWrapper
} }
} }
} }
unset($widget);
} else { } else {
if($this->_view != '') { if($this->_view != '') {
$widget = new $name(false, $this->_view); $widget = new $name(false, $this->_view);
@ -118,6 +122,11 @@ class WidgetWrapper
$this->css = array_merge($this->css, $widget->loadcss()); $this->css = array_merge($this->css, $widget->loadcss());
$this->js = array_merge($this->js, $widget->loadjs()); $this->js = array_merge($this->js, $widget->loadjs());
if(isset($widget->title)) $this->title = $widget->title;
if(isset($widget->image)) $this->image = $widget->image;
if(isset($widget->description)) $this->description = $widget->description;
if(isset($widget->url)) $this->url = $widget->url;
return $widget; return $widget;
} }
} }
@ -140,8 +149,6 @@ class WidgetWrapper
$result = call_user_func_array(array($widget, $method), $params); $result = call_user_func_array(array($widget, $method), $params);
unset($widget, $method, $params);
return $result; return $result;
} }
@ -156,7 +163,7 @@ class WidgetWrapper
{ {
if(array_key_exists($key, $this->_events)) { if(array_key_exists($key, $this->_events)) {
foreach($this->_events[$key] as $widget_name) { foreach($this->_events[$key] as $widget_name) {
$widget = new $widget_name; $widget = new $widget_name(true);
if(array_key_exists($key, $widget->events)) { if(array_key_exists($key, $widget->events)) {
foreach($widget->events[$key] as $method) { foreach($widget->events[$key] as $method) {
/* /*
@ -177,17 +184,13 @@ class WidgetWrapper
$widget->{$method}($data); $widget->{$method}($data);
} }
} }
unset($session, $notifs_key);
} else { } else {
$widget->{$method}($data); $widget->{$method}($data);
} }
} }
} }
unset($widget);
} }
} }
unset($key, $data);
} }
/** /**

View file

@ -142,6 +142,21 @@ article section content img.big_picture {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
article section content div.video_embed {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
margin-bottom: 2rem;
height: 0;
}
article section content div.video_embed iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
article ul li.pic img { article ul li.pic img {
max-width: 30rem; max-width: 30rem;
max-height: 30rem; max-height: 30rem;

View file

@ -28,3 +28,20 @@
font-weight: 800; font-weight: 800;
src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(../fonts/os_800.woff2) format('woff2'), url(../fonts/os_800.woff) format('woff'); src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(../fonts/os_800.woff2) format('woff2'), url(../fonts/os_800.woff) format('woff');
} }
.emoji {
width: 2rem;
height: 2rem;
margin: 0 0.5rem;
margin-bottom: -0.3rem;
}
.emoji.large {
width: 5rem;
height: 5rem;
margin: 0;
}
.hfr {
display: inline-block;
}

View file

@ -6,6 +6,10 @@ form > div:not(.clear):not(.control) {
box-sizing: border-box; box-sizing: border-box;
} }
form > div.compact:not(.clear):not(.control) {
min-height: 0;
}
li > form > div:not(.control) { /* If we put the form in a list */ li > form > div:not(.control) { /* If we put the form in a list */
min-height: 0; min-height: 0;
line-height: 3rem; line-height: 3rem;
@ -60,6 +64,7 @@ form > div > .select:after {
form > div > .select select { form > div > .select select {
width: calc(100% + 3rem); width: calc(100% + 3rem);
background-color: transparent; background-color: transparent;
background-image: none;
} }
main > header form > div:not(.clear):not(.control) { main > header form > div:not(.clear):not(.control) {
@ -106,6 +111,12 @@ form > div > textarea {
box-shadow: none; /* Firefox weird CSS */ box-shadow: none; /* Firefox weird CSS */
} }
form > div.compact > .select,
form > div.compact > input:not([type=submit]),
form > div.compact > textarea {
padding-top: 2.5rem;
}
/* Webkit hack */ /* Webkit hack */
form > div > input:not([type=submit]):-webkit-autofill { form > div > input:not([type=submit]):-webkit-autofill {
-webkit-box-shadow: 0 0 0 50px white inset; -webkit-box-shadow: 0 0 0 50px white inset;
@ -261,6 +272,8 @@ input[type=button] {
transition: background 0.3s ease, box-shadow 0.3s ease; transition: background 0.3s ease, box-shadow 0.3s ease;
box-shadow: 0 0.1rem 0.3rem rgba(0, 0, 0, 0.5); box-shadow: 0 0.1rem 0.3rem rgba(0, 0, 0, 0.5);
background-image: none;
} }
.button:active { .button:active {

View file

@ -1,5 +1,5 @@
/* Grid */ /* Grid */
ul.grid li { ul.grid > li {
background-size: cover; background-size: cover;
width: calc(25% - 0.2em); width: calc(25% - 0.2em);
padding: 0; padding: 0;
@ -12,7 +12,7 @@ ul.grid li {
margin: 0.1em; margin: 0.1em;
} }
ul.grid nav { ul.grid > li > nav {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
color: white; color: white;
@ -26,14 +26,14 @@ ul.grid nav {
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
ul.grid li { ul.grid > li {
width: calc(33.33% - 0.2em); width: calc(33.33% - 0.2em);
padding-bottom: 33.33%; padding-bottom: 33.33%;
} }
} }
@media screen and (max-width: 640px) { @media screen and (max-width: 640px) {
ul.grid li { ul.grid > li {
width: calc(50% - 0.2em); width: calc(50% - 0.2em);
padding-bottom: 50%; padding-bottom: 50%;
} }
@ -44,3 +44,7 @@ ul.grid:after {
display: block; display: block;
clear: both; clear: both;
} }
ul.grid.padded {
padding: 0;
}

File diff suppressed because one or more lines are too long

View file

@ -811,12 +811,10 @@ main section > div:first-child:nth-last-child(2) ~ div .actions.fixed > div:last
.icon.news { background-image: url(../img/icons/receipt.svg); } .icon.news { background-image: url(../img/icons/receipt.svg); }
.icon.forum { background-image: url(../img/icons/forum.svg); } .icon.forum { background-image: url(../img/icons/forum.svg); }
.icon.contacts { background-image: url(../img/icons/group.svg); } .icon.contacts { background-image: url(../img/icons/group.svg); }
.icon.media { background-image: url(../img/placeholder/media.png); } .icon.account { background-image: url(../img/icons/perm_identity.svg); }
.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.pages { background-image: url(../img/icons/pages.svg); }
.icon.clipboard { background-image: url(../img/icons/assignment_turned_in.svg); } .icon.bookmark { background-image: url(../img/icons/bookmark.svg); }
.icon.clipboard { background-image: url(../img/icons/person.svg); }
/* Definition list */ /* Definition list */

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="240"
height="240"
id="svg3063"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="/home/edhelas/Desktop/logo.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192"
sodipodi:docname="vectorial.svg">
<defs
id="defs3065">
<linearGradient
id="linearGradient3920">
<stop
style="stop-color:#344394;stop-opacity:1;"
offset="0"
id="stop3922" />
<stop
style="stop-color:#7c45df;stop-opacity:1;"
offset="1"
id="stop3925" />
</linearGradient>
<linearGradient
id="linearGradient3878">
<stop
style="stop-color:#345cca;stop-opacity:1;"
offset="0"
id="stop3880" />
<stop
style="stop-color:#5d47c6;stop-opacity:1;"
offset="1"
id="stop3882" />
</linearGradient>
<linearGradient
id="linearGradient3798">
<stop
style="stop-color:#ececec;stop-opacity:1;"
offset="0"
id="stop3800" />
<stop
style="stop-color:#dfdfdf;stop-opacity:1;"
offset="1"
id="stop3802" />
</linearGradient>
<linearGradient
id="linearGradient3792">
<stop
id="stop3794"
offset="0"
style="stop-color:#626fb4;stop-opacity:1;" />
<stop
id="stop3796"
offset="0.89999998"
style="stop-color:#3f51b5;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3782">
<stop
style="stop-color:#414661;stop-opacity:1;"
offset="0"
id="stop3784" />
<stop
style="stop-color:#3f51b5;stop-opacity:1;"
offset="0"
id="stop3788" />
</linearGradient>
<linearGradient
id="linearGradient5650">
<stop
id="stop5652"
offset="0"
style="stop-color:#ed871e;stop-opacity:1;" />
<stop
style="stop-color:#e36e15;stop-opacity:1;"
offset="0.9628492"
id="stop5654" />
<stop
id="stop5656"
offset="1"
style="stop-color:#a26221;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient5640">
<stop
style="stop-color:#3f51b5;stop-opacity:1;"
offset="0"
id="stop5642" />
<stop
id="stop5648"
offset="0.9628492"
style="stop-color:#616fba;stop-opacity:1;" />
<stop
style="stop-color:#4e598f;stop-opacity:1;"
offset="1"
id="stop5644" />
</linearGradient>
<linearGradient
id="linearGradient5632">
<stop
style="stop-color:#d25917;stop-opacity:1;"
offset="0"
id="stop5634" />
<stop
style="stop-color:#b5843f;stop-opacity:0;"
offset="1"
id="stop5636" />
</linearGradient>
<linearGradient
id="linearGradient5540">
<stop
style="stop-color:#212121;stop-opacity:1;"
offset="0"
id="stop5542" />
<stop
style="stop-color:#212121;stop-opacity:0;"
offset="1"
id="stop5544" />
</linearGradient>
<linearGradient
id="linearGradient3922">
<stop
style="stop-color:#60b8ac;stop-opacity:1;"
offset="0"
id="stop3924" />
<stop
style="stop-color:#296561;stop-opacity:1;"
offset="1"
id="stop3926" />
</linearGradient>
<linearGradient
id="linearGradient3895">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3897" />
<stop
style="stop-color:#cccccc;stop-opacity:0;"
offset="1"
id="stop3899" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5632"
id="radialGradient5638"
cx="125"
cy="125"
fx="125"
fy="125"
r="115"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3878"
id="linearGradient3884"
x1="20"
y1="20"
x2="220"
y2="220"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3878-5"
id="linearGradient3884-9"
x1="20"
y1="20"
x2="220"
y2="220"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3878-5">
<stop
style="stop-color:#3f51b5;stop-opacity:1;"
offset="0"
id="stop3880-1" />
<stop
style="stop-color:#b871cd;stop-opacity:1;"
offset="1"
id="stop3882-9" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3920"
id="linearGradient3927"
x1="125"
y1="65"
x2="220"
y2="220"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter4029"
x="-0.14247962"
width="1.2849592"
y="-0.24434541"
height="1.4886908">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="10.685972"
id="feGaussianBlur4031" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3878"
id="linearGradient4049"
x1="40"
y1="40"
x2="200"
y2="200"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3920"
id="linearGradient4057"
x1="125"
y1="65"
x2="174.94821"
y2="210.10153"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.4748737"
inkscape:cx="7.6085795"
inkscape:cy="141.43879"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:snap-global="true"
inkscape:window-width="1920"
inkscape:window-height="1013"
inkscape:window-x="1920"
inkscape:window-y="24"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3078"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="5px"
spacingy="5px" />
<sodipodi:guide
orientation="0,1"
position="5,20"
id="guide3836" />
<sodipodi:guide
orientation="1,0"
position="20,70"
id="guide3838" />
<sodipodi:guide
orientation="1,0"
position="220,35"
id="guide3840" />
<sodipodi:guide
orientation="0,1"
position="40,220"
id="guide3842" />
<sodipodi:guide
orientation="1,0"
position="125,195"
id="guide3850" />
<sodipodi:guide
orientation="0,1"
position="100,125"
id="guide3852" />
<sodipodi:guide
orientation="1,0"
position="30,135"
id="guide3870" />
<sodipodi:guide
orientation="0,1"
position="90,210"
id="guide3872" />
<sodipodi:guide
orientation="1,0"
position="210,165"
id="guide3874" />
<sodipodi:guide
orientation="0,1"
position="100,30"
id="guide3876" />
<sodipodi:guide
orientation="1,0"
position="40,135"
id="guide4033" />
<sodipodi:guide
orientation="1,0"
position="200,130"
id="guide4035" />
<sodipodi:guide
orientation="0,1"
position="140,200"
id="guide4037" />
<sodipodi:guide
orientation="0,1"
position="75,40"
id="guide4039" />
</sodipodi:namedview>
<metadata
id="metadata3068">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-812.36218)">
<path
sodipodi:type="arc"
style="fill:url(#linearGradient4049);fill-opacity:1;stroke:url(#linearGradient4057);stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none"
id="path4041"
sodipodi:cx="120"
sodipodi:cy="120"
sodipodi:rx="110"
sodipodi:ry="110"
d="M 230,120 A 110,110 0 0 1 120,230 110,110 0 0 1 10,120 110,110 0 0 1 120,10 110,110 0 0 1 230,120 Z"
transform="translate(0,812.36218)"
inkscape:export-filename="/var/www/0.9/themes/material/img/app/96.png"
inkscape:export-xdpi="38.744396"
inkscape:export-ydpi="38.744396" />
<path
inkscape:connector-curvature="0"
d="m 109.28439,887.55968 c -20.510476,0 -37.137346,16.62694 -37.137346,37.13731 0,1.59397 0.10688,3.17071 0.301709,4.71183 -0.293751,-0.009 -0.586236,-0.0232 -0.882008,-0.0232 C 54.13289,929.38555 40,943.51846 40,960.95225 c 0,17.43385 14.13289,31.56674 31.566745,31.56674 l 122.437085,0 c 14.35725,0 25.99617,-11.63885 25.99617,-25.99613 0,-14.35725 -11.63892,-25.9961 -25.99617,-25.9961 -0.0468,0 -0.093,-2.5e-4 -0.13928,0 0.0334,-0.64832 0.0696,-1.29301 0.0696,-1.94973 0,-20.51035 -16.62699,-37.1373 -37.13737,-37.1373 -5.72422,0 -11.15,1.3077 -15.99222,3.62087 -6.55964,-10.50711 -18.22116,-17.50095 -31.52041,-17.50095 z"
id="path3053-5-3"
style="opacity:0.45895523;fill:#332949;fill-opacity:1;stroke:none;filter:url(#filter4029)"
sodipodi:nodetypes="cscsssssscssccc"
transform="matrix(0.91666667,0,0,0.91666667,3.3333333,73.963304)"
inkscape:export-filename="/var/www/0.9/themes/material/img/app/96.png"
inkscape:export-xdpi="38.744396"
inkscape:export-ydpi="38.744396" />
<path
inkscape:connector-curvature="0"
d="m 101.58613,885.71361 c -18.231539,0 -33.01098,14.77951 -33.01098,33.01094 0,1.41687 0.095,2.81841 0.268187,4.1883 -0.261113,-0.008 -0.521099,-0.0206 -0.784008,-0.0206 C 52.56257,922.89216 40,935.45475 40,950.95145 c 0,15.49676 12.56257,28.05933 28.059329,28.05933 l 108.832971,0 c 12.762,0 23.1077,-10.34565 23.1077,-23.10768 0,-12.762 -10.3457,-23.10764 -23.1077,-23.10764 -0.0416,0 -0.0827,-2.2e-4 -0.1238,0 0.0297,-0.57629 0.0619,-1.14934 0.0619,-1.7331 0,-18.23142 -14.77955,-33.01093 -33.011,-33.01093 -5.08819,0 -9.91111,1.1624 -14.2153,3.21855 -5.83079,-9.33965 -16.19659,-15.5564 -28.01814,-15.5564 z"
id="path3053-5"
style="fill:#ffffff;fill-opacity:1;stroke:none"
sodipodi:nodetypes="cscsssssscssccc"
inkscape:export-filename="/var/www/0.9/themes/material/img/app/96.png"
inkscape:export-xdpi="38.744396"
inkscape:export-ydpi="38.744396" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show more