Merge branch 'dev' of https://github.com/redmatrix/hubzilla into xdev_merge

This commit is contained in:
zotlabs 2017-03-30 16:10:59 -07:00
commit a9cceea850
21 changed files with 3282 additions and 431 deletions

View File

@ -83,6 +83,7 @@ class Import extends \Zotlabs\Web\Controller {
$api_path .= 'channel/export/basic?f=&channel=' . $channelname; $api_path .= 'channel/export/basic?f=&channel=' . $channelname;
if($import_posts) if($import_posts)
$api_path .= '&posts=1'; $api_path .= '&posts=1';
$binary = false; $binary = false;
$redirects = 0; $redirects = 0;
$opts = array('http_auth' => $email . ':' . $password); $opts = array('http_auth' => $email . ':' . $password);
@ -104,8 +105,8 @@ class Import extends \Zotlabs\Web\Controller {
$data = json_decode($data,true); $data = json_decode($data,true);
// logger('import: data: ' . print_r($data,true)); //logger('import: data: ' . print_r($data,true));
// print_r($data); //print_r($data);
if(! array_key_exists('compatibility',$data)) { if(! array_key_exists('compatibility',$data)) {
call_hooks('import_foreign_channel_data',$data); call_hooks('import_foreign_channel_data',$data);
@ -248,7 +249,7 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 6'); logger('import step 6');
// import xchans
$xchans = $data['xchan']; $xchans = $data['xchan'];
if($xchans) { if($xchans) {
foreach($xchans as $xchan) { foreach($xchans as $xchan) {
@ -292,13 +293,11 @@ class Import extends \Zotlabs\Web\Controller {
dbesc($photodate), dbesc($photodate),
dbesc($xchan['xchan_hash']) dbesc($xchan['xchan_hash'])
); );
} }
logger('import step 7'); logger('import step 7');
} }
$friends = 0; $friends = 0;
$feeds = 0; $feeds = 0;
@ -367,19 +366,20 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 8'); logger('import step 8');
} }
// import groups
$groups = $data['group']; $groups = $data['group'];
if($groups) { if($groups) {
$saved = array(); $saved = array();
foreach($groups as $group) { foreach($groups as $group) {
$saved[$group['hash']] = array('old' => $group['id']); $saved[$group['hash']] = array('old' => $group['id']);
if(array_key_exists('name',$group)) { if(array_key_exists('name', $group)) {
$group['gname'] = $group['name']; $group['gname'] = $group['name'];
unset($group['name']); unset($group['name']);
} }
unset($group['id']); unset($group['id']);
$group['uid'] = $channel['channel_id']; $group['uid'] = $channel['channel_id'];
create_table_from_array('groups',$group); create_table_from_array('groups', $group);
} }
$r = q("select * from groups where uid = %d", $r = q("select * from groups where uid = %d",
intval($channel['channel_id']) intval($channel['channel_id'])
@ -391,7 +391,7 @@ class Import extends \Zotlabs\Web\Controller {
} }
} }
// import group members
$group_members = $data['group_member']; $group_members = $data['group_member'];
if($group_members) { if($group_members) {
foreach($group_members as $group_member) { foreach($group_members as $group_member) {
@ -401,7 +401,7 @@ class Import extends \Zotlabs\Web\Controller {
if($x['old'] == $group_member['gid']) if($x['old'] == $group_member['gid'])
$group_member['gid'] = $x['new']; $group_member['gid'] = $x['new'];
} }
create_table_from_array('group_member',$group_member); create_table_from_array('group_member', $group_member);
} }
} }
@ -450,7 +450,6 @@ class Import extends \Zotlabs\Web\Controller {
notifications_on($channel['channel_id'],$saved_notification_flags); notifications_on($channel['channel_id'],$saved_notification_flags);
if(array_key_exists('item_id',$data) && $data['item_id']) if(array_key_exists('item_id',$data) && $data['item_id'])
import_item_ids($channel,$data['item_id']); import_item_ids($channel,$data['item_id']);
@ -490,7 +489,7 @@ class Import extends \Zotlabs\Web\Controller {
function get() { function get() {
if(! get_account_id()) { if(! get_account_id()) {
notice( t('You must be logged in to use this feature.')); notice( t('You must be logged in to use this feature.') . EOL);
return ''; return '';
} }

View File

@ -3,7 +3,11 @@ namespace Zotlabs\Module;
require_once('include/import.php'); require_once('include/import.php');
/**
* @brief Module for importing items.
*
* Import existing posts and content from an export file.
*/
class Import_items extends \Zotlabs\Web\Controller { class Import_items extends \Zotlabs\Web\Controller {
function post() { function post() {
@ -38,7 +42,7 @@ class Import_items extends \Zotlabs\Web\Controller {
$old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : '');
if(! $old_address) { if(! $old_address) {
logger('mod_import: nothing to import.'); logger('Nothing to import.');
notice( t('Nothing to import.') . EOL); notice( t('Nothing to import.') . EOL);
return; return;
} }
@ -64,19 +68,18 @@ class Import_items extends \Zotlabs\Web\Controller {
$data = $ret['body']; $data = $ret['body'];
else else
notice( t('Unable to download data from old server') . EOL); notice( t('Unable to download data from old server') . EOL);
} }
if(! $data) { if(! $data) {
logger('mod_import: empty file.'); logger('Empty file.');
notice( t('Imported file is empty.') . EOL); notice( t('Imported file is empty.') . EOL);
return; return;
} }
$data = json_decode($data,true); $data = json_decode($data, true);
// logger('import: data: ' . print_r($data,true)); //logger('import: data: ' . print_r($data,true));
// print_r($data); //print_r($data);
if(! is_array($data)) if(! is_array($data))
return; return;
@ -86,13 +89,12 @@ class Import_items extends \Zotlabs\Web\Controller {
$v2 = substr(DB_UPDATE_VERSION,-4); $v2 = substr(DB_UPDATE_VERSION,-4);
if($v2 > $v1) { if($v2 > $v1) {
$t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
notice($t); notice($t . EOL);
} }
} }
$channel = \App::get_channel(); $channel = \App::get_channel();
if(array_key_exists('item',$data) && $data['item']) { if(array_key_exists('item',$data) && $data['item']) {
import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null));
} }
@ -102,12 +104,14 @@ class Import_items extends \Zotlabs\Web\Controller {
} }
info( t('Import completed') . EOL); info( t('Import completed') . EOL);
return;
} }
/**
* @brief Generate item import page.
*
* @return string with parsed HTML.
*/
function get() { function get() {
if(! local_channel()) { if(! local_channel()) {
@ -115,7 +119,7 @@ class Import_items extends \Zotlabs\Web\Controller {
return login(); return login();
} }
$o = replace_macros(get_markup_template('item_import.tpl'),array( $o = replace_macros(get_markup_template('item_import.tpl'), array(
'$title' => t('Import Items'), '$title' => t('Import Items'),
'$desc' => t('Use this form to import existing posts and content from an export file.'), '$desc' => t('Use this form to import existing posts and content from an export file.'),
'$label_filename' => t('File to Upload'), '$label_filename' => t('File to Upload'),
@ -123,9 +127,6 @@ class Import_items extends \Zotlabs\Web\Controller {
)); ));
return $o; return $o;
} }
} }

View File

@ -236,11 +236,10 @@ class Wiki extends \Zotlabs\Web\Controller {
$mimeType = $p['mimeType']; $mimeType = $p['mimeType'];
$rawContent = htmlspecialchars_decode(json_decode($p['content']),ENT_COMPAT); $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page'));
$rawContent = $p['content']; $content = (($p['content'] == '') ? $sampleContent : $p['content']);
$content = ($p['content'] !== '' ? $rawContent : '"# New page\n"');
// Render the Markdown-formatted page content in HTML // Render the Markdown-formatted page content in HTML
if($mimeType == 'text/bbcode') { if($mimeType == 'text/bbcode') {
$renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName); $renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
@ -365,6 +364,14 @@ class Wiki extends \Zotlabs\Web\Controller {
if($wiki['urlName'] === '') { if($wiki['urlName'] === '') {
notice( t('Error creating wiki. Invalid name.') . EOL); notice( t('Error creating wiki. Invalid name.') . EOL);
goaway('/wiki'); goaway('/wiki');
return; //not reached
}
$exists = Zlib\NativeWiki::exists_by_name($owner['channel_id'], $wiki['urlName']);
if($exists['id']) {
notice( t('A wiki with this name already exists.') . EOL);
goaway('/wiki');
return; //not reached
} }
// Get ACL for permissions // Get ACL for permissions

View File

@ -1,6 +1,17 @@
<?php /** @file */ <?php
/**
* @file include/hubloc.php
* @brief Hubloc related functions.
*/
/**
* @brief Create an array for hubloc table and insert record.
*
* Creates an assoziative array which will be inserted into the hubloc table.
*
* @param array $arr An assoziative array with hubloc values
* @return boolean|PDOStatement
*/
function hubloc_store_lowlevel($arr) { function hubloc_store_lowlevel($arr) {
$store = [ $store = [
@ -25,8 +36,7 @@ function hubloc_store_lowlevel($arr) {
'hubloc_deleted' => ((array_key_exists('hubloc_deleted',$arr)) ? $arr['hubloc_deleted'] : 0) 'hubloc_deleted' => ((array_key_exists('hubloc_deleted',$arr)) ? $arr['hubloc_deleted'] : 0)
]; ];
return create_table_from_array('hubloc',$store); return create_table_from_array('hubloc', $store);
} }
@ -45,9 +55,8 @@ function prune_hub_reinstalls() {
// see if this url has more than one sitekey, indicating it has been re-installed. // see if this url has more than one sitekey, indicating it has been re-installed.
if(count($x) > 1) { if(count($x) > 1) {
$d1 = datetime_convert('UTC', 'UTC', $x[0]['c']);
$d1 = datetime_convert('UTC','UTC',$x[0]['c']); $d2 = datetime_convert('UTC', 'UTC', 'now - 3 days');
$d2 = datetime_convert('UTC','UTC','now - 3 days');
// allow some slop period, say 3 days - just in case this is a glitch or transient occurrence // allow some slop period, say 3 days - just in case this is a glitch or transient occurrence
// Then remove any hublocs pointing to the oldest entry. // Then remove any hublocs pointing to the oldest entry.
@ -63,18 +72,22 @@ function prune_hub_reinstalls() {
} }
} }
/**
* @brief Remove obsolete hublocs.
*
* Get rid of any hublocs which are ours but aren't valid anymore -
* e.g. they point to a different and perhaps transient URL that we aren't using.
*
* I need to stress that this shouldn't happen. fix_system_urls() fixes hublocs
* when it discovers the URL has changed. So it's unclear how we could end up
* with URLs pointing to the old site name. But it happens. This may be an artifact
* of an old bug or maybe a regression in some newer code. In any event, they
* mess up communications and we have to take action if we find any.
*/
function remove_obsolete_hublocs() { function remove_obsolete_hublocs() {
logger('remove_obsolete_hublocs',LOGGER_DEBUG); logger('remove_obsolete_hublocs', LOGGER_DEBUG);
// Get rid of any hublocs which are ours but aren't valid anymore -
// e.g. they point to a different and perhaps transient URL that we aren't using.
// I need to stress that this shouldn't happen. fix_system_urls() fixes hublocs
// when it discovers the URL has changed. So it's unclear how we could end up
// with URLs pointing to the old site name. But it happens. This may be an artifact
// of an old bug or maybe a regression in some newer code. In any event, they
// mess up communications and we have to take action if we find any.
// First make sure we have any hublocs (at all) with this URL and sitekey. // First make sure we have any hublocs (at all) with this URL and sitekey.
// We don't want to perform this operation while somebody is in the process // We don't want to perform this operation while somebody is in the process
@ -82,27 +95,25 @@ function remove_obsolete_hublocs() {
$r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'", $r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'",
dbesc(z_root()), dbesc(z_root()),
dbesc(get_config('system','pubkey')) dbesc(get_config('system', 'pubkey'))
); );
if((! $r) || (! count($r))) if((! $r) || (! count($r)))
return; return;
$channels = array();
// Good. We have at least one *valid* hubloc. // Good. We have at least one *valid* hubloc.
// Do we have any invalid ones? // Do we have any invalid ones?
$r = q("select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'", $r = q("select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'",
dbesc(get_config('system','pubkey')), dbesc(get_config('system', 'pubkey')),
dbesc(z_root()) dbesc(z_root())
); );
$p = q("select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s'", $p = q("select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s'",
dbesc(get_config('system','pubkey')), dbesc(get_config('system', 'pubkey')),
dbesc(z_root()) dbesc(z_root())
); );
if(is_array($r) && is_array($p)) if(is_array($r) && is_array($p))
$r = array_merge($r,$p); $r = array_merge($r, $p);
if(! $r) if(! $r)
return; return;
@ -111,8 +122,8 @@ function remove_obsolete_hublocs() {
logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.'); logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.');
$interval = ((get_config('system','delivery_interval') !== false) $interval = ((get_config('system', 'delivery_interval') !== false)
? intval(get_config('system','delivery_interval')) : 2 ); ? intval(get_config('system', 'delivery_interval')) : 2 );
foreach($r as $rr) { foreach($r as $rr) {
q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d", q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d",
@ -123,7 +134,7 @@ function remove_obsolete_hublocs() {
dbesc($rr['hubloc_hash']) dbesc($rr['hubloc_hash'])
); );
if($x) { if($x) {
Zotlabs\Daemon\Master::Summon(array('Notifier','location',$x[0]['channel_id'])); Zotlabs\Daemon\Master::Summon(array('Notifier', 'location', $x[0]['channel_id']));
if($interval) if($interval)
@time_sleep_until(microtime(true) + (float) $interval); @time_sleep_until(microtime(true) + (float) $interval);
} }
@ -131,8 +142,15 @@ function remove_obsolete_hublocs() {
} }
// This actually changes other structures to match the given (presumably current) hubloc primary selection /**
* @brief Change primary hubloc.
*
* This actually changes other structures to match the given (presumably current)
* hubloc primary selection.
*
* @param array $hubloc
* @return boolean
*/
function hubloc_change_primary($hubloc) { function hubloc_change_primary($hubloc) {
if(! is_array($hubloc)) { if(! is_array($hubloc)) {
@ -179,7 +197,7 @@ function hubloc_change_primary($hubloc) {
} }
$url = $hubloc['hubloc_url']; $url = $hubloc['hubloc_url'];
$lwebbie = substr($hubloc['hubloc_addr'],0,strpos($hubloc['hubloc_addr'],'@')); $lwebbie = substr($hubloc['hubloc_addr'], 0, strpos($hubloc['hubloc_addr'], '@'));
$r = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s' where xchan_hash = '%s'", $r = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s' where xchan_hash = '%s'",
dbesc($hubloc['hubloc_addr']), dbesc($hubloc['hubloc_addr']),
@ -191,14 +209,19 @@ function hubloc_change_primary($hubloc) {
if(! $r) if(! $r)
logger('xchan_update failed.'); logger('xchan_update failed.');
logger('primary hubloc changed.' . print_r($hubloc,true),LOGGER_DEBUG); logger('primary hubloc changed.' . print_r($hubloc, true), LOGGER_DEBUG);
return true; return true;
} }
// We use the post url to distinguish between http and https hublocs.
// The https might be alive, and the http dead.
/**
* @brief Mark a hubloc as down.
*
* We use the post url to distinguish between http and https hublocs.
* The https might be alive, and the http dead.
*
* @param string $posturl Hubloc callback url which to disable
*/
function hubloc_mark_as_down($posturl) { function hubloc_mark_as_down($posturl) {
$r = q("update hubloc set hubloc_status = ( hubloc_status | %d ) where hubloc_callback = '%s'", $r = q("update hubloc set hubloc_status = ( hubloc_status | %d ) where hubloc_callback = '%s'",
intval(HUBLOC_OFFLINE), intval(HUBLOC_OFFLINE),
@ -208,20 +231,19 @@ function hubloc_mark_as_down($posturl) {
function ping_site($url) { function ping_site($url) {
$ret = array('success' => false); $ret = array('success' => false);
$sys = get_sys_channel(); $sys = get_sys_channel();
$m = zot_build_packet($sys,'ping'); $m = zot_build_packet($sys, 'ping');
$r = zot_zot($url . '/post',$m); $r = zot_zot($url . '/post', $m);
if(! $r['success']) { if(! $r['success']) {
$ret['message'] = 'no answer from ' . $url; $ret['message'] = 'no answer from ' . $url;
return $ret; return $ret;
} }
$packet_result = json_decode($r['body'],true); $packet_result = json_decode($r['body'], true);
if(! $packet_result['success']) { if(! $packet_result['success']) {
$ret['message'] = 'packet failure from ' . $url; $ret['message'] = 'packet failure from ' . $url;
return $ret; return $ret;

View File

@ -1,8 +1,19 @@
<?php <?php
use Zotlabs\Lib\IConfig;
require_once('include/menu.php'); require_once('include/menu.php');
require_once('include/perm_upgrade.php'); require_once('include/perm_upgrade.php');
/**
* @brief Import a channel.
*
* @param array $channel
* @param int $account_id
* @param int $seize
* @return boolean|array
*/
function import_channel($channel, $account_id, $seize) { function import_channel($channel, $account_id, $seize) {
if(! array_key_exists('channel_system',$channel)) { if(! array_key_exists('channel_system',$channel)) {
@ -108,24 +119,37 @@ function import_channel($channel, $account_id, $seize) {
set_default_login_identity($account_id,$channel['channel_id'],false); set_default_login_identity($account_id,$channel['channel_id'],false);
logger('import step 1'); logger('import step 1');
$_SESSION['import_step'] = 1; $_SESSION['import_step'] = 1;
return $channel;
return $channel;
} }
function import_config($channel,$configs) { /**
* @brief Import pconfig for channel.
*
* @param array $channel
* @param array $configs
*/
function import_config($channel, $configs) {
if($channel && $configs) { if($channel && $configs) {
foreach($configs as $config) { foreach($configs as $config) {
unset($config['id']); unset($config['id']);
$config['uid'] = $channel['channel_id']; $config['uid'] = $channel['channel_id'];
create_table_from_array('pconfig',$config);
create_table_from_array('pconfig', $config);
} }
load_pconfig($channel['channel_id']); load_pconfig($channel['channel_id']);
} }
} }
/**
function import_profiles($channel,$profiles) { * @brief Import profiles.
*
* @param array $channel
* @param array $profiles
*/
function import_profiles($channel, $profiles) {
if($channel && $profiles) { if($channel && $profiles) {
foreach($profiles as $profile) { foreach($profiles as $profile) {
@ -137,19 +161,29 @@ function import_profiles($channel,$profiles) {
convert_oldfields($profile,'with','partner'); convert_oldfields($profile,'with','partner');
convert_oldfields($profile,'work','employment'); convert_oldfields($profile,'work','employment');
/**
// we are going to reset all profile photos to the original * @TODO we are going to reset all profile photos to the original
// somebody will have to fix this later and put all the applicable photos into the export * somebody will have to fix this later and put all the applicable
* photos into the export.
*/
$profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
$profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
create_table_from_array('profile',$profile);
create_table_from_array('profile', $profile);
} }
} }
} }
/**
function import_hublocs($channel,$hublocs,$seize,$moving = false) { * @brief Import hublocs.
*
* @param array $channel
* @param array $hublocs
* @param unknown $seize
* @param boolean $moving
*/
function import_hublocs($channel, $hublocs, $seize, $moving = false) {
if($channel && $hublocs) { if($channel && $hublocs) {
foreach($hublocs as $hubloc) { foreach($hublocs as $hubloc) {
@ -183,7 +217,7 @@ function import_hublocs($channel,$hublocs,$seize,$moving = false) {
if(($x = zot_gethub($arr,false)) === false) { if(($x = zot_gethub($arr,false)) === false) {
unset($hubloc['hubloc_id']); unset($hubloc['hubloc_id']);
create_table_from_array('hubloc',$hubloc); create_table_from_array('hubloc', $hubloc);
} }
else { else {
q("UPDATE hubloc set hubloc_primary = %d, hubloc_deleted = %d where hubloc_id = %d", q("UPDATE hubloc set hubloc_primary = %d, hubloc_deleted = %d where hubloc_id = %d",
@ -191,15 +225,18 @@ function import_hublocs($channel,$hublocs,$seize,$moving = false) {
intval($hubloc['hubloc_deleted']), intval($hubloc['hubloc_deleted']),
intval($x['hubloc_id']) intval($x['hubloc_id'])
); );
} }
} }
} }
} }
/**
* @brief Import things.
function import_objs($channel,$objs) { *
* @param array $channel
* @param array $objs
*/
function import_objs($channel, $objs) {
if($channel && $objs) { if($channel && $objs) {
foreach($objs as $obj) { foreach($objs as $obj) {
@ -214,21 +251,27 @@ function import_objs($channel,$objs) {
$obj['obj_channel'] = $channel['channel_id']; $obj['obj_channel'] = $channel['channel_id'];
if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) { if($baseurl && (strpos($obj['obj_url'], $baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']); $obj['obj_url'] = str_replace($baseurl, z_root(), $obj['obj_url']);
} }
if($obj['obj_imgurl']) { if($obj['obj_imgurl']) {
$x = import_xchan_photo($obj['obj_imgurl'],$channel['channel_hash'],true); $x = import_xchan_photo($obj['obj_imgurl'], $channel['channel_hash'], true);
$obj['obj_imgurl'] = $x[0]; $obj['obj_imgurl'] = $x[0];
} }
create_table_from_array('obj',$obj); create_table_from_array('obj', $obj);
} }
} }
} }
function sync_objs($channel,$objs) { /**
* @brief Import things.
*
* @param array $channel
* @param array $objs
*/
function sync_objs($channel, $objs) {
if($channel && $objs) { if($channel && $objs) {
foreach($objs as $obj) { foreach($objs as $obj) {
@ -251,8 +294,8 @@ function sync_objs($channel,$objs) {
$obj['obj_channel'] = $channel['channel_id']; $obj['obj_channel'] = $channel['channel_id'];
if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) { if($baseurl && (strpos($obj['obj_url'], $baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']); $obj['obj_url'] = str_replace($baseurl, z_root(), $obj['obj_url']);
} }
$exists = false; $exists = false;
@ -269,7 +312,7 @@ function sync_objs($channel,$objs) {
} }
if($obj['obj_imgurl']) { if($obj['obj_imgurl']) {
$x = import_xchan_photo($obj['obj_imgurl'],$channel['channel_hash'],true); $x = import_xchan_photo($obj['obj_imgurl'], $channel['channel_hash'], true);
$obj['obj_imgurl'] = $x[0]; $obj['obj_imgurl'] = $x[0];
} }
@ -287,17 +330,19 @@ function sync_objs($channel,$objs) {
} }
} }
else { else {
create_table_from_array('obj',$obj); create_table_from_array('obj', $obj);
} }
} }
} }
} }
/**
* @brief Import apps.
*
* @param array $channel
function import_apps($channel,$apps) { * @param array $apps
*/
function import_apps($channel, $apps) {
if($channel && $apps) { if($channel && $apps) {
foreach($apps as $app) { foreach($apps as $app) {
@ -311,13 +356,13 @@ function import_apps($channel,$apps) {
$app['app_channel'] = $channel['channel_id']; $app['app_channel'] = $channel['channel_id'];
if($app['app_photo']) { if($app['app_photo']) {
$x = import_xchan_photo($app['app_photo'],$channel['channel_hash'],true); $x = import_xchan_photo($app['app_photo'], $channel['channel_hash'], true);
$app['app_photo'] = $x[0]; $app['app_photo'] = $x[0];
} }
$hash = $app['app_id']; $hash = $app['app_id'];
create_table_from_array('app',$app); create_table_from_array('app', $app);
if($term) { if($term) {
$x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
@ -328,20 +373,22 @@ function import_apps($channel,$apps) {
foreach($term as $t) { foreach($term as $t) {
if(array_key_exists('type',$t)) if(array_key_exists('type',$t))
$t['ttype'] = $t['type']; $t['ttype'] = $t['type'];
store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['ttype'],escape_tags($t['term']),escape_tags($t['url'])); store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['ttype'],escape_tags($t['term']),escape_tags($t['url']));
} }
} }
} }
} }
} }
} }
/**
* @brief Sync apps.
function sync_apps($channel,$apps) { *
* @param array $channel
* @param array $apps
*/
function sync_apps($channel, $apps) {
if($channel && $apps) { if($channel && $apps) {
foreach($apps as $app) { foreach($apps as $app) {
@ -358,18 +405,18 @@ function sync_apps($channel,$apps) {
} }
if(array_key_exists('app_deleted',$app) && $app['app_deleted'] && $app['app_id']) { if(array_key_exists('app_deleted',$app) && $app['app_deleted'] && $app['app_id']) {
q("delete from app where app_id = '%s' and app_channel = %d", q("delete from app where app_id = '%s' and app_channel = %d",
dbesc($app['app_id']), dbesc($app['app_id']),
intval($channel['channel_id']) intval($channel['channel_id'])
); );
if($exists) { if($exists) {
q("delete from term where otype = %d and oid = %d", q("delete from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP), intval(TERM_OBJ_APP),
intval($exists['id']) intval($exists['id'])
); );
} }
continue; continue;
} }
unset($app['id']); unset($app['id']);
unset($app['app_channel']); unset($app['app_channel']);
@ -379,7 +426,7 @@ function sync_apps($channel,$apps) {
q("delete from term where otype = %d and oid = %d", q("delete from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP), intval(TERM_OBJ_APP),
intval($exists['id']) intval($exists['id'])
); );
} }
if((! $app['app_created']) || ($app['app_created'] <= NULL_DATE)) if((! $app['app_created']) || ($app['app_created'] <= NULL_DATE))
@ -440,9 +487,13 @@ function sync_apps($channel,$apps) {
} }
} }
/**
* @brief Import chatrooms.
function import_chatrooms($channel,$chatrooms) { *
* @param array $channel
* @param array $chatrooms
*/
function import_chatrooms($channel, $chatrooms) {
if($channel && $chatrooms) { if($channel && $chatrooms) {
foreach($chatrooms as $chatroom) { foreach($chatrooms as $chatroom) {
@ -457,14 +508,18 @@ function import_chatrooms($channel,$chatrooms) {
$chatroom['cr_aid'] = $channel['channel_account_id']; $chatroom['cr_aid'] = $channel['channel_account_id'];
$chatroom['cr_uid'] = $channel['channel_id']; $chatroom['cr_uid'] = $channel['channel_id'];
create_table_from_array('chatroom',$chatroom); create_table_from_array('chatroom', $chatroom);
} }
} }
} }
/**
* @brief Sync chatrooms.
function sync_chatrooms($channel,$chatrooms) { *
* @param array $channel
* @param array $chatrooms
*/
function sync_chatrooms($channel, $chatrooms) {
if($channel && $chatrooms) { if($channel && $chatrooms) {
foreach($chatrooms as $chatroom) { foreach($chatrooms as $chatroom) {
@ -473,13 +528,12 @@ function sync_chatrooms($channel,$chatrooms) {
continue; continue;
if(array_key_exists('cr_deleted',$chatroom) && $chatroom['cr_deleted']) { if(array_key_exists('cr_deleted',$chatroom) && $chatroom['cr_deleted']) {
q("delete from chatroom where cr_name = '%s' and cr_uid = %d", q("delete from chatroom where cr_name = '%s' and cr_uid = %d",
dbesc($chatroom['cr_name']), dbesc($chatroom['cr_name']),
intval($channel['channel_id']) intval($channel['channel_id'])
); );
continue; continue;
} }
unset($chatroom['cr_id']); unset($chatroom['cr_id']);
unset($chatroom['cr_aid']); unset($chatroom['cr_aid']);
@ -502,6 +556,7 @@ function sync_chatrooms($channel,$chatrooms) {
if($x) { if($x) {
if($x[0]['cr_edited'] >= $chatroom['cr_edited']) if($x[0]['cr_edited'] >= $chatroom['cr_edited'])
continue; continue;
$exists = true; $exists = true;
} }
$name = $chatroom['cr_name']; $name = $chatroom['cr_name'];
@ -517,21 +572,28 @@ function sync_chatrooms($channel,$chatrooms) {
} }
} }
else { else {
create_table_from_array('chatroom',$chatroom); create_table_from_array('chatroom', $chatroom);
} }
} }
} }
} }
/**
function import_items($channel,$items,$sync = false,$relocate = null) { * @brief Import items to channel.
*
* @param array $channel where to import to
* @param array $items
* @param boolean $sync
* @param array $relocate default null
*/
function import_items($channel, $items, $sync = false, $relocate = null) {
if($channel && $items) { if($channel && $items) {
$allow_code = channel_codeallowed($channel['channel_id']); $allow_code = channel_codeallowed($channel['channel_id']);
$deliver = false; // Don't deliver any messages or notifications when importing $deliver = false; // Don't deliver any messages or notifications when importing
foreach($items as $i) { foreach($items as $i) {
$item_result = false; $item_result = false;
@ -578,9 +640,17 @@ function import_items($channel,$items,$sync = false,$relocate = null) {
} }
} }
/**
function sync_items($channel,$items,$relocate = null) { * @brief Sync items to channel.
import_items($channel,$items,true,$relocate); *
* @see import_items
*
* @param array $channel where to import to
* @param array $items
* @param array $relocate default null
*/
function sync_items($channel, $items, $relocate = null) {
import_items($channel, $items, true, $relocate);
} }
@ -601,13 +671,19 @@ function import_item_ids($channel,$itemids) {
intval($r[0]['id']) intval($r[0]['id'])
); );
if(! $z) { if(! $z) {
\Zotlabs\Lib\IConfig::Set($r[0]['id'],'system',$i['service'],$i['sid'],true); IConfig::Set($r[0]['id'],'system',$i['service'],$i['sid'],true);
} }
} }
} }
} }
function import_events($channel,$events) { /**
* @brief Import events.
*
* @param array $channel
* @param array $events
*/
function import_events($channel, $events) {
if($channel && $events) { if($channel && $events) {
foreach($events as $event) { foreach($events as $event) {
@ -619,13 +695,18 @@ function import_events($channel,$events) {
convert_oldfields($event,'type','etype'); convert_oldfields($event,'type','etype');
convert_oldfields($event,'ignore','dismissed'); convert_oldfields($event,'ignore','dismissed');
create_table_from_array('event',$event); create_table_from_array('event', $event);
} }
} }
} }
/**
function sync_events($channel,$events) { * @brief Sync events.
*
* @param array $channel
* @param array $events
*/
function sync_events($channel, $events) {
if($channel && $events) { if($channel && $events) {
foreach($events as $event) { foreach($events as $event) {
@ -650,7 +731,6 @@ function sync_events($channel,$events) {
convert_oldfields($event,'type','etype'); convert_oldfields($event,'type','etype');
convert_oldfields($event,'ignore','dismissed'); convert_oldfields($event,'ignore','dismissed');
$exists = false; $exists = false;
$x = q("select * from event where event_hash = '%s' and uid = %d limit 1", $x = q("select * from event where event_hash = '%s' and uid = %d limit 1",
@ -660,6 +740,7 @@ function sync_events($channel,$events) {
if($x) { if($x) {
if($x[0]['edited'] >= $event['edited']) if($x[0]['edited'] >= $event['edited'])
continue; continue;
$exists = true; $exists = true;
} }
@ -674,15 +755,19 @@ function sync_events($channel,$events) {
} }
} }
else { else {
create_table_from_array('event',$event); create_table_from_array('event', $event);
} }
} }
} }
} }
/**
function import_menus($channel,$menus) { * @brief Import menus.
*
* @param array $channel
* @param array $menus
*/
function import_menus($channel, $menus) {
if($channel && $menus) { if($channel && $menus) {
foreach($menus as $menu) { foreach($menus as $menu) {
@ -701,7 +786,6 @@ function import_menus($channel,$menus) {
$m['menu_flags'] |= MENU_BOOKMARK; $m['menu_flags'] |= MENU_BOOKMARK;
if(in_array('system',$menu['flags'])) if(in_array('system',$menu['flags']))
$m['menu_flags'] |= MENU_SYSTEM; $m['menu_flags'] |= MENU_SYSTEM;
} }
$menu_id = menu_create($m); $menu_id = menu_create($m);
@ -733,12 +817,15 @@ function import_menus($channel,$menus) {
} }
} }
} }
} }
/**
function sync_menus($channel,$menus) { * @brief Sync menus.
*
* @param array $channel
* @param array $menus
*/
function sync_menus($channel, $menus) {
if($channel && $menus) { if($channel && $menus) {
foreach($menus as $menu) { foreach($menus as $menu) {
@ -795,7 +882,6 @@ function sync_menus($channel,$menus) {
foreach($menu['items'] as $it) { foreach($menu['items'] as $it) {
$mitem = array(); $mitem = array();
$mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']); $mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']); $mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']);
$mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']); $mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']);
@ -820,9 +906,13 @@ function sync_menus($channel,$menus) {
} }
} }
/**
* @brief Import likes.
function import_likes($channel,$likes) { *
* @param array $channel
* @param array $likes
*/
function import_likes($channel, $likes) {
if($channel && $likes) { if($channel && $likes) {
foreach($likes as $like) { foreach($likes as $like) {
if($like['deleted']) { if($like['deleted']) {
@ -850,7 +940,7 @@ function import_likes($channel,$likes) {
if($r) if($r)
continue; continue;
create_table_from_array('likes',$like); create_table_from_array('likes', $like);
} }
} }
} }
@ -877,14 +967,19 @@ function import_conv($channel,$convs) {
); );
if($r) if($r)
continue; continue;
create_table_from_array('conv',$conv); create_table_from_array('conv',$conv);
} }
} }
} }
/**
* @brief Import mails.
function import_mail($channel,$mails,$sync = false) { *
* @param array $channel
* @param array $mails
*/
function import_mail($channel, $mails, $sync = false) {
if($channel && $mails) { if($channel && $mails) {
foreach($mails as $mail) { foreach($mails as $mail) {
if(array_key_exists('flags',$mail) && in_array('deleted',$mail['flags'])) { if(array_key_exists('flags',$mail) && in_array('deleted',$mail['flags'])) {
@ -916,11 +1011,24 @@ function import_mail($channel,$mails,$sync = false) {
} }
} }
function sync_mail($channel,$mails) { /**
import_mail($channel,$mails,true); * @brief Synchronise mails.
*
* @see import_mail
* @param array $channel
* @param array $mails
*/
function sync_mail($channel, $mails) {
import_mail($channel, $mails, true);
} }
function sync_files($channel,$files) { /**
* @brief Synchronise files.
*
* @param array $channel
* @param array $files
*/
function sync_files($channel, $files) {
require_once('include/attach.php'); require_once('include/attach.php');
@ -964,7 +1072,6 @@ function sync_files($channel,$files) {
$att['aid'] = $channel['channel_account_id']; $att['aid'] = $channel['channel_account_id'];
$att['uid'] = $channel['channel_id']; $att['uid'] = $channel['channel_id'];
// check for duplicate folder names with the same parent. // check for duplicate folder names with the same parent.
// If we have a duplicate that doesn't match this hash value // If we have a duplicate that doesn't match this hash value
// change the name so that the contents won't be "covered over" // change the name so that the contents won't be "covered over"
@ -1009,7 +1116,7 @@ function sync_files($channel,$files) {
// end duplicate detection // end duplicate detection
// @fixme - update attachment structures if they are modified rather than created /// @FIXME update attachment structures if they are modified rather than created
$att['content'] = $newfname; $att['content'] = $newfname;
@ -1018,21 +1125,22 @@ function sync_files($channel,$files) {
// If the hash ever contains any escapable chars this could cause // If the hash ever contains any escapable chars this could cause
// problems. Currently it does not. // problems. Currently it does not.
// @TODO implement os_path /// @TODO implement os_path
if(!isset($att['os_path'])) if(!isset($att['os_path']))
$att['os_path'] = ''; $att['os_path'] = '';
if($attach_exists) { if($attach_exists) {
logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG); logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG);
if(! dbesc_array($att)) if(! dbesc_array($att))
continue; continue;
$str = ''; $str = '';
foreach($att as $k => $v) { foreach($att as $k => $v) {
if($str) if($str)
$str .= ","; $str .= ",";
$str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' ";
} $str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' ";
}
$r = dbq("update attach set " . $str . " where id = " . intval($attach_id) ); $r = dbq("update attach set " . $str . " where id = " . intval($attach_id) );
} }
else { else {
@ -1040,7 +1148,6 @@ function sync_files($channel,$files) {
create_table_from_array('attach',$att); create_table_from_array('attach',$att);
} }
// is this a directory? // is this a directory?
if($att['filetype'] === 'multipart/mixed' && $att['is_dir']) { if($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
@ -1049,7 +1156,6 @@ function sync_files($channel,$files) {
continue; continue;
} }
else { else {
// it's a file // it's a file
// for the sync version of this algorithm (as opposed to 'offline import') // for the sync version of this algorithm (as opposed to 'offline import')
// we will fetch the actual file from the source server so it can be // we will fetch the actual file from the source server so it can be
@ -1084,7 +1190,7 @@ function sync_files($channel,$files) {
} }
} }
if(! $attachment_stored) { if(! $attachment_stored) {
// @TODO should we queue this and retry or delete everything or what? /// @TODO should we queue this and retry or delete everything or what?
logger('attachment store failed',LOGGER_NORMAL,LOG_ERR); logger('attachment store failed',LOGGER_NORMAL,LOG_ERR);
} }
if($f['photo']) { if($f['photo']) {
@ -1128,7 +1234,6 @@ function sync_files($channel,$files) {
else else
$p['content'] = base64_decode($p['content']); $p['content'] = base64_decode($p['content']);
if(!isset($p['display_path'])) if(!isset($p['display_path']))
$p['display_path'] = ''; $p['display_path'] = '';
@ -1138,17 +1243,18 @@ function sync_files($channel,$files) {
intval($channel['channel_id']) intval($channel['channel_id'])
); );
if($exists) { if($exists) {
if(! dbesc_array($p)) if(! dbesc_array($p))
continue; continue;
$str = '';
foreach($p as $k => $v) { $str = '';
if($str) foreach($p as $k => $v) {
$str .= ","; if($str)
$str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' "; $str .= ",";
}
$r = dbq("update photo set " . $str . " where id = " . intval($exists[0]['id']) ); $str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' ";
}
$r = dbq("update photo set " . $str . " where id = " . intval($exists[0]['id']) );
} }
else { else {
create_attach_from_array('photo',$p); create_attach_from_array('photo',$p);
@ -1164,9 +1270,17 @@ function sync_files($channel,$files) {
} }
} }
/**
function convert_oldfields(&$arr,$old,$new) { * @brief Rename a key in an array.
if(array_key_exists($old,$arr)) { *
* Replaces $old key with $new key in $arr.
*
* @param array[in,out] $arr The array where to work on
* @param string $old The old key in the array
* @param string $new The new key in the array
*/
function convert_oldfields(&$arr, $old, $new) {
if(array_key_exists($old, $arr)) {
$arr[$new] = $arr[$old]; $arr[$new] = $arr[$old];
unset($arr[$old]); unset($arr[$old]);
} }
@ -1240,6 +1354,7 @@ function scan_webpage_elements($path, $type, $cloud = false) {
} }
} }
} }
return $elements; return $elements;
} }
@ -1256,26 +1371,26 @@ function import_webpage_element($element, $channel, $type) {
$arr['item_type'] = ITEM_TYPE_WEBPAGE; $arr['item_type'] = ITEM_TYPE_WEBPAGE;
$namespace = 'WEBPAGE'; $namespace = 'WEBPAGE';
$name = $element['pagelink']; $name = $element['pagelink'];
if($name) { if($name) {
require_once('library/urlify/URLify.php'); require_once('library/urlify/URLify.php');
$name = strtolower(\URLify::transliterate($name)); $name = strtolower(\URLify::transliterate($name));
} }
$arr['title'] = $element['title']; $arr['title'] = $element['title'];
$arr['term'] = $element['term']; $arr['term'] = $element['term'];
$arr['layout_mid'] = ''; // by default there is no layout associated with the page $arr['layout_mid'] = ''; // by default there is no layout associated with the page
// If a layout was specified, find it in the database and get its info. If // If a layout was specified, find it in the database and get its info. If
// it does not exist, leave layout_mid empty // it does not exist, leave layout_mid empty
if($element['layout'] !== '') { if($element['layout'] !== '') {
$liid = q("select iid from iconfig where k = 'PDL' and v = '%s' and cat = 'system'", $liid = q("select iid from iconfig where k = 'PDL' and v = '%s' and cat = 'system'",
dbesc($element['layout']) dbesc($element['layout'])
); );
if($liid) { if($liid) {
$linfo = q("select mid from item where id = %d", $linfo = q("select mid from item where id = %d",
intval($liid[0]['iid']) intval($liid[0]['iid'])
); );
$arr['layout_mid'] = $linfo[0]['mid']; $arr['layout_mid'] = $linfo[0]['mid'];
} }
} }
break; break;
// //
// LAYOUTS // LAYOUTS
@ -1352,8 +1467,7 @@ function import_webpage_element($element, $channel, $type) {
intval(local_channel()) intval(local_channel())
); );
\Zotlabs\Lib\IConfig::Set($arr,'system',$namespace,(($name) ? $name : substr($arr['mid'],0,16)),true); IConfig::Set($arr,'system',$namespace,(($name) ? $name : substr($arr['mid'],0,16)),true);
if($i) { if($i) {
$arr['id'] = $i[0]['id']; $arr['id'] = $i[0]['id'];
@ -1374,7 +1488,7 @@ function import_webpage_element($element, $channel, $type) {
} }
if($x && $x['success']) { if($x && $x['success']) {
$item_id = $x['item_id']; //$item_id = $x['item_id'];
//update_remote_id($channel, $item_id, $arr['item_type'], $name, $namespace, $remote_id, $arr['mid']); //update_remote_id($channel, $item_id, $arr['item_type'], $name, $namespace, $remote_id, $arr['mid']);
$element['import_success'] = 1; $element['import_success'] = 1;
} }
@ -1387,8 +1501,8 @@ function import_webpage_element($element, $channel, $type) {
function get_webpage_elements($channel, $type = 'all') { function get_webpage_elements($channel, $type = 'all') {
$elements = array(); $elements = array();
if(!$channel['channel_id']) { if(!$channel['channel_id']) {
return null; return null;
} }
switch($type) { switch($type) {
case 'all': case 'all':
@ -1399,7 +1513,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner); $sql_extra = item_permissions_sql($owner);
$r = q("select * from iconfig left join item on iconfig.iid = item.id $r = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d
$sql_extra order by item.created desc", $sql_extra order by item.created desc",
@ -1439,7 +1552,6 @@ function get_webpage_elements($channel, $type = 'all') {
); );
$elements['pages'][] = $element_arr; $elements['pages'][] = $element_arr;
} }
} }
if($type !== 'all') { if($type !== 'all') {
break; break;
@ -1451,7 +1563,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner); $sql_extra = item_permissions_sql($owner);
$r = q("select * from iconfig left join item on iconfig.iid = item.id $r = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d
$sql_extra order by item.created desc", $sql_extra order by item.created desc",
@ -1459,23 +1570,21 @@ function get_webpage_elements($channel, $type = 'all') {
intval(ITEM_TYPE_PDL) intval(ITEM_TYPE_PDL)
); );
$layouts = null;
if($r) { if($r) {
$elements['layouts'] = array(); $elements['layouts'] = array();
$layouts = array();
foreach($r as $rr) { foreach($r as $rr) {
unobscure($rr); unobscure($rr);
$elements['layouts'][] = array( $elements['layouts'][] = array(
'type' => 'layout', 'type' => 'layout',
'description' => $rr['title'], // description of the layout 'description' => $rr['title'], // description of the layout
'body' => $rr['body'], 'body' => $rr['body'],
'created' => $rr['created'], 'created' => $rr['created'],
'edited' => $rr['edited'], 'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'], 'mimetype' => $rr['mimetype'],
'name' => $rr['v'], // name of reference for the layout 'name' => $rr['v'], // name of reference for the layout
'mid' => $rr['mid'], 'mid' => $rr['mid'],
); );
} }
} }
@ -1490,7 +1599,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner); $sql_extra = item_permissions_sql($owner);
$r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig $r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig
left join item on iconfig.iid = item.id left join item on iconfig.iid = item.id
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
@ -1499,26 +1607,23 @@ function get_webpage_elements($channel, $type = 'all') {
intval(ITEM_TYPE_BLOCK) intval(ITEM_TYPE_BLOCK)
); );
$blocks = null;
if($r) { if($r) {
$elements['blocks'] = array(); $elements['blocks'] = array();
$blocks = array();
foreach($r as $rr) { foreach($r as $rr) {
unobscure($rr); unobscure($rr);
$elements['blocks'][] = array( $elements['blocks'][] = array(
'type' => 'block', 'type' => 'block',
'title' => $rr['title'], 'title' => $rr['title'],
'body' => $rr['body'], 'body' => $rr['body'],
'created' => $rr['created'], 'created' => $rr['created'],
'edited' => $rr['edited'], 'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'], 'mimetype' => $rr['mimetype'],
'name' => $rr['v'], 'name' => $rr['v'],
'mid' => $rr['mid'] 'mid' => $rr['mid']
); );
} }
} }
if($type !== 'all') { if($type !== 'all') {
@ -1528,11 +1633,18 @@ function get_webpage_elements($channel, $type = 'all') {
default: default:
break; break;
} }
return $elements; return $elements;
} }
/* creates a compressed zip file */ /**
* @brief Create a compressed zip file.
*
* @param array $files List of files to put in zip file
* @param string $destination
* @param boolean $overwrite
* @return boolean Success status
*/
function create_zip_file($files = array(), $destination = '', $overwrite = false) { function create_zip_file($files = array(), $destination = '', $overwrite = false) {
// if the zip file already exists and overwrite is false, return false // if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) { if(file_exists($destination) && !$overwrite) {
@ -1555,7 +1667,7 @@ function create_zip_file($files = array(), $destination = '', $overwrite = false
if(count($valid_files)) { if(count($valid_files)) {
//create the archive //create the archive
$zip = new ZipArchive(); $zip = new ZipArchive();
if($zip->open($destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) { if($zip->open($destination, $overwrite ? ZipArchive::OVERWRITE : ZipArchive::CREATE) !== true) {
return false; return false;
} }
// add the files // add the files

View File

@ -3048,7 +3048,15 @@ function array2XML($obj, $array) {
} }
} }
/**
* @brief Inserts an array into $table.
*
* @TODO Why is this function in include/text.php?
*
* @param string $table
* @param array $arr
* @return boolean|PDOStatement
*/
function create_table_from_array($table, $arr) { function create_table_from_array($table, $arr) {
if(! ($arr && $table)) if(! ($arr && $table))

2321
library/bootstrap/css/bootstrap-grid.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,334 @@
html {
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
*,
*::before,
*::after {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
@-ms-viewport {
width: device-width;
}
body {
margin: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 1rem;
font-weight: normal;
line-height: 1.5;
color: #292b2c;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: none !important;
}
hr {
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: .5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: bold;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #0275d8;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #014c8c;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
a,
area,
button,
[role="button"],
input,
label,
select,
summary,
textarea {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #636c72;
text-align: left;
caption-side: bottom;
}
th {
text-align: left;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
input[type="radio"]:disabled,
input[type="checkbox"]:disabled {
cursor: not-allowed;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
html{-webkit-box-sizing:border-box;box-sizing:border-box;font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}@-ms-viewport{width:device-width}body{margin:0;font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#292b2c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0275d8;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#014c8c;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#636c72;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}/*# sourceMappingURL=bootstrap-reboot.min.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../scss/_reboot.scss","dist/css/bootstrap-reboot.css","bootstrap-reboot.css","../../scss/mixins/_hover.scss"],"names":[],"mappings":"AAoBA,KACE,mBAAA,WAAA,WAAA,WACA,YAAA,WACA,YAAA,KACA,yBAAA,KACA,qBAAA,KACA,mBAAA,UACA,4BAAA,YAGF,ECjBA,QADA,SDqBE,mBAAA,QAAA,WAAA,QAKA,cAAgB,MAAA,aASlB,KACE,OAAA,EACA,YAAA,aAAA,CAAA,SAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WACA,UAAA,KACA,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KExBF,sBFiCE,QAAA,YASF,GACE,mBAAA,YAAA,WAAA,YACA,OAAA,EACA,SAAA,QAYF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KC5CF,0BDsDA,YAEE,gBAAA,UACA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QClDF,GDqDA,GCtDA,GDyDE,WAAA,EACA,cAAA,KAGF,MCrDA,MACA,MAFA,MD0DE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,IACE,WAAA,OAGF,ECtDA,ODwDE,YAAA,OAGF,MACE,UAAA,IAQF,IC3DA,ID6DE,SAAA,SACA,UAAA,IACA,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YACA,6BAAA,QGhLE,QHmLA,MAAA,QACA,gBAAA,UAUJ,8BACE,MAAA,QACA,gBAAA,KGrLE,oCAAA,oCHwLA,MAAA,QACA,gBAAA,KANJ,oCAUI,QAAA,EC7DJ,KACA,IDqEA,ICpEA,KDwEE,YAAA,SAAA,CAAA,UACA,UAAA,IAGF,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,eACE,SAAA,OC/EF,cD6FA,EC/FA,KACA,OAEA,MACA,MACA,OACA,QACA,SDiGE,iBAAA,aAAA,aAAA,aAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAGF,GAEE,WAAA,KAQF,MAEE,QAAA,aACA,cAAA,MAOF,aACE,QAAA,IAAA,OACA,QAAA,IAAA,KAAA,yBC3GF,OD8GA,MC5GA,SADA,OAEA,SDgHE,OAAA,EACA,YAAA,QACA,UAAA,QACA,YAAA,QAGF,OC9GA,MDgHE,SAAA,QAGF,OC9GA,ODgHE,eAAA,KC1GF,aACA,cD+GA,OCjHA,mBDqHE,mBAAA,OC9GF,gCACA,+BACA,gCDgHA,yBAIE,QAAA,EACA,aAAA,KC/GF,qBDkHA,kBAEE,mBAAA,WAAA,WAAA,WACA,QAAA,EC9GF,8BD2GA,2BASI,OAAA,YAKJ,iBCnHA,2BACA,kBAFA,iBD6HE,mBAAA,QAGF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,MACA,UAAA,OACA,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SErIF,yCDMA,yCDqIE,OAAA,KEtIF,cF8IE,eAAA,KACA,mBAAA,KE1IF,4CDMA,yCD6IE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UAGF,SACE,QAAA,KEvJF,SF6JE,QAAA"}

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013-2014 Yuku Takahashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -136,10 +136,6 @@ if (typeof jQuery === 'undefined') {
return Object.prototype.toString.call(obj) === '[object String]'; return Object.prototype.toString.call(obj) === '[object String]';
}; };
var isFunction = function (obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};
var uniqueId = 0; var uniqueId = 0;
function Completer(element, option) { function Completer(element, option) {
@ -147,32 +143,46 @@ if (typeof jQuery === 'undefined') {
this.id = 'textcomplete' + uniqueId++; this.id = 'textcomplete' + uniqueId++;
this.strategies = []; this.strategies = [];
this.views = []; this.views = [];
this.option = $.extend({}, Completer._getDefaults(), option); this.option = $.extend({}, Completer.defaults, option);
if (!this.$el.is('input[type=text]') && !this.$el.is('input[type=search]') && !this.$el.is('textarea') && !element.isContentEditable && element.contentEditable != 'true') { if (!this.$el.is('input[type=text]') && !this.$el.is('input[type=search]') && !this.$el.is('textarea') && !element.isContentEditable && element.contentEditable != 'true') {
throw new Error('textcomplete must be called on a Textarea or a ContentEditable.'); throw new Error('textcomplete must be called on a Textarea or a ContentEditable.');
} }
if (element === document.activeElement) { // use ownerDocument to fix iframe / IE issues
if (element === element.ownerDocument.activeElement) {
// element has already been focused. Initialize view objects immediately. // element has already been focused. Initialize view objects immediately.
this.initialize() this.initialize()
} else { } else {
// Initialize view objects lazily. // Initialize view objects lazily.
var self = this; var self = this;
this.$el.one('focus.' + this.id, function () { self.initialize(); }); this.$el.one('focus.' + this.id, function () { self.initialize(); });
// Special handling for CKEditor: lazy init on instance load
if ((!this.option.adapter || this.option.adapter == 'CKEditor') && typeof CKEDITOR != 'undefined' && (this.$el.is('textarea'))) {
CKEDITOR.on("instanceReady", function(event) {
event.editor.once("focus", function(event2) {
// replace the element with the Iframe element and flag it as CKEditor
self.$el = $(event.editor.editable().$);
if (!self.option.adapter) {
self.option.adapter = $.fn.textcomplete['CKEditor'];
self.option.ckeditor_instance = event.editor;
}
self.initialize();
});
});
}
} }
} }
Completer._getDefaults = function () { Completer.defaults = {
if (!Completer.DEFAULTS) { appendTo: 'body',
Completer.DEFAULTS = { className: '', // deprecated option
appendTo: $('body'), dropdownClassName: 'dropdown-menu textcomplete-dropdown',
zIndex: '100' maxCount: 10,
}; zIndex: '100',
} rightEdgeOffset: 30
};
return Completer.DEFAULTS;
}
$.extend(Completer.prototype, { $.extend(Completer.prototype, {
// Public properties // Public properties
@ -184,12 +194,26 @@ if (typeof jQuery === 'undefined') {
adapter: null, adapter: null,
dropdown: null, dropdown: null,
$el: null, $el: null,
$iframe: null,
// Public methods // Public methods
// -------------- // --------------
initialize: function () { initialize: function () {
var element = this.$el.get(0); var element = this.$el.get(0);
// check if we are in an iframe
// we need to alter positioning logic if using an iframe
if (this.$el.prop('ownerDocument') !== document && window.frames.length) {
for (var iframeIndex = 0; iframeIndex < window.frames.length; iframeIndex++) {
if (this.$el.prop('ownerDocument') === window.frames[iframeIndex].document) {
this.$iframe = $(window.frames[iframeIndex].frameElement);
break;
}
}
}
// Initialize view objects. // Initialize view objects.
this.dropdown = new $.fn.textcomplete.Dropdown(element, this, this.option); this.dropdown = new $.fn.textcomplete.Dropdown(element, this, this.option);
var Adapter, viewName; var Adapter, viewName;
@ -281,7 +305,7 @@ if (typeof jQuery === 'undefined') {
var strategy = this.strategies[i]; var strategy = this.strategies[i];
var context = strategy.context(text); var context = strategy.context(text);
if (context || context === '') { if (context || context === '') {
var matchRegexp = isFunction(strategy.match) ? strategy.match(text) : strategy.match; var matchRegexp = $.isFunction(strategy.match) ? strategy.match(text) : strategy.match;
if (isString(context)) { text = context; } if (isString(context)) { text = context; }
var match = text.match(matchRegexp); var match = text.match(matchRegexp);
if (match) { return [strategy, match[strategy.index], match]; } if (match) { return [strategy, match[strategy.index], match]; }
@ -399,7 +423,7 @@ if (typeof jQuery === 'undefined') {
var $parent = option.appendTo; var $parent = option.appendTo;
if (!($parent instanceof $)) { $parent = $($parent); } if (!($parent instanceof $)) { $parent = $($parent); }
var $el = $('<ul></ul>') var $el = $('<ul></ul>')
.addClass('dropdown-menu textcomplete-dropdown') .addClass(option.dropdownClassName)
.attr('id', 'textcomplete-dropdown-' + option._oid) .attr('id', 'textcomplete-dropdown-' + option._oid)
.css({ .css({
display: 'none', display: 'none',
@ -422,7 +446,7 @@ if (typeof jQuery === 'undefined') {
footer: null, footer: null,
header: null, header: null,
id: null, id: null,
maxCount: 10, maxCount: null,
placement: '', placement: '',
shown: false, shown: false,
data: [], // Shown zipped data. data: [], // Shown zipped data.
@ -445,8 +469,8 @@ if (typeof jQuery === 'undefined') {
render: function (zippedData) { render: function (zippedData) {
var contentsHtml = this._buildContents(zippedData); var contentsHtml = this._buildContents(zippedData);
var unzippedData = $.map(this.data, function (d) { return d.value; }); var unzippedData = $.map(zippedData, function (d) { return d.value; });
if (this.data.length) { if (zippedData.length) {
var strategy = zippedData[0].strategy; var strategy = zippedData[0].strategy;
if (strategy.id) { if (strategy.id) {
this.$el.attr('data-strategy', strategy.id); this.$el.attr('data-strategy', strategy.id);
@ -785,7 +809,10 @@ if (typeof jQuery === 'undefined') {
var windowScrollBottom = $window.scrollTop() + $window.height(); var windowScrollBottom = $window.scrollTop() + $window.height();
var height = this.$el.height(); var height = this.$el.height();
if ((this.$el.position().top + height) > windowScrollBottom) { if ((this.$el.position().top + height) > windowScrollBottom) {
this.$el.offset({top: windowScrollBottom - height}); // only do this if we are not in an iframe
if (!this.completer.$iframe) {
this.$el.offset({top: windowScrollBottom - height});
}
} }
}, },
@ -794,7 +821,7 @@ if (typeof jQuery === 'undefined') {
// to the document width so we don't know if we would have overrun it. As a heuristic to avoid that clipping // to the document width so we don't know if we would have overrun it. As a heuristic to avoid that clipping
// (which makes our elements wrap onto the next line and corrupt the next item), if we're close to the right // (which makes our elements wrap onto the next line and corrupt the next item), if we're close to the right
// edge, move left. We don't know how far to move left, so just keep nudging a bit. // edge, move left. We don't know how far to move left, so just keep nudging a bit.
var tolerance = 30; // pixels. Make wider than vertical scrollbar because we might not be able to use that space. var tolerance = this.option.rightEdgeOffset; // pixels. Make wider than vertical scrollbar because we might not be able to use that space.
var lastOffset = this.$el.offset().left, offset; var lastOffset = this.$el.offset().left, offset;
var width = this.$el.width(); var width = this.$el.width();
var maxLeft = $window.width() - tolerance; var maxLeft = $window.width() - tolerance;
@ -1005,8 +1032,14 @@ if (typeof jQuery === 'undefined') {
switch (clickEvent.keyCode) { switch (clickEvent.keyCode) {
case 9: // TAB case 9: // TAB
case 13: // ENTER case 13: // ENTER
case 16: // SHIFT
case 17: // CTRL
case 18: // ALT
case 33: // PAGEUP
case 34: // PAGEDOWN
case 40: // DOWN case 40: // DOWN
case 38: // UP case 38: // UP
case 27: // ESC
return true; return true;
} }
if (clickEvent.ctrlKey) switch (clickEvent.keyCode) { if (clickEvent.ctrlKey) switch (clickEvent.keyCode) {
@ -1040,12 +1073,14 @@ if (typeof jQuery === 'undefined') {
var pre = this.getTextFromHeadToCaret(); var pre = this.getTextFromHeadToCaret();
var post = this.el.value.substring(this.el.selectionEnd); var post = this.el.value.substring(this.el.selectionEnd);
var newSubstr = strategy.replace(value, e); var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') { if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) { if ($.isArray(newSubstr)) {
post = newSubstr[1] + post; post = newSubstr[1] + post;
newSubstr = newSubstr[0]; newSubstr = newSubstr[0];
} }
pre = pre.replace(strategy.match, newSubstr); regExp = $.isFunction(strategy.match) ? strategy.match(pre) : strategy.match;
pre = pre.replace(regExp, newSubstr);
this.$el.val(pre + post); this.$el.val(pre + post);
this.el.selectionStart = this.el.selectionEnd = pre.length; this.el.selectionStart = this.el.selectionEnd = pre.length;
} }
@ -1062,7 +1097,8 @@ if (typeof jQuery === 'undefined') {
var p = $.fn.textcomplete.getCaretCoordinates(this.el, this.el.selectionStart); var p = $.fn.textcomplete.getCaretCoordinates(this.el, this.el.selectionStart);
return { return {
top: p.top + this._calculateLineHeight() - this.$el.scrollTop(), top: p.top + this._calculateLineHeight() - this.$el.scrollTop(),
left: p.left - this.$el.scrollLeft() left: p.left - this.$el.scrollLeft(),
lineHeight: this._calculateLineHeight()
}; };
}, },
@ -1111,12 +1147,14 @@ if (typeof jQuery === 'undefined') {
var pre = this.getTextFromHeadToCaret(); var pre = this.getTextFromHeadToCaret();
var post = this.el.value.substring(pre.length); var post = this.el.value.substring(pre.length);
var newSubstr = strategy.replace(value, e); var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') { if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) { if ($.isArray(newSubstr)) {
post = newSubstr[1] + post; post = newSubstr[1] + post;
newSubstr = newSubstr[0]; newSubstr = newSubstr[0];
} }
pre = pre.replace(strategy.match, newSubstr); regExp = $.isFunction(strategy.match) ? strategy.match(pre) : strategy.match;
pre = pre.replace(regExp, newSubstr);
this.$el.val(pre + post); this.$el.val(pre + post);
this.el.focus(); this.el.focus();
var range = this.el.createTextRange(); var range = this.el.createTextRange();
@ -1162,30 +1200,35 @@ if (typeof jQuery === 'undefined') {
// When an dropdown item is selected, it is executed. // When an dropdown item is selected, it is executed.
select: function (value, strategy, e) { select: function (value, strategy, e) {
var pre = this.getTextFromHeadToCaret(); var pre = this.getTextFromHeadToCaret();
var sel = window.getSelection() // use ownerDocument instead of window to support iframes
var sel = this.el.ownerDocument.getSelection();
var range = sel.getRangeAt(0); var range = sel.getRangeAt(0);
var selection = range.cloneRange(); var selection = range.cloneRange();
selection.selectNodeContents(range.startContainer); selection.selectNodeContents(range.startContainer);
var content = selection.toString(); var content = selection.toString();
var post = content.substring(range.startOffset); var post = content.substring(range.startOffset);
var newSubstr = strategy.replace(value, e); var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') { if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) { if ($.isArray(newSubstr)) {
post = newSubstr[1] + post; post = newSubstr[1] + post;
newSubstr = newSubstr[0]; newSubstr = newSubstr[0];
} }
pre = pre.replace(strategy.match, newSubstr); regExp = $.isFunction(strategy.match) ? strategy.match(pre) : strategy.match;
pre = pre.replace(regExp, newSubstr)
.replace(/ $/, "&nbsp"); // &nbsp necessary at least for CKeditor to not eat spaces
range.selectNodeContents(range.startContainer); range.selectNodeContents(range.startContainer);
range.deleteContents(); range.deleteContents();
// create temporary elements // create temporary elements
var preWrapper = document.createElement("div"); var preWrapper = this.el.ownerDocument.createElement("div");
preWrapper.innerHTML = pre; preWrapper.innerHTML = pre;
var postWrapper = document.createElement("div"); var postWrapper = this.el.ownerDocument.createElement("div");
postWrapper.innerHTML = post; postWrapper.innerHTML = post;
// create the fragment thats inserted // create the fragment thats inserted
var fragment = document.createDocumentFragment(); var fragment = this.el.ownerDocument.createDocumentFragment();
var childNode; var childNode;
var lastOfPre; var lastOfPre;
while (childNode = preWrapper.firstChild) { while (childNode = preWrapper.firstChild) {
@ -1218,8 +1261,8 @@ if (typeof jQuery === 'undefined') {
// //
// Dropdown's position will be decided using the result. // Dropdown's position will be decided using the result.
_getCaretRelativePosition: function () { _getCaretRelativePosition: function () {
var range = window.getSelection().getRangeAt(0).cloneRange(); var range = this.el.ownerDocument.getSelection().getRangeAt(0).cloneRange();
var node = document.createElement('span'); var node = this.el.ownerDocument.createElement('span');
range.insertNode(node); range.insertNode(node);
range.selectNodeContents(node); range.selectNodeContents(node);
range.deleteContents(); range.deleteContents();
@ -1228,6 +1271,17 @@ if (typeof jQuery === 'undefined') {
position.left -= this.$el.offset().left; position.left -= this.$el.offset().left;
position.top += $node.height() - this.$el.offset().top; position.top += $node.height() - this.$el.offset().top;
position.lineHeight = $node.height(); position.lineHeight = $node.height();
// special positioning logic for iframes
// this is typically used for contenteditables such as tinymce or ckeditor
if (this.completer.$iframe) {
var iframePosition = this.completer.$iframe.offset();
position.top += iframePosition.top;
position.left += iframePosition.left;
//subtract scrollTop from element in iframe
position.top -= this.$el.scrollTop();
}
$node.remove(); $node.remove();
return position; return position;
}, },
@ -1241,7 +1295,7 @@ if (typeof jQuery === 'undefined') {
// this.getTextFromHeadToCaret() // this.getTextFromHeadToCaret()
// // => ' wor' // not '<b>hello</b> wor' // // => ' wor' // not '<b>hello</b> wor'
getTextFromHeadToCaret: function () { getTextFromHeadToCaret: function () {
var range = window.getSelection().getRangeAt(0); var range = this.el.ownerDocument.getSelection().getRangeAt(0);
var selection = range.cloneRange(); var selection = range.cloneRange();
selection.selectNodeContents(range.startContainer); selection.selectNodeContents(range.startContainer);
return selection.toString().substring(0, range.startOffset); return selection.toString().substring(0, range.startOffset);
@ -1251,6 +1305,39 @@ if (typeof jQuery === 'undefined') {
$.fn.textcomplete.ContentEditable = ContentEditable; $.fn.textcomplete.ContentEditable = ContentEditable;
}(jQuery); }(jQuery);
// NOTE: TextComplete plugin has contenteditable support but it does not work
// fine especially on old IEs.
// Any pull requests are REALLY welcome.
+function ($) {
'use strict';
// CKEditor adapter
// =======================
//
// Adapter for CKEditor, based on contenteditable elements.
function CKEditor (element, completer, option) {
this.initialize(element, completer, option);
}
$.extend(CKEditor.prototype, $.fn.textcomplete.ContentEditable.prototype, {
_bindEvents: function () {
var $this = this;
this.option.ckeditor_instance.on('key', function(event) {
var domEvent = event.data;
$this._onKeyup(domEvent);
if ($this.completer.dropdown.shown && $this._skipSearch(domEvent)) {
return false;
}
}, null, null, 1); // 1 = Priority = Important!
// we actually also need the native event, as the CKEditor one is happening to late
this.$el.on('keyup.' + this.id, $.proxy(this._onKeyup, this));
},
});
$.fn.textcomplete.CKEditor = CKEditor;
}(jQuery);
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) 2015 Jonathan Ong me@jongleberry.com // Copyright (c) 2015 Jonathan Ong me@jongleberry.com

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -67,10 +67,6 @@ code {
white-space: normal; white-space: normal;
} }
.panel-group {
margin-bottom: 0px;
}
/* Bootstrap assumes that checkboxes are on the left of labels, while it's usually the opposite in Red */ /* Bootstrap assumes that checkboxes are on the left of labels, while it's usually the opposite in Red */
.field.checkbox input[type="checkbox"] { margin-left: 0px; } .field.checkbox input[type="checkbox"] { margin-left: 0px; }
.field.checkbox label { padding-left: 0px; font-weight: 700} .field.checkbox label { padding-left: 0px; font-weight: 700}

View File

@ -7,6 +7,11 @@
margin-top: 0px; margin-top: 0px;
} }
.widget .active .wall-item-ago,
.widget .active .dropdown-sub-text {
color: #fff;
}
.tags { .tags {
word-wrap: break-word; word-wrap: break-word;
} }

View File

@ -693,39 +693,6 @@ div.jGrowl div.jGrowl-notification {
min-height: 60px; min-height: 60px;
} }
#recip-ac .autocomplete,
#poke-recip-ac .autocomplete,
#id-name-ac .autocomplete,
#contact-search-ac .autocomplete {
margin-top: 2px;
margin-left: $radius;
margin-right: $radius;
border: 1px solid #666;
border-top: none;
}
.autocomplete {
color: $font_colour;
cursor: pointer;
text-align: left;
max-height: 350px;
overflow: auto;
border-bottom-left-radius: $radius;
border-bottom-right-radius: $radius;
}
.autocomplete .selected {
background: #eee;
}
.autocomplete div {
padding: 2px 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.jslider .jslider-scale ins { .jslider .jslider-scale ins {
color: #333; color: #333;
font-size: 0.9rem; font-size: 0.9rem;
@ -1095,20 +1062,10 @@ img.mail-conv-sender-photo {
.wall-item-ago, .wall-item-ago,
a:hover .wall-item-ago, .dropdown-sub-text {
.dropdown-sub-text,
a:hover .dropdown-sub-text {
color: #777; color: #777;
} }
.active .wall-item-ago,
a.active:hover .wall-item-ago,
.active .dropdown-sub-text,
a:active .dropdown-sub-text,
a.active:hover .dropdown-sub-text {
color: #fff;
}
.wall-item-content, .wall-item-content,
.mail-conv-body, .mail-conv-body,
.page-body, .page-body,
@ -1393,6 +1350,7 @@ blockquote {
} }
.dropdown-menu { .dropdown-menu {
color: $font_colour;
font-size: 0.9rem; font-size: 0.9rem;
border-radius: $radius; border-radius: $radius;
} }
@ -1401,6 +1359,21 @@ blockquote {
border-radius: $radius; border-radius: $radius;
} }
.dropdown-item {
color: $font_colour;
}
.dropdown-item:active,
.dropdown-item:focus,
.dropdown-item:hover,
.textcomplete-item:focus .dropdown-item,
.textcomplete-item:hover .dropdown-item,
.textcomplete-item.active .dropdown-item,
.textcomplete-item:active .dropdown-item {
color: $font_colour;
background-color: $item_colour;
}
.bg-inverse { .bg-inverse {
background-color: $nav_bg !important; background-color: $nav_bg !important;
} }