Merge remote branch 'upstream/master'

This commit is contained in:
habeascodice 2014-10-07 16:13:22 -07:00
commit c01a983957
66 changed files with 649 additions and 7601 deletions

0
.gitmodules vendored
View file

View file

@ -3,73 +3,38 @@
We need much more than this, but here are areas where developers can help. Please edit this page when items are finished. Another place for developers to start is with the issues list.
[li]Documentation - see Red Documentation Project To-Do List[/li]
[li]Include TOS link in registration/verification email[/li]
[li]Finish the anti-spam bayesian engine[/li]
[li]If DAV folders exist, add an option to the Settings page to set a default folder for attachment uploads.[/li]
[li]Integrate the "open site" list with the register page[/li]
[li]implement oembed provider interface[/li]
[li]refactor the oembed client interface so that we can safely sandbox remote content[/li]
[li]implement openid server interface[/li]
[li]Write more webpage layouts[/li]
[li]Write more webpage widgets[/li]
[li](Advanced) create a UI for building Comanche pages[/li]
[li]templatise and translate the Web interface to webDAV[/li]
[li]Extend WebDAV to provide desktop access to photo albums[/li]
[li]External post connectors - create standard interface[/li]
[li]External post connectors, add popular services[/li]
[li]service classes - provide a pluggable subscription payment gateway for premium accounts[/li]
[li]service classes - account overview page showing resources consumed by channel. With special consideration this page can also be accessed at a meta level by the site admin to drill down on problematic accounts/channels.[/li]
[li]Events module - fix permissions on events, and provide JS translation support for the calendar overview; integrate with calDAV[/li]
[li]Events module - event followups and RSVP[/li]
[li]Uploads - integrate #^[url=https://github.com/blueimp/jQuery-File-Upload]https://github.com/blueimp/jQuery-File-Upload[/url][/li]
[li]Import/export - include events, things, etc.[/li]
[li]Import channel from Diaspora/Friendica[/li]
[li]MediaGoblin photo "crosspost" connector[/li]
[li]Create management page/UI for extensible profile fields[/li]
[li]Create interface to include/exclude and re-order standard profile fields[/li]
[li]Provide a mechanism to share page design elements in posts (just like apps)[/li]
[li]App taxonomy[/li]
[li]Customisable App collection pages[/li]
[li]replace the tinymce visual editor and/or make the visual editor pluggable and responsive to different output formats. We probably want library/bbedit for bbcode. This needs a fair bit of work to catch up with our "enhanced bbcode", but start with images, links, bold and highlight and work from there.[/li]
[li]Photos module - turn photos into normal conversations and fix tagging[/li]
[li]Provide RSS feed support which look like channels (in matrix only - copyright issues)[/li]
[li]Create mobile clients for the top platforms - which involves extending the API so that we can do stuff far beyond the current crop of Twitter/Statusnet clients. Ditto for mobile themes. We can probably use something like the Friendica Android app as a base to start from.[/li]
[li]Implement owned and exchangeable "things".[/li]
[li]Family Account creation - using service classes (an account holder can create a certain number of sub-accounts which are all tied to their subscription - if the subscription lapses they all go away).[/li]
[li]Put mod_admin under Comanche[/li]
In many cases some of the work has already been started and code exists so that you needn't start from scratch. Please contact one of the developer channels like Channel One (one@zothub.com) before embarking and we can tell you what we already have and provide some insights on how we envision these features fitting together.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,361 @@
<?php
/**
* RedMatrix - "The Network"
*
* @link http://github.com/friendica/red
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
namespace RedMatrix\RedDAV;
use Sabre\DAV;
/**
* @brief Provides a DAV frontend for the webbrowser.
*
* RedBrowser is a SabreDAV server-plugin to provide a view to the DAV storage
* for the webbrowser.
*
* @extends \Sabre\DAV\Browser\Plugin
*/
class RedBrowser extends DAV\Browser\Plugin {
/**
* @see set_writeable()
* @see \Sabre\DAV\Auth\Backend\BackendInterface
* @var RedBasicAuth
*/
private $auth;
/**
* @brief Constructor for RedBrowser class.
*
* $enablePost will be activated through set_writeable() in a later stage.
* At the moment the write_storage permission is only valid for the whole
* folder. No file specific permissions yet.
*
* Disable assets with $enableAssets = false. Should get some thumbnail views
* anyway.
*
* @param RedBasicAuth &$auth
*/
public function __construct(&$auth) {
$this->auth = $auth;
parent::__construct(false, false);
}
/**
* The DAV browser is instantiated after the auth module and directory classes
* but before we know the current directory and who the owner and observer
* are. So we add a pointer to the browser into the auth module and vice versa.
* Then when we've figured out what directory is actually being accessed, we
* call the following function to decide whether or not to show web elements
* which include writeable objects.
*
* @todo Maybe this can be solved with some $server->subscribeEvent()?
*/
public function set_writeable() {
if (! $this->auth->owner_id) {
$this->enablePost = false;
}
if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) {
$this->enablePost = false;
} else {
$this->enablePost = true;
}
}
/**
* @brief Creates the directory listing for the given path.
*
* @param string $path which should be displayed
*/
public function generateDirectoryIndex($path) {
// (owner_id = channel_id) is visitor owner of this directory?
$is_owner = ((local_user() && $this->auth->owner_id == local_user()) ? true : false);
if ($this->auth->getTimezone())
date_default_timezone_set($this->auth->getTimezone());
require_once('include/conversation.php');
if ($this->auth->owner_nick) {
$html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick);
}
$files = $this->server->getPropertiesForPath($path, array(
'{DAV:}displayname',
'{DAV:}resourcetype',
'{DAV:}getcontenttype',
'{DAV:}getcontentlength',
'{DAV:}getlastmodified',
), 1);
$parent = $this->server->tree->getNodeForPath($path);
$parentpath = array();
// only show parent if not leaving /cloud/; TODO how to improve this?
if ($path && $path != "cloud") {
list($parentUri) = DAV\URLUtil::splitPath($path);
$fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
$parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
$parentpath['path'] = $fullPath;
}
$f = array();
foreach ($files as $file) {
$ft = array();
$type = null;
// This is the current directory, we can skip it
if (rtrim($file['href'],'/') == $path) continue;
list(, $name) = DAV\URLUtil::splitPath($file['href']);
if (isset($file[200]['{DAV:}resourcetype'])) {
$type = $file[200]['{DAV:}resourcetype']->getValue();
// resourcetype can have multiple values
if (!is_array($type)) $type = array($type);
foreach ($type as $k=>$v) {
// Some name mapping is preferred
switch ($v) {
case '{DAV:}collection' :
$type[$k] = t('Collection');
break;
case '{DAV:}principal' :
$type[$k] = t('Principal');
break;
case '{urn:ietf:params:xml:ns:carddav}addressbook' :
$type[$k] = t('Addressbook');
break;
case '{urn:ietf:params:xml:ns:caldav}calendar' :
$type[$k] = t('Calendar');
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
$type[$k] = t('Schedule Inbox');
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
$type[$k] = t('Schedule Outbox');
break;
case '{http://calendarserver.org/ns/}calendar-proxy-read' :
$type[$k] = 'Proxy-Read';
break;
case '{http://calendarserver.org/ns/}calendar-proxy-write' :
$type[$k] = 'Proxy-Write';
break;
}
}
$type = implode(', ', $type);
}
// If no resourcetype was found, we attempt to use
// the contenttype property
if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
$type = $file[200]['{DAV:}getcontenttype'];
}
if (!$type) $type = t('Unknown');
$size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
$lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
$fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
$displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
$displayName = $this->escapeHTML($displayName);
$type = $this->escapeHTML($type);
$icon = '';
if ($this->enableAssets) {
$node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name);
foreach (array_reverse($this->iconMap) as $class=>$iconName) {
if ($node instanceof $class) {
$icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>';
break;
}
}
}
$parentHash = "";
$owner = $this->auth->owner_id;
$splitPath = split("/", $fullPath);
if (count($splitPath) > 3) {
for ($i = 3; $i < count($splitPath); $i++) {
$attachName = urldecode($splitPath[$i]);
$attachHash = $this->findAttachHash($owner, $parentHash, $attachName);
$parentHash = $attachHash;
}
}
$attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>";
// put the array for this file together
$ft['attachId'] = $this->findAttachIdByHash($attachHash);
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
$ft['icon'] = $icon;
$ft['attachIcon'] = (($size) ? $attachIcon : '');
// @todo Should this be an item value, not a global one?
$ft['is_owner'] = $is_owner;
$ft['fullPath'] = $fullPath;
$ft['displayName'] = $displayName;
$ft['type'] = $type;
$ft['size'] = $size;
$ft['sizeFormatted'] = $this->userReadableSize($size);
$ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : '');
$f[] = $ft;
}
// Storage and quota for the account (all channels of the owner of this directory)!
$limit = service_class_fetch($owner, 'attach_upload_limit');
$r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
intval($this->auth->channel_account_id)
);
$used = $r[0]['total'];
if ($used) {
$quotaDesc = t('%1$s used');
$quotaDesc = sprintf($quotaDesc,
$this->userReadableSize($used));
}
if ($limit && $used) {
$quotaDesc = t('%1$s used of %2$s (%3$s&#37;)');
$quotaDesc = sprintf($quotaDesc,
$this->userReadableSize($used),
$this->userReadableSize($limit),
round($used / $limit, 1));
}
// prepare quota for template
$quota['used'] = $used;
$quota['limit'] = $limit;
$quota['desc'] = $quotaDesc;
$html .= replace_macros(get_markup_template('cloud_directory.tpl'), array(
'$header' => t('Files') . ": " . $this->escapeHTML($path) . "/",
'$parentpath' => $parentpath,
'$entries' => $f,
'$quota' => $quota,
'$name' => t('Name'),
'$type' => t('Type'),
'$size' => t('Size'),
'$lastmod' => t('Last Modified'),
'$parent' => t('parent'),
'$edit' => t('Edit'),
'$delete' => t('Delete'),
'$total' => t('Total')
));
$output = '';
if ($this->enablePost) {
$this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
}
$html .= $output;
get_app()->page['content'] = $html;
construct_page(get_app());
}
function userReadableSize($size) {
$ret = "";
if (is_numeric($size)) {
$incr = 0;
$k = 1024;
$unit = array('bytes', 'KB', 'MB', 'GB', 'TB', 'PB');
while (($size / $k) >= 1){
$incr++;
$size = round($size / $k, 2);
}
$ret = $size . " " . $unit[$incr];
}
return $ret;
}
/**
* @brief Creates a form to add new folders and upload files.
*
* @param \Sabre\DAV\INode $node
* @param string &$output
*/
public function htmlActionsPanel(DAV\INode $node, &$output) {
if (! $node instanceof DAV\ICollection)
return;
// We also know fairly certain that if an object is a non-extended
// SimpleCollection, we won't need to show the panel either.
if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
return;
$output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
'$folder_header' => t('Create new folder'),
'$folder_submit' => t('Create'),
'$upload_header' => t('Upload file'),
'$upload_submit' => t('Upload')
));
}
/**
* This method takes a path/name of an asset and turns it into url
* suiteable for http access.
*
* @param string $assetName
* @return string
*/
protected function getAssetUrl($assetName) {
return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName);
}
/**
* @brief Return the hash of an attachment.
*
* Given the owner, the parent folder and and attach name get the attachment
* hash.
*
* @param int $owner
* The owner_id
* @param string $hash
* The parent's folder hash
* @param string $attachName
* The name of the attachment
* @return string
*/
protected function findAttachHash($owner, $parentHash, $attachName) {
$r = q("SELECT hash FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited DESC LIMIT 1",
intval($owner),
dbesc($parentHash),
dbesc($attachName)
);
$hash = "";
if ($r) {
foreach ($r as $rr) {
$hash = $rr['hash'];
}
}
return $hash;
}
/**
* @brief Returns an attachment's id for a given hash.
*
* This id is used to access the attachment in filestorage/
*
* @param string $attachHash
* The hash of an attachment
* @return string
*/
protected function findAttachIdByHash($attachHash) {
$r = q("SELECT id FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1",
dbesc($attachHash)
);
$id = "";
if ($r) {
foreach ($r as $rr) {
$id = $rr['id'];
}
}
return $id;
}
}

View file

@ -159,6 +159,14 @@ function bb_parse_app($match) {
}
function bb_parse_element($match) {
$j = json_decode(base64url_decode($match[1]),true);
if($j) {
$o = EOL . '<a href="' . z_root() . '" foo="baz" onclick="importElement(\'' . $match[1] . '\'); return false;" >' . t('Install design element: ') . $j['pagetitle'] . '</a>' . EOL;
}
return $o;
}
function bb_qr($match) {
return '<img class="zrl" src="' . z_root() . '/photo/qr?f=&qr=' . urlencode($match[1]) . '" alt="' . t('QR code') . '" title="' . htmlspecialchars($match[1],ENT_QUOTES,'UTF-8') . '" />';
}
@ -700,6 +708,10 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) {
$Text = preg_replace_callback("/\[app\](.*?)\[\/app\]/ism",'bb_parse_app', $Text);
}
if(strpos($Text,'[/element]') !== false) {
$Text = preg_replace_callback("/\[element\](.*?)\[\/element\]/ism",'bb_parse_element', $Text);
}
// html5 video and audio
if (strpos($Text,'[/video]') !== false) {

View file

@ -928,8 +928,8 @@ function get_diaspora_reshare_xml($url,$recurse = 0) {
// see if it's a reshare of a reshare
if($source_xml->root_diaspora_id && $source_xml->root_guid && $recurse < 15) {
$orig_author = notags(unxmlify($xml->root_diaspora_id));
$orig_guid = notags(unxmlify($xml->root_guid));
$orig_author = notags(unxmlify($source_xml->root_diaspora_id));
$orig_guid = notags(unxmlify($source_xml->root_guid));
$source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml';
$y = get_diaspora_reshare_xml($source_url,$recurse+1);
if($y)
@ -984,6 +984,10 @@ function diaspora_reshare($importer,$xml,$msg) {
if($source_xml->post->status_message) {
$body = diaspora2bb($source_xml->post->status_message->raw_message);
$orig_author = notags(unxmlify($source_xml->post->status_message->diaspora_handle));
$orig_guid = notags(unxmlify($source_xml->post->status_message->guid));
// Checking for embedded pictures
if($source_xml->post->status_message->photo->remote_photo_path &&
$source_xml->post->status_message->photo->remote_photo_name) {

View file

@ -50,7 +50,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
// look for any existing conversation structure
if(strlen($replyto)) {
$r = q("select convid from mail where uid = %d and ( mid = '%s' or parent_mid = '%s' ) limit 1",
$r = q("select convid from mail where channel_id = %d and ( mid = '%s' or parent_mid = '%s' ) limit 1",
intval(local_user()),
dbesc($replyto),
dbesc($replyto)

View file

@ -3,11 +3,24 @@
function photo_factory($data, $type = null) {
$ph = null;
if(class_exists('Imagick')) {
require_once('include/photo/photo_imagick.php');
$ph = new photo_imagick($data,$type);
$ignore_imagick = get_config('system', 'ignore_imagick');
if(class_exists('Imagick') && !$ignore_imagick) {
$v = Imagick::getVersion();
preg_match('/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $m);
if(version_compare($m[1],'6.6.7') >= 0) {
require_once('include/photo/photo_imagick.php');
$ph = new photo_imagick($data,$type);
}
else {
// earlier imagick versions have issues with scaling png's
// don't log this because it will just fill the logfile.
// leave this note here so those who are looking for why
// we aren't using imagick can find it
}
}
else {
if(! $ph) {
require_once('include/photo/photo_gd.php');
$ph = new photo_gd($data,$type);
}
@ -480,11 +493,11 @@ abstract class photo_driver {
* Guess image mimetype from filename or from Content-Type header
*
* @arg $filename string Image filename
* @arg $fromcurl boolean Check Content-Type header from curl request
* @arg $headers string Headers to check for Content-Type (from curl request)
*/
function guess_image_type($filename, $headers = '') {
logger('Photo: guess_image_type: '.$filename . ($fromcurl?' from curl headers':''), LOGGER_DEBUG);
logger('Photo: guess_image_type: '.$filename . ($headers?' from curl headers':''), LOGGER_DEBUG);
$type = null;
if ($headers) {
$a = get_app();
@ -494,13 +507,16 @@ function guess_image_type($filename, $headers = '') {
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[$k] = $v;
}
logger('Curl headers: '.var_export($hdrs, true), LOGGER_DEBUG);
if (array_key_exists('Content-Type', $hdrs))
$type = $hdrs['Content-Type'];
}
if (is_null($type)){
// FIXME!!!!
$ignore_imagick = get_config('system', 'ignore_imagick');
// Guessing from extension? Isn't that... dangerous?
if(class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
if(class_exists('Imagick') && !$ignore_imagick) {
logger('using imagemagick', LOGGER_DEBUG);
/**
* Well, this not much better,
* but at least it comes from the data inside the image,
@ -552,7 +568,7 @@ function import_profile_photo($photo,$xchan,$thing = false) {
if($photo) {
$filename = basename($photo);
$type = guess_image_type($photo,true);
$type = guess_image_type($photo);
if(! $type)
$type = 'image/jpeg';

View file

@ -14,14 +14,18 @@
*/
use Sabre\DAV;
require_once('vendor/autoload.php');
require_once('include/attach.php');
/**
* @brief RedDirectory class.
*
* A class that represents a directory.
*
* @extends \Sabre\DAV\Node
* @implements \Sabre\DAV\ICollection
* @implements \Sabre\DAV\IQuota
*/
class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
@ -1176,326 +1180,3 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic {
}
} // class RedBasicAuth
/**
* @brief RedBrowser class.
*
* RedBrowser is a SabreDAV server-plugin to provide a view to the DAV in
* the browser
*/
class RedBrowser extends DAV\Browser\Plugin {
/**
* @var RedBasicAuth
*/
private $auth;
/**
* @brief Constructor for RedBrowser.
*
* @param RedBasicAuth &$auth
*/
function __construct(&$auth) {
$this->auth = $auth;
$this->enableAssets = false;
}
// The DAV browser is instantiated after the auth module and directory classes but before we know the current
// directory and who the owner and observer are. So we add a pointer to the browser into the auth module and vice
// versa. Then when we've figured out what directory is actually being accessed, we call the following function
// to decide whether or not to show web elements which include writeable objects.
// @todo Maybe this can be solved with some $server->subscribeEvent()?
function set_writeable() {
if (! $this->auth->owner_id) {
$this->enablePost = false;
}
if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) {
$this->enablePost = false;
} else {
$this->enablePost = true;
}
}
/**
* @brief Creates the directory listing for the given path.
*
* @param string $path which should be displayed
*/
public function generateDirectoryIndex($path) {
// (owner_id = channel_id) is visitor owner of this directory?
$is_owner = ((local_user() && $this->auth->owner_id == local_user()) ? true : false);
if ($this->auth->getTimezone())
date_default_timezone_set($this->auth->getTimezone());
require_once('include/conversation.php');
if ($this->auth->owner_nick) {
$html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick);
}
$files = $this->server->getPropertiesForPath($path, array(
'{DAV:}displayname',
'{DAV:}resourcetype',
'{DAV:}getcontenttype',
'{DAV:}getcontentlength',
'{DAV:}getlastmodified',
), 1);
$parent = $this->server->tree->getNodeForPath($path);
$parentpath = array();
// only show parent if not leaving /cloud/; TODO how to improve this?
if ($path && $path != "cloud") {
list($parentUri) = DAV\URLUtil::splitPath($path);
$fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
$parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
$parentpath['path'] = $fullPath;
}
$f = array();
foreach ($files as $file) {
$ft = array();
$type = null;
// This is the current directory, we can skip it
if (rtrim($file['href'],'/')==$path) continue;
list(, $name) = DAV\URLUtil::splitPath($file['href']);
if (isset($file[200]['{DAV:}resourcetype'])) {
$type = $file[200]['{DAV:}resourcetype']->getValue();
// resourcetype can have multiple values
if (!is_array($type)) $type = array($type);
foreach ($type as $k=>$v) {
// Some name mapping is preferred
switch ($v) {
case '{DAV:}collection' :
$type[$k] = t('Collection');
break;
case '{DAV:}principal' :
$type[$k] = t('Principal');
break;
case '{urn:ietf:params:xml:ns:carddav}addressbook' :
$type[$k] = t('Addressbook');
break;
case '{urn:ietf:params:xml:ns:caldav}calendar' :
$type[$k] = t('Calendar');
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
$type[$k] = t('Schedule Inbox');
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
$type[$k] = t('Schedule Outbox');
break;
case '{http://calendarserver.org/ns/}calendar-proxy-read' :
$type[$k] = 'Proxy-Read';
break;
case '{http://calendarserver.org/ns/}calendar-proxy-write' :
$type[$k] = 'Proxy-Write';
break;
}
}
$type = implode(', ', $type);
}
// If no resourcetype was found, we attempt to use
// the contenttype property
if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
$type = $file[200]['{DAV:}getcontenttype'];
}
if (!$type) $type = t('Unknown');
$size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
$lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
$fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
$displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
$displayName = $this->escapeHTML($displayName);
$type = $this->escapeHTML($type);
$icon = '';
if ($this->enableAssets) {
$node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name);
foreach (array_reverse($this->iconMap) as $class=>$iconName) {
if ($node instanceof $class) {
$icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>';
break;
}
}
}
$parentHash = "";
$owner = $this->auth->owner_id;
$splitPath = split("/", $fullPath);
if (count($splitPath) > 3) {
for ($i = 3; $i < count($splitPath); $i++) {
$attachName = urldecode($splitPath[$i]);
$attachHash = $this->findAttachHash($owner, $parentHash, $attachName);
$parentHash = $attachHash;
}
}
$attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>";
// put the array for this file together
$ft['attachId'] = $this->findAttachIdByHash($attachHash);
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
$ft['icon'] = $icon;
$ft['attachIcon'] = (($size) ? $attachIcon : '');
// @todo Should this be an item value, not a global one?
$ft['is_owner'] = $is_owner;
$ft['fullPath'] = $fullPath;
$ft['displayName'] = $displayName;
$ft['type'] = $type;
$ft['size'] = $size;
$ft['sizeFormatted'] = $this->userReadableSize($size);
$ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : '');
$f[] = $ft;
}
// Storage and quota for the account (all channels of the owner of this directory)!
$limit = service_class_fetch($owner, 'attach_upload_limit');
$r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
intval($this->auth->channel_account_id)
);
$used = $r[0]['total'];
if ($used) {
$quotaDesc = t('%1$s used');
$quotaDesc = sprintf($quotaDesc,
$this->userReadableSize($used));
}
if ($limit && $used) {
$quotaDesc = t('%1$s used of %2$s (%3$s&#37;)');
$quotaDesc = sprintf($quotaDesc,
$this->userReadableSize($used),
$this->userReadableSize($limit),
round($used / $limit, 1));
}
// prepare quota for template
$quota['used'] = $used;
$quota['limit'] = $limit;
$quota['desc'] = $quotaDesc;
$html .= replace_macros(get_markup_template('cloud_directory.tpl'), array(
'$header' => t('Files') . ": " . $this->escapeHTML($path) . "/",
'$parentpath' => $parentpath,
'$entries' => $f,
'$quota' => $quota,
'$name' => t('Name'),
'$type' => t('Type'),
'$size' => t('Size'),
'$lastmod' => t('Last Modified'),
'$parent' => t('parent'),
'$edit' => t('Edit'),
'$delete' => t('Delete'),
'$total' => t('Total')
));
$output = '';
if ($this->enablePost) {
$this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
}
$html .= $output;
get_app()->page['content'] = $html;
construct_page(get_app());
}
function userReadableSize($size) {
$ret = "";
if (is_numeric($size)) {
$incr = 0;
$k = 1024;
$unit = array('bytes', 'KB', 'MB', 'GB', 'TB', 'PB');
while (($size / $k) >= 1){
$incr++;
$size = round($size / $k, 2);
}
$ret = $size . " " . $unit[$incr];
}
return $ret;
}
/**
* Creates a form to add new folders and upload files.
*
* @param DAV\INode $node
* @param string &$output
*/
public function htmlActionsPanel(DAV\INode $node, &$output) {
//Removed link to filestorage page
//if($this->auth->owner_id && $this->auth->owner_id == $this->auth->channel_id) {
// $channel = get_app()->get_channel();
// if($channel) {
// $output .= '<tr><td colspan="2"><a href="filestorage/' . $channel['channel_address'] . '" >' . t('Edit File properties') . '</a></td></tr><tr><td>&nbsp;</td></tr>';
// }
//}
if (! $node instanceof DAV\ICollection)
return;
// We also know fairly certain that if an object is a non-extended
// SimpleCollection, we won't need to show the panel either.
if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
return;
$output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
'$folder_header' => t('Create new folder'),
'$folder_submit' => t('Create'),
'$upload_header' => t('Upload file'),
'$upload_submit' => t('Upload')
));
}
/**
* This method takes a path/name of an asset and turns it into url
* suiteable for http access.
*
* @param string $assetName
* @return string
*/
protected function getAssetUrl($assetName) {
return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName);
}
protected function findAttachHash($owner, $parentHash, $attachName) {
$r = q("SELECT * FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited desc LIMIT 1",
intval($owner),
dbesc($parentHash),
dbesc($attachName)
);
$hash = "";
if ($r) {
foreach ($r as $rr) {
$hash = $rr['hash'];
}
}
return $hash;
}
protected function findAttachIdByHash($attachHash) {
$r = q("SELECT * FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1",
dbesc($attachHash)
);
$id = "";
if ($r) {
foreach ($r as $rr) {
$id = $rr['id'];
}
}
return $id;
}
} // class RedBrowser

View file

@ -532,6 +532,8 @@ function widget_mailmenu($arr) {
$a = get_app();
return replace_macros(get_markup_template('message_side.tpl'), array(
'$title' => t('Messages'),
'$tabs'=> array(),
'$check'=>array(

View file

@ -96,7 +96,7 @@ directory/path component in the URL) is REQUIRED.
- make sure folders *store/[data]/smarty3* and *store* exist and are writable by webserver
mkdir -p "store/\[data\]/smarty3"
mkdir -p "store/[data]/smarty3"
chmod -R 777 store

0
library/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js vendored Executable file → Normal file
View file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -7,12 +7,13 @@
*/
use Sabre\DAV;
use RedMatrix\RedDAV;
// composer autoloader for SabreDAV
require_once('vendor/autoload.php');
// workaround for HTTP-auth in CGI mode
if(x($_SERVER, 'REDIRECT_REMOTE_USER')) {
if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
if(strlen($userpass)) {
list($name, $password) = explode(':', $userpass);
@ -21,7 +22,7 @@ if(x($_SERVER, 'REDIRECT_REMOTE_USER')) {
}
}
if(x($_SERVER, 'HTTP_AUTHORIZATION')) {
if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
$userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
if(strlen($userpass)) {
list($name, $password) = explode(':', $userpass);
@ -40,7 +41,7 @@ function cloud_init(&$a) {
$theme_info_file = "view/theme/" . current_theme() . "/php/theme.php";
if (file_exists($theme_info_file)){
require_once($theme_info_file);
if(function_exists(str_replace('-', '_', current_theme()) . '_init')) {
if (function_exists(str_replace('-', '_', current_theme()) . '_init')) {
$func = str_replace('-', '_', current_theme()) . '_init';
$func($a);
}
@ -48,26 +49,26 @@ function cloud_init(&$a) {
require_once('include/reddav.php');
if(! is_dir('store'))
if (! is_dir('store'))
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
$which = null;
if(argc() > 1)
if (argc() > 1)
$which = argv(1);
$profile = 0;
$a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which . '" />' . "\r\n";
if($which)
if ($which)
profile_load($a, $which, $profile);
$auth = new RedBasicAuth();
$ob_hash = get_observer_hash();
if($ob_hash) {
if(local_user()) {
if ($ob_hash) {
if (local_user()) {
$channel = $a->get_channel();
$auth->setCurrentUser($channel['channel_address']);
$auth->channel_id = $channel['channel_id'];
@ -79,7 +80,7 @@ function cloud_init(&$a) {
$auth->observer = $ob_hash;
}
if($_GET['davguest'])
if ($_GET['davguest'])
$_SESSION['davguest'] = true;
$_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
@ -113,7 +114,7 @@ function cloud_init(&$a) {
$isapublic_file = false;
$davguest = ((x($_SESSION, 'davguest')) ? true : false);
if((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) {
if ((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) {
try {
$x = RedFileData('/' . $a->cmd, $auth);
if($x instanceof RedFile)
@ -124,7 +125,7 @@ function cloud_init(&$a) {
}
}
if((! $auth->observer) && (! $isapublic_file) && (! $davguest)) {
if ((! $auth->observer) && (! $isapublic_file) && (! $davguest)) {
try {
$auth->Authenticate($server, t('RedMatrix - Guests: Username: {your email address}, Password: +++'));
}
@ -134,13 +135,18 @@ function cloud_init(&$a) {
}
}
require_once('include/RedDAV/RedBrowser.php');
// provide a directory view for the cloud in Red Matrix
$browser = new RedBrowser($auth);
$browser = new RedDAV\RedBrowser($auth);
$auth->setBrowserPlugin($browser);
$server->addPlugin($browser);
// Experimental QuotaPlugin
// require_once('include/RedDAV/QuotaPlugin.php');
// $server->addPlugin(new RedDAV\QuotaPlugin($auth));
// All we need to do now, is to fire up the server
$server->exec();

View file

@ -152,6 +152,23 @@ function editblock_content(&$a) {
if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob))
$o .= '<br /><br /><a class="block-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Block') . '</a><br />';
$x = array(
'type' => 'block',
'title' => $itm[0]['title'],
'body' => $itm[0]['body'],
'term' => $itm[0]['term'],
'created' => $itm[0]['created'],
'edited' => $itm[0]['edited'],
'mimetype' => $itm[0]['mimetype'],
'pagetitle' => $page_title,
'mid' => $itm[0]['mid']
);
$o .= EOL . EOL . t('Share') . EOL . '<textarea onclick="this.select();" class="shareable_element_text" >[element]' . base64url_encode(json_encode($x)) . '[/element]</textarea>' . EOL . EOL;
return $o;
}

View file

@ -145,6 +145,23 @@ function editlayout_content(&$a) {
if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob))
$o .= '<br /><br /><a class="layout-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Layout') . '</a><br />';
$x = array(
'type' => 'layout',
'title' => $itm[0]['title'],
'body' => $itm[0]['body'],
'term' => $itm[0]['term'],
'created' => $itm[0]['created'],
'edited' => $itm[0]['edited'],
'mimetype' => $itm[0]['mimetype'],
'pagetitle' => $page_title,
'mid' => $itm[0]['mid']
);
$o .= EOL . EOL . t('Share') . EOL . '<textarea onclick="this.select();" class="shareable_element_text" >[element]' . base64url_encode(json_encode($x)) . '[/element]</textarea>' . EOL . EOL;
return $o;
}

View file

@ -185,6 +185,21 @@ function editwebpage_content(&$a) {
if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob))
$o .= '<br /><br /><a class="page-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Webpage') . '</a><br />';
$x = array(
'type' => 'webpage',
'title' => $itm[0]['title'],
'body' => $itm[0]['body'],
'term' => $itm[0]['term'],
'created' => $itm[0]['created'],
'edited' => $itm[0]['edited'],
'mimetype' => $itm[0]['mimetype'],
'pagetitle' => $page_title,
'mid' => $itm[0]['mid']
);
$o .= EOL . EOL . t('Share') . EOL . '<textarea onclick="this.select();" class="shareable_element_text" >[element]' . base64url_encode(json_encode($x)) . '[/element]</textarea>' . EOL . EOL;
return $o;
}

View file

@ -7,11 +7,13 @@ function impel_init(&$a) {
$ret = array('success' => false);
if(! $local_user())
if(! local_user())
json_return_and_die($ret);
logger('impel: ' . print_r($_REQUEST,true), LOGGER_DATA);
$elm = $_REQUEST['element'];
$x = base64_urldecode($elm);
$x = base64url_decode($elm);
if(! $x)
json_return_and_die($ret);
@ -20,7 +22,7 @@ function impel_init(&$a) {
json_return_and_die($ret);
$channel = get_channel();
$channel = $a->get_channel();
$arr = array();
@ -28,14 +30,17 @@ function impel_init(&$a) {
case 'webpage':
$arr['item_restrict'] = ITEM_WEBPAGE;
$namespace = 'WEBPAGE';
$installed_type = t('webpage');
break;
case 'block':
$arr['item_restrict'] = ITEM_BUILDBLOCK;
$namespace = 'BUILDBLOCK';
$installed_type = t('block');
break;
case 'layout':
$arr['item_restrict'] = ITEM_PDL;
$namespace = 'PDL';
$installed_type = t('layout');
break;
default:
logger('mod_impel: unrecognised element type' . print_r($j,true));
@ -46,8 +51,10 @@ function impel_init(&$a) {
$arr['title'] = $j['title'];
$arr['body'] = $j['body'];
$arr['term'] = $j['term'];
$arr['created'] = datetime_convert('UTC','UTC', $j['created']);
$arr['edited'] = datetime_convert('UTC','UTC',$j['edited']);
$arr['owner_xchan'] = get_observer_hash();
$arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : $get_observer_hash());
$arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash());
$arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode');
if(! $j['mid'])
@ -63,9 +70,6 @@ function impel_init(&$a) {
$channel = get_channel();
// Verify ability to use html or php!!!
$execflag = false;
@ -82,19 +86,21 @@ function impel_init(&$a) {
$remote_id = 0;
$z = q("select * from item_id where $sid = '%s' and service = '%s' and uid = %d limit 1",
$z = q("select * from item_id where sid = '%s' and service = '%s' and uid = %d limit 1",
dbesc($pagetitle),
dbesc($namespace),
intval(local_user())
);
$i = q("select id from item where mid = '%s' and $uid = %d limit 1",
$i = q("select id from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']),
intval(local_user())
);
if($z && $i) {
$remote_id = $z[0]['id'];
$arr['id'] = $i[0]['id'];
$x = item_store_update($arr,$execflag);
// don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited'])
$x = item_store_update($arr,$execflag);
}
else {
$x = item_store($arr,$execflag);
@ -102,12 +108,14 @@ function impel_init(&$a) {
if($x['success'])
$item_id = $x['item_id'];
$channel = get_channel();
update_remote_id($channel,$item_id,$arr['item_restrict'],$pagetitle,$namespace,$remote_id,$arr['mid']);
$ret['success'] = true;
info( sprintf( t('%s element installed'), $installed_type));
json_return_and_die(true);
}

View file

@ -61,18 +61,18 @@ function message_content(&$a) {
foreach($r as $rr) {
$o .= replace_macros($tpl, array(
'$id' => $rr['id'],
'$from_name' => $rr['from']['xchan_name'],
'$from_url' => chanlink_hash($rr['from_xchan']),
'$id' => $rr['id'],
'$from_name' => $rr['from']['xchan_name'],
'$from_url' => chanlink_hash($rr['from_xchan']),
'$from_photo' => $rr['from']['xchan_photo_s'],
'$to_name' => $rr['to']['xchan_name'],
'$to_url' => chanlink_hash($rr['to_xchan']),
'$to_photo' => $rr['to']['xchan_photo_s'],
'$subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
'$delete' => t('Delete message'),
'$body' => smilies(bbcode($rr['body'])),
'$date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')),
'$seen' => $rr['seen']
'$to_name' => $rr['to']['xchan_name'],
'$to_url' => chanlink_hash($rr['to_xchan']),
'$to_photo' => $rr['to']['xchan_photo_s'],
'$subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
'$delete' => t('Delete conversation'),
'$body' => smilies(bbcode($rr['body'])),
'$date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')),
'$seen' => $rr['seen']
));
}
$o .= alt_pager($a,count($r));

View file

@ -1 +1 @@
2014-10-05.819
2014-10-07.821

View file

@ -93,6 +93,10 @@
float: left;
}
a.wall-item-name-link {
font-weight: bold;
}
.wall-item-author {
white-space: nowrap;
overflow: hidden;

View file

@ -1,13 +1,3 @@
/* message side */
#message-check {
text-align: left;
white-space: normal;
margin-top: 48px;
margin-bottom: 15px;
}
/* message */
#mail-list-wrapper {

View file

@ -135,7 +135,7 @@
margin-left: 200px;
}
div[id^='photo-album-contents-'] {
margin-bottom: 3px;
#photos-usage-message {
line-height: 22px;
}

View file

@ -1,14 +1,9 @@
/* Easiest way to indent the widget body - indent the entire widget and then shift the header label back to the left */
.widget {
word-wrap: break-word;
margin-bottom: 10px;
padding: 10px 10px 10px 20px;
padding: 10px;
}
.widget h3 {
margin-left: -10px;
margin-top: 0px;
}
@ -36,13 +31,8 @@
height: 150px;
}
#note-save {
margin-top: 10px;
}
/* saved searches */
#netsearch-box #search-submit {
margin: 10px 0 7px 0;
}
@ -100,31 +90,14 @@
margin-left: 10px;
}
#datebrowse-sidebar select {
width: 190px;
max-width: 190px;
max-height: 150px;
}
/* categories */
/* group */
#sidebar-group-list {
margin-bottom: 10px;
}
.sidebar-group-li input {
float: right;
}
.groupsideedit {
float: right;
}
.group-edit-icon {
opacity: 0;
z-index: 1;
}
li:hover .group-edit-icon {
@ -145,9 +118,6 @@ li:hover .group-edit-icon {
/* photo albums */
#photo-albums-upload-link {
margin-top: 10px;
}
/* Chatrooms */

View file

@ -898,7 +898,10 @@ function updateConvItems(mode,data) {
"impel",
{ "element" : elem }
);
return false;
if(timer) clearTimeout(timer);
timer = setTimeout(NavUpdate,10);
return true;
}
function preview_post() {

View file

@ -62,7 +62,7 @@ abbr {
}
a, a:visited, a:link, .fakelink, .fakelink:visited, .fakelink:link {
font-weight: bold;
font-weight: $link_font_weight;
color: $link_colour;
text-decoration: none;
}
@ -75,12 +75,10 @@ a:hover, .fakelink:hover { color: $link_colour; text-decoration: underline; }
a.btn-default {
color: #333;
font-weight: normal;
}
a.btn-success {
color: #fff;
font-weight: normal;
}
input[type="text"],
@ -444,7 +442,6 @@ aside li {
margin-bottom: 15px;
}
.fn {
font-weight: bold;
font-size: 16px;
@ -461,11 +458,6 @@ aside li {
border-radius: $radiuspx;
}
.vcard .title {
margin-bottom: 10px;
}
.vcard dl {
margin-top: 10px;
margin-bottom: 0px;
@ -530,6 +522,11 @@ aside li {
height: 197px;
}
#profile-photo-wrapper {
margin-top: 10px;
}
#profile-in-dir-yes-label,
#profile-in-dir-no-label,
#profile-in-netdir-yes-label,
@ -2142,7 +2139,7 @@ img.mail-list-sender-photo {
border-bottom-right-radius: $radiuspx;
border-bottom-left-radius: $radiuspx;
text-align: center;
font-weight: bold;
font-size: $body_font_size;
color: $link_colour;
cursor: pointer;
}
@ -2314,6 +2311,11 @@ blockquote {
$dropdown_bgimghover
}
aside .nav > li > a:hover, aside .nav > li > a:focus {
text-decoration: $navtabs_decohover;
background-color: $navaside_bghover;
}
.dropdown-menu img {
border-radius: $radiuspx;
}
@ -2528,3 +2530,8 @@ blockquote {
}
}
.shareable_element_text {
height: 300px;
width: 300px;
}

View file

@ -109,6 +109,10 @@ if(! $a->install) {
$navtabs_bgchover = "rgba(238,238,238,0.8)";
if (! $link_colour)
$link_colour = "#428BCA";
if (! $navaside_bghover)
$navaside_bghover = "#eee";
if (! $link_font_weight)
$link_font_weight = "normal";
if (! $banner_colour)
$banner_colour = "#fff";
if (! $search_background)
@ -320,7 +324,9 @@ $options = array (
'$navtabs_linkchover' => $navtabs_linkchover,
'$navtabs_bgchover' => $navtabs_bgchover,
'$navtabs_decohover' => $navtabs_decohover,
'$navaside_bghover' => $navaside_bghover,
'$link_colour' => $link_colour,
'$link_font_weight' => $link_font_weight,
'$banner_colour' => $banner_colour,
'$search_background' => $search_background,
'$bgcolour' => $bgcolour,

View file

@ -11,7 +11,7 @@ require_once('view/php/theme_init.php');
head_add_js('library/bootstrap/js/bootstrap.min.js');
head_add_js('library/bootstrap/js/bootbox.min.js');
head_add_js('library/bootstrap-datetimepicker/js/moment.js');
head_add_js('library/bootstrap-datetimepicker/js/moment.min.js');
head_add_js('library/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js');
//head_add_js('library/colorpicker/js/colorpicker.js');
head_add_js('library/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js');

View file

@ -34,8 +34,12 @@
$navtabs_bgchover = "#222";
if (! $navtabs_decohover)
$navtabs_decohover = "underline";
if (! $navaside_bghover)
$navaside_bghover = "#222";
if (! $link_colour)
$link_colour = "#fff";
if (! $link_font_weight)
$link_font_weight = "bold";
if (! $selected_active_colour)
$selected_active_colour = "#fff";
if (! $selected_active_deco)

View file

@ -34,8 +34,12 @@
$navtabs_bgchover = "#fff";
if (! $navtabs_decohover)
$navtabs_decohover = "underline";
if (! $navaside_bghover)
$navaside_bghover = "#F5F5F5";
if (! $link_colour)
$link_colour = "#000";
if (! $link_font_weight)
$link_font_weight = "bold";
if (! $selected_active_colour)
$selected_active_colour = "#000";
if (! $selected_active_deco)

View file

@ -34,8 +34,12 @@
$navtabs_bgchover = "#000";
if (! $navtabs_decohover)
$navtabs_decohover = "underline";
if (! $navaside_bghover)
$navaside_bghover = "#143D12";
if (! $link_colour)
$link_colour = "#50f148";
if (! $link_font_weight)
$link_font_weight = "bold";
if (! $selected_active_colour)
$selected_active_colour = "#50f148";
if (! $selected_active_deco)

View file

@ -34,8 +34,12 @@
$navtabs_bgchover = "#000";
if (! $navtabs_decohover)
$navtabs_decohover = "underline";
if (! $navaside_bghover)
$navaside_bghover = "#030303";
if (! $link_colour)
$link_colour = "#fff";
if (! $link_font_weight)
$link_font_weight = "bold";
if (! $selected_active_colour)
$selected_active_colour = "#fff";
if (! $selected_active_deco)

View file

@ -10,35 +10,35 @@
});
});
</script>
<h4><a href="{{$admurl}}">{{$admtxt}}</a></h4>
<ul class='admin linklist'>
<li class='admin link button {{$admin.site.2}}'><a href='{{$admin.site.0}}'>{{$admin.site.1}}</a></li>
<li class='admin link button {{$admin.users.2}}'><a href='{{$admin.users.0}}'>{{$admin.users.1}}</a><span id='pending-update' title='{{$h_pending}}'></span></li>
<li class='admin link button {{$admin.channels.2}}'><a href='{{$admin.channels.0}}'>{{$admin.channels.1}}</a></li>
<li class='admin link button {{$admin.plugins.2}}'><a href='{{$admin.plugins.0}}'>{{$admin.plugins.1}}</a></li>
<li class='admin link button {{$admin.themes.2}}'><a href='{{$admin.themes.0}}'>{{$admin.themes.1}}</a></li>
<li class='admin link button {{$admin.hubloc.2}}'><a href='{{$admin.hubloc.0}}'>{{$admin.hubloc.1}}</a></li>
<li class='admin link button {{$admin.dbsync.2}}'><a href='{{$admin.dbsync.0}}'>{{$admin.dbsync.1}}</a></li>
<h3>{{$admtxt}}</h3>
<ul class="nav nav-pills nav-stacked">
<li><a href='{{$admin.site.0}}'>{{$admin.site.1}}</a></li>
<li><a href='{{$admin.users.0}}'>{{$admin.users.1}}<span id='pending-update' title='{{$h_pending}}'></span></a></li>
<li><a href='{{$admin.channels.0}}'>{{$admin.channels.1}}</a></li>
<li><a href='{{$admin.plugins.0}}'>{{$admin.plugins.1}}</a></li>
<li><a href='{{$admin.themes.0}}'>{{$admin.themes.1}}</a></li>
<li><a href='{{$admin.hubloc.0}}'>{{$admin.hubloc.1}}</a></li>
<li><a href='{{$admin.dbsync.0}}'>{{$admin.dbsync.1}}</a></li>
</ul>
{{if $admin.update}}
<ul class='admin linklist'>
<li class='admin link button {{$admin.update.2}}'><a href='{{$admin.update.0}}'>{{$admin.update.1}}</a></li>
<li class='admin link button {{$admin.update.2}}'><a href='https://kakste.com/profile/inthegit'>Important Changes</a></li>
<ul class="nav nav-pills nav-stacked">
<li><a href='{{$admin.update.0}}'>{{$admin.update.1}}</a></li>
<li><a href='https://kakste.com/profile/inthegit'>Important Changes</a></li>
</ul>
{{/if}}
{{if $admin.plugins_admin}}<h4>{{$plugadmtxt}}</h4>{{/if}}
<ul class='admin linklist'>
{{if $admin.plugins_admin}}<h3>{{$plugadmtxt}}</h3>{{/if}}
<ul class="nav nav-pills nav-stacked">
{{foreach $admin.plugins_admin as $l}}
<li class='admin link button {{$l.2}}'><a href='{{$l.0}}'>{{$l.1}}</a></li>
<li><a href='{{$l.0}}'>{{$l.1}}</a></li>
{{/foreach}}
</ul>
<h4>{{$logtxt}}</h4>
<ul class='admin linklist'>
<li class='admin link button {{$admin.logs.2}}'><a href='{{$admin.logs.0}}'>{{$admin.logs.1}}</a></li>
<h3>{{$logtxt}}</h3>
<ul class="nav nav-pills nav-stacked">
<li><a href='{{$admin.logs.0}}'>{{$admin.logs.1}}</a></li>
</ul>

View file

@ -2,10 +2,10 @@
<h3>{{$title}}</h3>
<div id="categories-sidebar-desc">{{$desc}}</div>
<ul class="categories-ul">
<li class="tool"><a href="{{$base}}" class="categories-link categories-all{{if $sel_all}} categories-selected{{/if}}">{{$all}}</a></li>
<ul class="nav nav-pills nav-stacked">
<li><a href="{{$base}}"{{if $sel_all}} class="categories-selected"{{/if}}>{{$all}}</a></li>
{{foreach $terms as $term}}
<li class="tool"><a href="{{$base}}?f=&cat={{$term.name}}" class="categories-link{{if $term.selected}} categories-selected{{/if}}">{{$term.name}}</a></li>
<li><a href="{{$base}}?f=&cat={{$term.name}}"{{if $term.selected}} class="categories-selected"{{/if}}>{{$term.name}}</a></li>
{{/foreach}}
</ul>

View file

@ -84,7 +84,7 @@
<span class="input-group-addon"><!-- <span class="glyphicon glyphicon-calendar"></span> -->
<span class="icon-calendar"></span>
</span>
<input id="start-date" value='{{$stext}}' type='text' class="form-control" data-format="YYYY-MM-DD HH:mm" size="20"/>
<input id="start-date" value='{{$stext}}' type='text' class="form-control" data-date-format="YYYY-MM-DD HH:mm" size="20"/>
</div>
</div>
<!-- </div> -->
@ -123,7 +123,7 @@
<span class="input-group-addon"><!-- <span class="glyphicon glyphicon-calendar"></span> -->
<span class="icon-calendar"></span>
</span>
<input id="finish-date" value='{{$ftext}}' type='text' class="form-control" data-format="YYYY-MM-DD HH:mm" size="20"/>
<input id="finish-date" value='{{$ftext}}' type='text' class="form-control" data-date-format="YYYY-MM-DD HH:mm" size="20"/>
</div>
</div>
<!-- </div> -->

View file

@ -2,10 +2,10 @@
<h3>{{$title}}</h3>
<div id="nets-desc">{{$desc}}</div>
<ul class="fileas-ul">
<li class="tool"><a href="{{$base}}" class="fileas-link fileas-all{{if $sel_all}} fileas-selected{{/if}}">{{$all}}</a></li>
<ul class="nav nav-pills nav-stacked">
<li><a href="{{$base}}"{{if $sel_all}} class="fileas-selected"{{/if}}>{{$all}}</a></li>
{{foreach $terms as $term}}
<li class="tool"><a href="{{$base}}?f=&file={{$term.name}}" class="fileas-link{{if $term.selected}} fileas-selected{{/if}}">{{$term.name}}</a></li>
<li><a href="{{$base}}?f=&file={{$term.name}}"{{if $term.selected}} class="fileas-selected"{{/if}}>{{$term.name}}</a></li>
{{/foreach}}
</ul>

View file

@ -2,9 +2,9 @@
{{if $title}}<h3>{{$title}}</h3>{{/if}}
{{if $desc}}<div class="desc">{{$desc}}</div>{{/if}}
<ul>
<ul class="nav nav-pills nav-stacked">
{{foreach $items as $item}}
<li class="tool"><a href="{{$item.url}}" class="{{if $item.selected}}active{{/if}}">{{$item.label}}</a></li>
<li><a href="{{$item.url}}" class="{{if $item.selected}}active{{/if}}">{{$item.label}}</a></li>
{{/foreach}}
</ul>

View file

@ -1,31 +1,27 @@
<div class="widget" id="group-sidebar">
<h3>{{$title}}</h3>
<div id="sidebar-group-list">
<ul id="sidebar-group-ul">
{{foreach $groups as $group}}
<li class="sidebar-group-li">
<h3>{{$title}}</h3>
<div>
<ul class="nav nav-pills nav-stacked">
{{foreach $groups as $group}}
<li>
{{if $group.cid}}
<input type="checkbox"
class="{{if $group.selected}}ticked{{else}}unticked {{/if}} action"
onclick="contactgroupChangeMember('{{$group.id}}','{{$group.enc_cid}}');return true;"
{{if $group.ismember}}checked="checked"{{/if}}
/>
<input type="checkbox"
class="{{if $group.selected}}ticked{{else}}unticked {{/if}} action"
onclick="contactgroupChangeMember('{{$group.id}}','{{$group.enc_cid}}');return true;"
{{if $group.ismember}}checked="checked"{{/if}}
/>
{{/if}}
{{if $group.edit}}
<a class="groupsideedit" href="{{$group.edit.href}}" title="{{$edittext}}"><i id="edit-sidebar-group-element-{{$group.id}}" class="group-edit-icon iconspacer icon-pencil"></i></a>
<a class="pull-right group-edit-icon" href="{{$group.edit.href}}" title="{{$edittext}}"><i class="icon-pencil"></i></a>
{{/if}}
<span class="sidebar-group-name"><a id="sidebar-group-element-{{$group.id}}" class="sidebar-group-element {{if $group.selected}}group-selected{{/if}}" href="{{$group.href}}">{{$group.text}}</a></span>
<a class="{{if $group.selected}}group-selected{{/if}}" href="{{$group.href}}">{{$group.text}}</a>
</li>
{{/foreach}}
</ul>
</div>
<div id="sidebar-new-group">
<a href="group/new">{{$createtext}}</a>
</div>
{{/foreach}}
<li>
<a href="group/new">{{$createtext}}</a>
</li>
</ul>
</div>
</div>

View file

@ -112,7 +112,7 @@
<span class="input-group-addon"><!-- <span class="glyphicon glyphicon-calendar"></span> -->
<span class="icon-calendar"></span>
</span>
<input id="expiration-date" type='text' class="form-control" data-format="YYYY-MM-DD HH:mm" size="20"/>
<input id="expiration-date" type='text' class="form-control" data-date-format="YYYY-MM-DD HH:mm" size="20"/>
</div>
</div>
<!-- </div> -->

View file

@ -1,11 +1,14 @@
<div id="message-sidebar" class="widget">
<div id="message-check" class="btn btn-default"><a href="{{$check.url}}" class="{{if $check.sel}}checkmessage-selected{{/if}}">{{$check.label}}</a> </div>
<div id="message-new" class="btn btn-default"><a href="{{$new.url}}" class="{{if $new.sel}}newmessage-selected{{/if}}">{{$new.label}}</a> </div>
<ul class="message-ul">
<div class="widget">
<h3>{{$title}}</h3>
<ul class="nav nav-pills nav-stacked">
<li><a href="{{$check.url}}"{{if $check.sel}} class="checkmessage-selected"{{/if}}>{{$check.label}}</a></li>
<li><a href="{{$new.url}}"{{if $new.sel}} class="newmessage-selected"{{/if}}>{{$new.label}}</a></li>
</ul>
{{if $tabs}}
<ul class="nav nav-pills nav-stacked">
{{foreach $tabs as $t}}
<li class="tool"><a href="{{$t.url}}" class="message-link{{if $t.sel}}message-selected{{/if}}">{{$t.label}}</a></li>
<li><a href="{{$t.url}}"{{if $t.sel}} class="message-selected"{{/if}}>{{$t.label}}</a></li>
{{/foreach}}
</ul>
{{/if}}
</div>

View file

@ -1,6 +1,8 @@
<h3>{{$pagename}}</h3>
<div id="photos-usage-message" class="usage-message">{{$usage}}</div>
<div class="section-title-wrapper">
<div id="photos-usage-message" class="pull-right">{{$usage}}</div>
<h2>{{$pagename}}</h2>
<div class="clear"></div>
</div>
<form action="photos/{{$nickname}}" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form" >
<input type="hidden" id="photos-upload-source" name="source" value="photos" />

View file

@ -1,16 +1,20 @@
<div id="datebrowse-sidebar" class="widget">
<h3>{{$title}}</h3>
<script>function dateSubmit(dateurl) { window.location.href = dateurl; } </script>
<ul id="posted-date-selector">
{{foreach $dates as $y => $arr}}
<li id="posted-date-selector-year-{{$y}}" class="fakelink" onclick="openClose('posted-date-selector-{{$y}}');">{{$y}}</li>
<div id="posted-date-selector-{{$y}}" style="display: none;">
<ul class="posted-date-selector-months">
{{foreach $arr as $d}}
<li class="posted-date-li"><a href="#" onclick="dateSubmit('{{$url}}?f=&dend={{$d.1}}&dbegin={{$d.2}}'); return false;">{{$d.0}}</a></li>
{{/foreach}}
</ul>
</div>
{{/foreach}}
</ul>
<script>function dateSubmit(dateurl) { window.location.href = dateurl; } </script>
<ul id="posted-date-selector" class="nav nav-pills nav-stacked">
{{foreach $dates as $y => $arr}}
<li id="posted-date-selector-year-{{$y}}">
<a href="#" onclick="openClose('posted-date-selector-{{$y}}'); return false;">{{$y}}</a>
</li>
<div id="posted-date-selector-{{$y}}" style="display: none;">
<ul class="posted-date-selector-months nav nav-pills nav-stacked">
{{foreach $arr as $d}}
<li>
<a href="#" onclick="dateSubmit('{{$url}}?f=&dend={{$d.1}}&dbegin={{$d.2}}'); return false;">{{$d.0}}</a>
</li>
{{/foreach}}
</ul>
</div>
{{/foreach}}
</ul>
</div>