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;
if($import_posts)
$api_path .= '&posts=1';
$binary = false;
$redirects = 0;
$opts = array('http_auth' => $email . ':' . $password);
@ -104,8 +105,8 @@ class Import extends \Zotlabs\Web\Controller {
$data = json_decode($data,true);
// logger('import: data: ' . print_r($data,true));
// print_r($data);
//logger('import: data: ' . print_r($data,true));
//print_r($data);
if(! array_key_exists('compatibility',$data)) {
call_hooks('import_foreign_channel_data',$data);
@ -248,7 +249,7 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 6');
// import xchans
$xchans = $data['xchan'];
if($xchans) {
foreach($xchans as $xchan) {
@ -292,13 +293,11 @@ class Import extends \Zotlabs\Web\Controller {
dbesc($photodate),
dbesc($xchan['xchan_hash'])
);
}
logger('import step 7');
}
$friends = 0;
$feeds = 0;
@ -367,19 +366,20 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 8');
}
// import groups
$groups = $data['group'];
if($groups) {
$saved = array();
foreach($groups as $group) {
$saved[$group['hash']] = array('old' => $group['id']);
if(array_key_exists('name',$group)) {
if(array_key_exists('name', $group)) {
$group['gname'] = $group['name'];
unset($group['name']);
}
unset($group['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",
intval($channel['channel_id'])
@ -391,7 +391,7 @@ class Import extends \Zotlabs\Web\Controller {
}
}
// import group members
$group_members = $data['group_member'];
if($group_members) {
foreach($group_members as $group_member) {
@ -401,7 +401,7 @@ class Import extends \Zotlabs\Web\Controller {
if($x['old'] == $group_member['gid'])
$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);
if(array_key_exists('item_id',$data) && $data['item_id'])
import_item_ids($channel,$data['item_id']);
@ -490,7 +489,7 @@ class Import extends \Zotlabs\Web\Controller {
function get() {
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 '';
}

View File

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

View File

@ -236,11 +236,10 @@ class Wiki extends \Zotlabs\Web\Controller {
$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
if($mimeType == 'text/bbcode') {
$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'] === '') {
notice( t('Error creating wiki. Invalid name.') . EOL);
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

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) {
$store = [
@ -25,8 +36,7 @@ function hubloc_store_lowlevel($arr) {
'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.
if(count($x) > 1) {
$d1 = datetime_convert('UTC','UTC',$x[0]['c']);
$d2 = datetime_convert('UTC','UTC','now - 3 days');
$d1 = datetime_convert('UTC', 'UTC', $x[0]['c']);
$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
// 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() {
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.
logger('remove_obsolete_hublocs', LOGGER_DEBUG);
// 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
@ -82,27 +95,25 @@ function remove_obsolete_hublocs() {
$r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'",
dbesc(z_root()),
dbesc(get_config('system','pubkey'))
dbesc(get_config('system', 'pubkey'))
);
if((! $r) || (! count($r)))
return;
$channels = array();
// Good. We have at least one *valid* hubloc.
// Do we have any invalid ones?
$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())
);
$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())
);
if(is_array($r) && is_array($p))
$r = array_merge($r,$p);
$r = array_merge($r, $p);
if(! $r)
return;
@ -111,8 +122,8 @@ function remove_obsolete_hublocs() {
logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.');
$interval = ((get_config('system','delivery_interval') !== false)
? intval(get_config('system','delivery_interval')) : 2 );
$interval = ((get_config('system', 'delivery_interval') !== false)
? intval(get_config('system', 'delivery_interval')) : 2 );
foreach($r as $rr) {
q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d",
@ -123,7 +134,7 @@ function remove_obsolete_hublocs() {
dbesc($rr['hubloc_hash'])
);
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)
@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) {
if(! is_array($hubloc)) {
@ -179,7 +197,7 @@ function hubloc_change_primary($hubloc) {
}
$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'",
dbesc($hubloc['hubloc_addr']),
@ -191,14 +209,19 @@ function hubloc_change_primary($hubloc) {
if(! $r)
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;
}
// 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) {
$r = q("update hubloc set hubloc_status = ( hubloc_status | %d ) where hubloc_callback = '%s'",
intval(HUBLOC_OFFLINE),
@ -208,20 +231,19 @@ function hubloc_mark_as_down($posturl) {
function ping_site($url) {
$ret = array('success' => false);
$sys = get_sys_channel();
$m = zot_build_packet($sys,'ping');
$r = zot_zot($url . '/post',$m);
$m = zot_build_packet($sys, 'ping');
$r = zot_zot($url . '/post', $m);
if(! $r['success']) {
$ret['message'] = 'no answer from ' . $url;
return $ret;
}
$packet_result = json_decode($r['body'],true);
$packet_result = json_decode($r['body'], true);
if(! $packet_result['success']) {
$ret['message'] = 'packet failure from ' . $url;
return $ret;

View File

@ -1,8 +1,19 @@
<?php
use Zotlabs\Lib\IConfig;
require_once('include/menu.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) {
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);
logger('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) {
foreach($configs as $config) {
unset($config['id']);
$config['uid'] = $channel['channel_id'];
create_table_from_array('pconfig',$config);
create_table_from_array('pconfig', $config);
}
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) {
foreach($profiles as $profile) {
@ -137,19 +161,29 @@ function import_profiles($channel,$profiles) {
convert_oldfields($profile,'with','partner');
convert_oldfields($profile,'work','employment');
// 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
/**
* @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.
*/
$profile['photo'] = z_root() . '/photo/profile/l/' . $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) {
foreach($hublocs as $hubloc) {
@ -183,7 +217,7 @@ function import_hublocs($channel,$hublocs,$seize,$moving = false) {
if(($x = zot_gethub($arr,false)) === false) {
unset($hubloc['hubloc_id']);
create_table_from_array('hubloc',$hubloc);
create_table_from_array('hubloc', $hubloc);
}
else {
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($x['hubloc_id'])
);
}
}
}
}
function import_objs($channel,$objs) {
/**
* @brief Import things.
*
* @param array $channel
* @param array $objs
*/
function import_objs($channel, $objs) {
if($channel && $objs) {
foreach($objs as $obj) {
@ -214,21 +251,27 @@ function import_objs($channel,$objs) {
$obj['obj_channel'] = $channel['channel_id'];
if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']);
if($baseurl && (strpos($obj['obj_url'], $baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl, z_root(), $obj['obj_url']);
}
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];
}
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) {
foreach($objs as $obj) {
@ -251,8 +294,8 @@ function sync_objs($channel,$objs) {
$obj['obj_channel'] = $channel['channel_id'];
if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']);
if($baseurl && (strpos($obj['obj_url'], $baseurl . '/thing/') !== false)) {
$obj['obj_url'] = str_replace($baseurl, z_root(), $obj['obj_url']);
}
$exists = false;
@ -269,7 +312,7 @@ function sync_objs($channel,$objs) {
}
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];
}
@ -287,17 +330,19 @@ function sync_objs($channel,$objs) {
}
}
else {
create_table_from_array('obj',$obj);
create_table_from_array('obj', $obj);
}
}
}
}
function import_apps($channel,$apps) {
/**
* @brief Import apps.
*
* @param array $channel
* @param array $apps
*/
function import_apps($channel, $apps) {
if($channel && $apps) {
foreach($apps as $app) {
@ -311,13 +356,13 @@ function import_apps($channel,$apps) {
$app['app_channel'] = $channel['channel_id'];
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];
}
$hash = $app['app_id'];
create_table_from_array('app',$app);
create_table_from_array('app', $app);
if($term) {
$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) {
if(array_key_exists('type',$t))
$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']));
}
}
}
}
}
}
function sync_apps($channel,$apps) {
/**
* @brief Sync apps.
*
* @param array $channel
* @param array $apps
*/
function sync_apps($channel, $apps) {
if($channel && $apps) {
foreach($apps as $app) {
@ -440,9 +487,13 @@ function sync_apps($channel,$apps) {
}
}
function import_chatrooms($channel,$chatrooms) {
/**
* @brief Import chatrooms.
*
* @param array $channel
* @param array $chatrooms
*/
function import_chatrooms($channel, $chatrooms) {
if($channel && $chatrooms) {
foreach($chatrooms as $chatroom) {
@ -457,14 +508,18 @@ function import_chatrooms($channel,$chatrooms) {
$chatroom['cr_aid'] = $channel['channel_account_id'];
$chatroom['cr_uid'] = $channel['channel_id'];
create_table_from_array('chatroom',$chatroom);
create_table_from_array('chatroom', $chatroom);
}
}
}
function sync_chatrooms($channel,$chatrooms) {
/**
* @brief Sync chatrooms.
*
* @param array $channel
* @param array $chatrooms
*/
function sync_chatrooms($channel, $chatrooms) {
if($channel && $chatrooms) {
foreach($chatrooms as $chatroom) {
@ -480,7 +535,6 @@ function sync_chatrooms($channel,$chatrooms) {
continue;
}
unset($chatroom['cr_id']);
unset($chatroom['cr_aid']);
unset($chatroom['cr_uid']);
@ -502,6 +556,7 @@ function sync_chatrooms($channel,$chatrooms) {
if($x) {
if($x[0]['cr_edited'] >= $chatroom['cr_edited'])
continue;
$exists = true;
}
$name = $chatroom['cr_name'];
@ -517,15 +572,22 @@ function sync_chatrooms($channel,$chatrooms) {
}
}
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) {
@ -578,9 +640,17 @@ function import_items($channel,$items,$sync = false,$relocate = null) {
}
}
function sync_items($channel,$items,$relocate = null) {
import_items($channel,$items,true,$relocate);
/**
* @brief Sync items to channel.
*
* @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'])
);
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) {
foreach($events as $event) {
@ -619,13 +695,18 @@ function import_events($channel,$events) {
convert_oldfields($event,'type','etype');
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) {
foreach($events as $event) {
@ -650,7 +731,6 @@ function sync_events($channel,$events) {
convert_oldfields($event,'type','etype');
convert_oldfields($event,'ignore','dismissed');
$exists = false;
$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[0]['edited'] >= $event['edited'])
continue;
$exists = true;
}
@ -674,15 +755,19 @@ function sync_events($channel,$events) {
}
}
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) {
foreach($menus as $menu) {
@ -701,7 +786,6 @@ function import_menus($channel,$menus) {
$m['menu_flags'] |= MENU_BOOKMARK;
if(in_array('system',$menu['flags']))
$m['menu_flags'] |= MENU_SYSTEM;
}
$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) {
foreach($menus as $menu) {
@ -795,7 +882,6 @@ function sync_menus($channel,$menus) {
foreach($menu['items'] as $it) {
$mitem = array();
$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('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']);
@ -820,9 +906,13 @@ function sync_menus($channel,$menus) {
}
}
function import_likes($channel,$likes) {
/**
* @brief Import likes.
*
* @param array $channel
* @param array $likes
*/
function import_likes($channel, $likes) {
if($channel && $likes) {
foreach($likes as $like) {
if($like['deleted']) {
@ -850,7 +940,7 @@ function import_likes($channel,$likes) {
if($r)
continue;
create_table_from_array('likes',$like);
create_table_from_array('likes', $like);
}
}
}
@ -877,14 +967,19 @@ function import_conv($channel,$convs) {
);
if($r)
continue;
create_table_from_array('conv',$conv);
}
}
}
function import_mail($channel,$mails,$sync = false) {
/**
* @brief Import mails.
*
* @param array $channel
* @param array $mails
*/
function import_mail($channel, $mails, $sync = false) {
if($channel && $mails) {
foreach($mails as $mail) {
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');
@ -964,7 +1072,6 @@ function sync_files($channel,$files) {
$att['aid'] = $channel['channel_account_id'];
$att['uid'] = $channel['channel_id'];
// check for duplicate folder names with the same parent.
// If we have a duplicate that doesn't match this hash value
// change the name so that the contents won't be "covered over"
@ -1009,7 +1116,7 @@ function sync_files($channel,$files) {
// 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;
@ -1018,19 +1125,20 @@ function sync_files($channel,$files) {
// If the hash ever contains any escapable chars this could cause
// problems. Currently it does not.
// @TODO implement os_path
/// @TODO implement os_path
if(!isset($att['os_path']))
$att['os_path'] = '';
if($attach_exists) {
logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG);
if(! dbesc_array($att))
continue;
$str = '';
foreach($att as $k => $v) {
if($str)
$str .= ",";
$str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' ";
}
$r = dbq("update attach set " . $str . " where id = " . intval($attach_id) );
@ -1040,7 +1148,6 @@ function sync_files($channel,$files) {
create_table_from_array('attach',$att);
}
// is this a directory?
if($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
@ -1049,7 +1156,6 @@ function sync_files($channel,$files) {
continue;
}
else {
// it's a file
// 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
@ -1084,7 +1190,7 @@ function sync_files($channel,$files) {
}
}
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);
}
if($f['photo']) {
@ -1128,7 +1234,6 @@ function sync_files($channel,$files) {
else
$p['content'] = base64_decode($p['content']);
if(!isset($p['display_path']))
$p['display_path'] = '';
@ -1138,14 +1243,15 @@ function sync_files($channel,$files) {
intval($channel['channel_id'])
);
if($exists) {
if(! dbesc_array($p))
continue;
$str = '';
foreach($p as $k => $v) {
if($str)
$str .= ",";
$str .= " " . TQUOT . $k . TQUOT . " = '" . $v . "' ";
}
$r = dbq("update photo set " . $str . " where id = " . intval($exists[0]['id']) );
@ -1164,9 +1270,17 @@ function sync_files($channel,$files) {
}
}
function convert_oldfields(&$arr,$old,$new) {
if(array_key_exists($old,$arr)) {
/**
* @brief Rename a key in an array.
*
* 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];
unset($arr[$old]);
}
@ -1240,6 +1354,7 @@ function scan_webpage_elements($path, $type, $cloud = false) {
}
}
}
return $elements;
}
@ -1352,8 +1467,7 @@ function import_webpage_element($element, $channel, $type) {
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) {
$arr['id'] = $i[0]['id'];
@ -1374,7 +1488,7 @@ function import_webpage_element($element, $channel, $type) {
}
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']);
$element['import_success'] = 1;
}
@ -1399,7 +1513,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner);
$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
$sql_extra order by item.created desc",
@ -1439,7 +1552,6 @@ function get_webpage_elements($channel, $type = 'all') {
);
$elements['pages'][] = $element_arr;
}
}
if($type !== 'all') {
break;
@ -1451,7 +1563,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner);
$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
$sql_extra order by item.created desc",
@ -1459,11 +1570,9 @@ function get_webpage_elements($channel, $type = 'all') {
intval(ITEM_TYPE_PDL)
);
$layouts = null;
if($r) {
$elements['layouts'] = array();
$layouts = array();
foreach($r as $rr) {
unobscure($rr);
@ -1490,7 +1599,6 @@ function get_webpage_elements($channel, $type = 'all') {
$sql_extra = item_permissions_sql($owner);
$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
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
@ -1499,11 +1607,9 @@ function get_webpage_elements($channel, $type = 'all') {
intval(ITEM_TYPE_BLOCK)
);
$blocks = null;
if($r) {
$elements['blocks'] = array();
$blocks = array();
foreach($r as $rr) {
unobscure($rr);
@ -1518,7 +1624,6 @@ function get_webpage_elements($channel, $type = 'all') {
'mid' => $rr['mid']
);
}
}
if($type !== 'all') {
@ -1528,11 +1633,18 @@ function get_webpage_elements($channel, $type = 'all') {
default:
break;
}
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) {
// if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) {
@ -1555,7 +1667,7 @@ function create_zip_file($files = array(), $destination = '', $overwrite = false
if(count($valid_files)) {
//create the archive
$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;
}
// 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) {
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]';
};
var isFunction = function (obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};
var uniqueId = 0;
function Completer(element, option) {
@ -147,32 +143,46 @@ if (typeof jQuery === 'undefined') {
this.id = 'textcomplete' + uniqueId++;
this.strategies = [];
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') {
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.
this.initialize()
} else {
// Initialize view objects lazily.
var self = this;
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 () {
if (!Completer.DEFAULTS) {
Completer.DEFAULTS = {
appendTo: $('body'),
zIndex: '100'
Completer.defaults = {
appendTo: 'body',
className: '', // deprecated option
dropdownClassName: 'dropdown-menu textcomplete-dropdown',
maxCount: 10,
zIndex: '100',
rightEdgeOffset: 30
};
}
return Completer.DEFAULTS;
}
$.extend(Completer.prototype, {
// Public properties
@ -184,12 +194,26 @@ if (typeof jQuery === 'undefined') {
adapter: null,
dropdown: null,
$el: null,
$iframe: null,
// Public methods
// --------------
initialize: function () {
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.
this.dropdown = new $.fn.textcomplete.Dropdown(element, this, this.option);
var Adapter, viewName;
@ -281,7 +305,7 @@ if (typeof jQuery === 'undefined') {
var strategy = this.strategies[i];
var context = strategy.context(text);
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; }
var match = text.match(matchRegexp);
if (match) { return [strategy, match[strategy.index], match]; }
@ -399,7 +423,7 @@ if (typeof jQuery === 'undefined') {
var $parent = option.appendTo;
if (!($parent instanceof $)) { $parent = $($parent); }
var $el = $('<ul></ul>')
.addClass('dropdown-menu textcomplete-dropdown')
.addClass(option.dropdownClassName)
.attr('id', 'textcomplete-dropdown-' + option._oid)
.css({
display: 'none',
@ -422,7 +446,7 @@ if (typeof jQuery === 'undefined') {
footer: null,
header: null,
id: null,
maxCount: 10,
maxCount: null,
placement: '',
shown: false,
data: [], // Shown zipped data.
@ -445,8 +469,8 @@ if (typeof jQuery === 'undefined') {
render: function (zippedData) {
var contentsHtml = this._buildContents(zippedData);
var unzippedData = $.map(this.data, function (d) { return d.value; });
if (this.data.length) {
var unzippedData = $.map(zippedData, function (d) { return d.value; });
if (zippedData.length) {
var strategy = zippedData[0].strategy;
if (strategy.id) {
this.$el.attr('data-strategy', strategy.id);
@ -785,8 +809,11 @@ if (typeof jQuery === 'undefined') {
var windowScrollBottom = $window.scrollTop() + $window.height();
var height = this.$el.height();
if ((this.$el.position().top + height) > windowScrollBottom) {
// only do this if we are not in an iframe
if (!this.completer.$iframe) {
this.$el.offset({top: windowScrollBottom - height});
}
}
},
_fitToRight: function() {
@ -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
// (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.
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 width = this.$el.width();
var maxLeft = $window.width() - tolerance;
@ -1005,8 +1032,14 @@ if (typeof jQuery === 'undefined') {
switch (clickEvent.keyCode) {
case 9: // TAB
case 13: // ENTER
case 16: // SHIFT
case 17: // CTRL
case 18: // ALT
case 33: // PAGEUP
case 34: // PAGEDOWN
case 40: // DOWN
case 38: // UP
case 27: // ESC
return true;
}
if (clickEvent.ctrlKey) switch (clickEvent.keyCode) {
@ -1040,12 +1073,14 @@ if (typeof jQuery === 'undefined') {
var pre = this.getTextFromHeadToCaret();
var post = this.el.value.substring(this.el.selectionEnd);
var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
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.selectionStart = this.el.selectionEnd = pre.length;
}
@ -1062,7 +1097,8 @@ if (typeof jQuery === 'undefined') {
var p = $.fn.textcomplete.getCaretCoordinates(this.el, this.el.selectionStart);
return {
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 post = this.el.value.substring(pre.length);
var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
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.focus();
var range = this.el.createTextRange();
@ -1162,30 +1200,35 @@ if (typeof jQuery === 'undefined') {
// When an dropdown item is selected, it is executed.
select: function (value, strategy, e) {
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 selection = range.cloneRange();
selection.selectNodeContents(range.startContainer);
var content = selection.toString();
var post = content.substring(range.startOffset);
var newSubstr = strategy.replace(value, e);
var regExp;
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
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.deleteContents();
// create temporary elements
var preWrapper = document.createElement("div");
var preWrapper = this.el.ownerDocument.createElement("div");
preWrapper.innerHTML = pre;
var postWrapper = document.createElement("div");
var postWrapper = this.el.ownerDocument.createElement("div");
postWrapper.innerHTML = post;
// create the fragment thats inserted
var fragment = document.createDocumentFragment();
var fragment = this.el.ownerDocument.createDocumentFragment();
var childNode;
var lastOfPre;
while (childNode = preWrapper.firstChild) {
@ -1218,8 +1261,8 @@ if (typeof jQuery === 'undefined') {
//
// Dropdown's position will be decided using the result.
_getCaretRelativePosition: function () {
var range = window.getSelection().getRangeAt(0).cloneRange();
var node = document.createElement('span');
var range = this.el.ownerDocument.getSelection().getRangeAt(0).cloneRange();
var node = this.el.ownerDocument.createElement('span');
range.insertNode(node);
range.selectNodeContents(node);
range.deleteContents();
@ -1228,6 +1271,17 @@ if (typeof jQuery === 'undefined') {
position.left -= this.$el.offset().left;
position.top += $node.height() - this.$el.offset().top;
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();
return position;
},
@ -1241,7 +1295,7 @@ if (typeof jQuery === 'undefined') {
// this.getTextFromHeadToCaret()
// // => ' wor' // not '<b>hello</b> wor'
getTextFromHeadToCaret: function () {
var range = window.getSelection().getRangeAt(0);
var range = this.el.ownerDocument.getSelection().getRangeAt(0);
var selection = range.cloneRange();
selection.selectNodeContents(range.startContainer);
return selection.toString().substring(0, range.startOffset);
@ -1251,6 +1305,39 @@ if (typeof jQuery === 'undefined') {
$.fn.textcomplete.ContentEditable = ContentEditable;
}(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)
//
// 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;
}
.panel-group {
margin-bottom: 0px;
}
/* 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 label { padding-left: 0px; font-weight: 700}

View File

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

View File

@ -693,39 +693,6 @@ div.jGrowl div.jGrowl-notification {
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 {
color: #333;
font-size: 0.9rem;
@ -1095,20 +1062,10 @@ img.mail-conv-sender-photo {
.wall-item-ago,
a:hover .wall-item-ago,
.dropdown-sub-text,
a:hover .dropdown-sub-text {
.dropdown-sub-text {
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,
.mail-conv-body,
.page-body,
@ -1393,6 +1350,7 @@ blockquote {
}
.dropdown-menu {
color: $font_colour;
font-size: 0.9rem;
border-radius: $radius;
}
@ -1401,6 +1359,21 @@ blockquote {
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 {
background-color: $nav_bg !important;
}