Merge branch 'develop' into 'master'
Update 4.6 See merge request harukin/core!71
This commit is contained in:
commit
bc7f029b0b
@ -1,10 +1,65 @@
|
||||
# Hubzilla at Home next to your Router
|
||||
# How to use
|
||||
|
||||
This readme will show you how to install and run Hubzilla (or Zap) at home.
|
||||
## Disclaimers
|
||||
|
||||
The installation is done by a script.
|
||||
- This script does work with Debian 10 only.
|
||||
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
|
||||
|
||||
What the script will do for you...
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ Internet connection and router at home
|
||||
+ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ USB drive for backups
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 10 (Stretch)
|
||||
+ Router with open ports 80 and 443 for your web server
|
||||
|
||||
## How to run the script
|
||||
|
||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||
+ Log on to your fresh Debian
|
||||
- apt-get install git
|
||||
- mkdir -p /var/www
|
||||
- cd /var/www
|
||||
- git clone https://framagit.org/hubzilla/core.git html
|
||||
- cd html/.homeinstall
|
||||
- cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
- nano hubzilla-config.txt
|
||||
- Read the comments carefully
|
||||
- Enter your values: db pass, domain, values for dyn DNS
|
||||
- Prepare your external disk for backups
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
||||
|
||||
## Optional - Set path to imagemagick
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
## Optional - Switch verification of email on/off
|
||||
|
||||
Do this just befor you register the user.
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
Check the current setting
|
||||
|
||||
util/config system verify_email
|
||||
|
||||
Switch the verification on/off (1/0)
|
||||
|
||||
util/config system verify_email 0
|
||||
|
||||
## What the script will do for you...
|
||||
|
||||
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||
+ create a database
|
||||
@ -38,69 +93,11 @@ The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzill
|
||||
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
|
||||
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
|
||||
|
||||
## Disclaimers
|
||||
|
||||
- This script does work with Debian 10 only.
|
||||
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
|
||||
|
||||
# Step-by-Step Overwiew
|
||||
# Step-by-Step - some Details
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ Internet connection and router at home
|
||||
+ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
|
||||
+ USB drive for backups
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 10 (Stretch)
|
||||
+ Router with open ports 80 and 443 for your web server
|
||||
|
||||
## The basic steps (quick overview)
|
||||
|
||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||
+ Log on to your fresh Debian
|
||||
- apt-get install git
|
||||
- mkdir -p /var/www
|
||||
- cd /var/www
|
||||
- git clone https://framagit.org/hubzilla/core.git html
|
||||
- cd html/.homeinstall
|
||||
- cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
- nano hubzilla-config.txt
|
||||
- Read the comments carefully
|
||||
- Enter your values: db pass, domain, values for dyn DNS
|
||||
- Prepare your external disk for backups
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the check of the mail address fails when you try to register the very first user in the browser. Do...
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.do_not_check_dns 1
|
||||
|
||||
## Optional - Set path to imagemagick
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
# Step-by-Step in Detail
|
||||
|
||||
## Preparations Software
|
||||
|
||||
## Install Debian 9
|
||||
|
||||
Provided you use a Raspberry Pi 3...
|
||||
|
||||
Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
|
||||
|
||||
Follow the installation instruction there.
|
||||
## Preparations
|
||||
|
||||
## Configure your Router
|
||||
|
||||
@ -146,12 +143,5 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
On a Raspian Stretch (Debian 10) the validation of the mail address fails for the very first user.
|
||||
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
|
||||
|
||||
So if your system isn't registered in DNS or DNS isn't active do
|
||||
|
||||
cd /var/www/html
|
||||
util/config system.do_not_check_dns 1
|
||||
|
||||
|
||||
|
@ -28,14 +28,13 @@
|
||||
# * php,
|
||||
# * mariadb - the database for hubzilla,
|
||||
# * adminer,
|
||||
# * git to download and update hubzilla addon
|
||||
# - download hubzilla core and addons
|
||||
# * git to download and update addons
|
||||
# - configure cron
|
||||
# * "Master.php" for regular background prozesses of hubzilla
|
||||
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
|
||||
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
|
||||
# * backup hubzillas database and files (rsync)
|
||||
# - letsencrypt
|
||||
# - run letsencrypt to create, register and use a certifacte for https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
@ -56,7 +55,7 @@
|
||||
# - creates a daily cron that runs the hubzilla-daily.sh
|
||||
#
|
||||
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
||||
# - /var/lib/mysql/ > hubzilla database
|
||||
# - /var/lib/mysql/ > database
|
||||
# - /var/www/ > hubzilla/zap from github
|
||||
# - /etc/letsencrypt/ > certificates
|
||||
#
|
||||
@ -223,6 +222,11 @@ function install_curl {
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
function install_wget {
|
||||
print_info "installing wget..."
|
||||
nocheck_install "wget"
|
||||
}
|
||||
|
||||
function install_sendmail {
|
||||
print_info "installing sendmail..."
|
||||
nocheck_install "sendmail sendmail-bin"
|
||||
@ -269,7 +273,19 @@ function install_adminer {
|
||||
else
|
||||
print_info "file /etc/adminer/adminer.conf exists already"
|
||||
fi
|
||||
|
||||
a2enmod rewrite
|
||||
|
||||
if [ ! -f /etc/apache2/apache2.conf ]
|
||||
then
|
||||
die "could not find file /etc/apache2/apache2.conf"
|
||||
fi
|
||||
sed -i \
|
||||
"s/AllowOverride None/AllowOverride all/" \
|
||||
/etc/apache2/apache2.conf
|
||||
|
||||
a2enconf adminer
|
||||
systemctl restart mariadb
|
||||
systemctl reload apache2
|
||||
}
|
||||
|
||||
@ -407,10 +423,9 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
fi
|
||||
# check if user gave mail address
|
||||
if [ -z "$le_email" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
@ -431,12 +446,19 @@ function check_https {
|
||||
}
|
||||
|
||||
function install_hubzilla {
|
||||
print_info "installing hubzilla addons..."
|
||||
print_info "installing addons..."
|
||||
cd /var/www/html/
|
||||
# if you install Hubzilla
|
||||
# util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
# if you install ZAP
|
||||
if git remote -v | grep -i "origin.*hubzilla.*core"
|
||||
then
|
||||
print_info "hubzilla"
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||
elif git remote -v | grep -i "origin.*zap.*core"
|
||||
then
|
||||
print_info "zap"
|
||||
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
|
||||
else
|
||||
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
|
||||
fi
|
||||
mkdir -p "store/[data]/smarty3"
|
||||
chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
@ -446,7 +468,7 @@ function install_hubzilla {
|
||||
chown root:www-data /var/www/html/
|
||||
chown root:www-data /var/www/html/.htaccess
|
||||
chmod 0644 /var/www/html/.htaccess
|
||||
print_info "installed hubzilla"
|
||||
print_info "installed addons"
|
||||
}
|
||||
|
||||
function install_rsync {
|
||||
@ -585,6 +607,7 @@ check_config
|
||||
stop_hubzilla
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_wget
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_imagemagick
|
||||
@ -601,6 +624,7 @@ configure_cron_selfhost
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
@ -608,15 +632,25 @@ fi
|
||||
|
||||
install_hubzilla
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
else
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
fi
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_rsync
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
||||
|
||||
|
69
CHANGELOG
69
CHANGELOG
@ -1,3 +1,72 @@
|
||||
Hubzilla 4.6 (2019-12-04)
|
||||
- Improve opengraph support for channels
|
||||
- Add opengraph support for articles
|
||||
- Update abook_connected for RSS feeds only if handle_feed() returned success
|
||||
- Do not embed PDF files by default but allow to enabled this feature in security options
|
||||
- Check if file exists before we include it in the router
|
||||
- Update jquery to version 3.4.1
|
||||
- Update composer libraries
|
||||
- Remove old and unused javascript libraries
|
||||
- Improved BBcode to Markdown conversion
|
||||
- Introduce inline SVG support via BBcode
|
||||
- Sanitize title on Atom/RSS feed import
|
||||
- Improved HTTP headers cache support for photos
|
||||
- Add date headers to signed headers
|
||||
- Add check if item['tag'] is an array
|
||||
- Add hook comments_are_now_closed for addons to override date based comment closure
|
||||
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
|
||||
- Improved photo cache expiration
|
||||
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
|
||||
- Improved support for CDN/Infrastructure caching (especially profile images)
|
||||
- New japanese translation
|
||||
- Add connect button for non-zot networks not connected in current location
|
||||
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
|
||||
- Allow addons to process forum posts published through mentions
|
||||
- Improved internal routing for ActivityPub messages
|
||||
- Improved admin documentation
|
||||
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
|
||||
- Support "comment policy" in Zot6 communications
|
||||
- Add selected text as quote on reply if comment button is used
|
||||
- Add more nofollow tags to links to discourage backlink farmers
|
||||
- Improved conversion of emoji reactions from zot to zot6
|
||||
- Add CardDAV/CalDAV autodiscovery
|
||||
- Label source project of zotfeed since it is not completely compatible across projects
|
||||
- Update homeinstall script
|
||||
|
||||
Bugfixes
|
||||
- Fix once cached embedded content is used and stored forever
|
||||
- Fix wildcard tag issue
|
||||
- Fix duplicate attachment in jot fileupload
|
||||
- Fix regression with audio file upload
|
||||
- Fix can not edit menu name or title (#1402)
|
||||
- Fix pagination encoding issue for some server setups
|
||||
- Fix Zap->Hubzilla event title compatibility
|
||||
- Fix event timezones for Zot6
|
||||
- Fix missing summary in mod article_edit
|
||||
- Fix PHP warning failed to write session data using user defined save handler
|
||||
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
|
||||
- Fix issues with image import to zot6
|
||||
- Fix attachment permissions on clonned channels sync
|
||||
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
|
||||
|
||||
Addons
|
||||
- Twitter: send tweet even if attached image uploading was unsuccessful
|
||||
- Livejournal: add link to original post option
|
||||
- Flashcards: update to version 2.08
|
||||
- Pubcrawl: compatibility changes to support pixelfed
|
||||
- Cart: update paypal button to API v2
|
||||
- Photocache: rework for speed and lower memory consumption
|
||||
- Photocache: etag support for cached photos
|
||||
- Photocache: purge cache on addon uninstall
|
||||
- Openstreetmap: fix regression if no default values set
|
||||
- Livejournal: allow send posts from non channel owner
|
||||
- Pubcrawl: fix event timezones
|
||||
- Pubcrawl: better ActivityPub channel URL detection
|
||||
- Pubcrawl: fix comments delivery for other channels on the same hub
|
||||
- New addon "workflow" with initial basic "issue tracker" capability
|
||||
|
||||
|
||||
|
||||
Hubzilla 4.4.1 (2019-08-16)
|
||||
- Fix wrong profile photo displayed when previewing and editing profiles
|
||||
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
|
||||
|
@ -97,13 +97,17 @@ class Cron {
|
||||
|
||||
// Clean expired photos from cache
|
||||
|
||||
$age = get_config('system','active_expire_days', '30');
|
||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
if($r) {
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
foreach($r as $rr) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
if(is_file($file)) {
|
||||
@ -113,11 +117,6 @@ class Cron {
|
||||
}
|
||||
}
|
||||
}
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
);
|
||||
|
||||
// publish any applicable items that were set to be published in the future
|
||||
// (time travel posts). Restrict to items that have come of age in the last
|
||||
@ -215,7 +214,7 @@ class Cron {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
reload_plugins();
|
||||
|
@ -44,6 +44,11 @@ class Cron_daily {
|
||||
db_utcnow(), db_quoteinterval('1 YEAR')
|
||||
);
|
||||
|
||||
// Clean up emdedded content cache
|
||||
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
|
||||
//update statistics in config
|
||||
require_once('include/statistics_fns.php');
|
||||
|
@ -13,7 +13,7 @@ class CurlAuth {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if($argc != 2)
|
||||
killme();
|
||||
return;
|
||||
|
||||
\App::$session->start();
|
||||
|
||||
@ -50,6 +50,6 @@ class CurlAuth {
|
||||
|
||||
file_put_contents($c,$x);
|
||||
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
|
||||
if($argc)
|
||||
Master::Release($argc,$argv);
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -285,10 +285,23 @@ class Notifier {
|
||||
}
|
||||
|
||||
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
|
||||
$hookinfo=[
|
||||
'targetitem'=>$target_item,
|
||||
'deliver'=>false
|
||||
];
|
||||
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
|
||||
call_hooks('customitem_deliver',$hookinfo);
|
||||
}
|
||||
|
||||
if (!$hookinfo['deliver']) {
|
||||
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
$target_item = $hookinfo['targetitem'];
|
||||
|
||||
}
|
||||
|
||||
// Check for non published items, but allow an exclusion for transmitting hidden file activities
|
||||
|
||||
if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
|
||||
|
@ -61,11 +61,13 @@ class Onepoll {
|
||||
|
||||
if($contact['xchan_network'] === 'rss') {
|
||||
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
||||
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
if ($alive) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ class Poller {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
if(($argc > 1) && intval($argv[1])) {
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/event.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class Activity {
|
||||
|
||||
@ -40,6 +42,8 @@ class Activity {
|
||||
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
return self::fetch_image($x);
|
||||
}
|
||||
|
||||
call_hooks('encode_object',$x);
|
||||
}
|
||||
|
||||
return $x;
|
||||
@ -63,12 +67,32 @@ class Activity {
|
||||
}
|
||||
else {
|
||||
$m = parse_url($url);
|
||||
|
||||
// handle bearcaps
|
||||
if ($m['scheme'] === 'bear') {
|
||||
$params = explode('&',$m['query']);
|
||||
if ($params) {
|
||||
foreach ($params as $p) {
|
||||
if (substr($p,0,2) === 'u=') {
|
||||
$url = substr($p,2);
|
||||
}
|
||||
if (substr($p,0,2) === 't=') {
|
||||
$token = substr($p,2);
|
||||
}
|
||||
}
|
||||
$m = parse_url($url);
|
||||
}
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'get ' . get_request_string($url),
|
||||
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
|
||||
'(request-target)' => 'get ' . get_request_string($url)
|
||||
];
|
||||
if (isset($token)) {
|
||||
$headers['Authorization'] = 'Bearer ' . $token;
|
||||
}
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
|
||||
}
|
||||
@ -178,6 +202,11 @@ class Activity {
|
||||
$ev = bbtoevent($x['content']);
|
||||
if($ev) {
|
||||
|
||||
|
||||
if (! $ev['timezone']) {
|
||||
$ev['timezone'] = 'UTC';
|
||||
}
|
||||
|
||||
$actor = null;
|
||||
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
|
||||
$actor = $x['author']['link'][0]['href'];
|
||||
@ -185,16 +214,17 @@ class Activity {
|
||||
$y = [
|
||||
'type' => 'Event',
|
||||
'id' => z_root() . '/event/' . $ev['event_hash'],
|
||||
'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
|
||||
'name' => $ev['summary'],
|
||||
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
|
||||
// RFC3339 Section 4.3
|
||||
'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
|
||||
'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
|
||||
'content' => bbcode($ev['description'], [ 'cache' => true ]),
|
||||
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
|
||||
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
|
||||
'actor' => $actor,
|
||||
];
|
||||
if(! $ev['nofinish']) {
|
||||
$y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
|
||||
$y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
|
||||
}
|
||||
|
||||
// copy attachments from the passed object - these are already formatted for ActivityStreams
|
||||
@ -274,7 +304,13 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if($i['verb'] === ACTIVITY_FRIEND) {
|
||||
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
||||
$objtype = 'Note';
|
||||
}
|
||||
else {
|
||||
$objtype = self::activity_obj_mapper($i['obj_type']);
|
||||
}
|
||||
|
||||
if(intval($i['item_deleted'])) {
|
||||
$ret['type'] = 'Tombstone';
|
||||
@ -312,10 +348,21 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
|
||||
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
|
||||
}
|
||||
|
||||
if (intval($i['item_private']) === 2) {
|
||||
$ret['directMessage'] = true;
|
||||
}
|
||||
|
||||
if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
|
||||
if($ret['commentPolicy']) {
|
||||
$ret['commentPolicy'] .= ' ';
|
||||
}
|
||||
$ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
|
||||
}
|
||||
|
||||
$ret['attributedTo'] = $i['author']['xchan_url'];
|
||||
|
||||
if($i['id'] != $i['parent']) {
|
||||
@ -354,19 +401,23 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if($item['tag']) {
|
||||
foreach($item['tag'] as $t) {
|
||||
if(! array_key_exists('type',$t))
|
||||
if ($item['tag'] && is_array($item['tag'])) {
|
||||
$ptr = $item['tag'];
|
||||
if (! array_key_exists(0,$ptr)) {
|
||||
$ptr = [ $ptr ];
|
||||
}
|
||||
foreach ($ptr as $t) {
|
||||
if (! array_key_exists('type',$t))
|
||||
$t['type'] = 'Hashtag';
|
||||
|
||||
switch($t['type']) {
|
||||
case 'Hashtag':
|
||||
$ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => ((isset($t['href'])) ? $t['href'] : $t['id']), 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
|
||||
$ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
|
||||
break;
|
||||
|
||||
case 'Mention':
|
||||
$mention_type = substr($t['name'],0,1);
|
||||
if($mention_type === '!') {
|
||||
if ($mention_type === '!') {
|
||||
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
|
||||
}
|
||||
else {
|
||||
@ -384,6 +435,7 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function encode_taxonomy($item) {
|
||||
|
||||
$ret = [];
|
||||
@ -467,6 +519,12 @@ class Activity {
|
||||
$ret = [];
|
||||
$reply = false;
|
||||
|
||||
|
||||
if($i['verb'] === ACTIVITY_FRIEND) {
|
||||
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
||||
$ret['obj'] = [];
|
||||
}
|
||||
|
||||
if(intval($i['item_deleted'])) {
|
||||
$ret['type'] = 'Tombstone';
|
||||
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
|
||||
@ -479,11 +537,6 @@ class Activity {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if($i['verb'] === ACTIVITY_FRIEND) {
|
||||
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
||||
$ret['obj_type'] = ACTIVITY_OBJ_NOTE;
|
||||
$ret['obj'] = [];
|
||||
}
|
||||
|
||||
$ret['type'] = self::activity_mapper($i['verb']);
|
||||
|
||||
@ -497,6 +550,25 @@ class Activity {
|
||||
xchan_query($p,true);
|
||||
$p = fetch_post_tags($p,true);
|
||||
$i['obj'] = self::encode_item($p[0]);
|
||||
|
||||
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
|
||||
// specific emoji instead of overloading the verb or type.
|
||||
|
||||
$im = explode('#',$i['verb']);
|
||||
if($im && count($im) > 1)
|
||||
$emoji = $im[1];
|
||||
if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
|
||||
$ln = $match[2];
|
||||
}
|
||||
|
||||
$i['tgt_type'] = 'Image';
|
||||
|
||||
$i['target'] = [
|
||||
'type' => 'Image',
|
||||
'name' => $emoji,
|
||||
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,9 +609,15 @@ class Activity {
|
||||
}
|
||||
|
||||
if($i['id'] != $i['parent']) {
|
||||
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
|
||||
$reply = true;
|
||||
|
||||
// inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
|
||||
// but *not* for comments, where it should only be present in the object
|
||||
|
||||
if (! in_array($ret['type'],[ 'Create','Update' ])) {
|
||||
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
|
||||
}
|
||||
|
||||
if($i['item_private']) {
|
||||
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
|
||||
intval($i['parent'])
|
||||
@ -577,7 +655,7 @@ class Activity {
|
||||
$i['obj'] = json_decode($i['obj'],true);
|
||||
}
|
||||
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
$i['obj']['id'] = $i['id'];
|
||||
$i['obj']['id'] = $i['mid'];
|
||||
}
|
||||
|
||||
$obj = self::encode_object($i['obj']);
|
||||
@ -668,8 +746,24 @@ class Activity {
|
||||
}
|
||||
$ret = [];
|
||||
|
||||
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
|
||||
|
||||
$ret['type'] = 'Person';
|
||||
$ret['id'] = $p['xchan_url'];
|
||||
|
||||
if ($c) {
|
||||
$role = get_pconfig($c['channel_id'],'system','permissions_role');
|
||||
if (strpos($role,'forum') !== false) {
|
||||
$ret['type'] = 'Group';
|
||||
}
|
||||
}
|
||||
|
||||
if ($c) {
|
||||
$ret['id'] = channel_url($c);
|
||||
}
|
||||
else {
|
||||
$ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
|
||||
}
|
||||
|
||||
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
|
||||
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
|
||||
$ret['name'] = $p['xchan_name'];
|
||||
@ -731,6 +825,7 @@ class Activity {
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
call_hooks('activity_mapper',$acts);
|
||||
|
||||
if(array_key_exists($verb,$acts) && $acts[$verb]) {
|
||||
return $acts[$verb];
|
||||
@ -743,6 +838,9 @@ class Activity {
|
||||
if(strpos($verb,ACTIVITY_MOOD) !== false)
|
||||
return 'Create';
|
||||
|
||||
if(strpos($verb,ACTIVITY_FRIEND) !== false)
|
||||
return 'Create';
|
||||
|
||||
if(strpos($verb,ACTIVITY_POKE) !== false)
|
||||
return 'Activity';
|
||||
|
||||
@ -773,6 +871,7 @@ class Activity {
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
call_hooks('activity_decode_mapper',$acts);
|
||||
|
||||
foreach($acts as $k => $v) {
|
||||
if($verb === $v) {
|
||||
@ -806,6 +905,8 @@ class Activity {
|
||||
|
||||
];
|
||||
|
||||
call_hooks('activity_obj_decode_mapper',$objs);
|
||||
|
||||
foreach($objs as $k => $v) {
|
||||
if($obj === $v) {
|
||||
return $k;
|
||||
@ -843,6 +944,8 @@ class Activity {
|
||||
|
||||
];
|
||||
|
||||
call_hooks('activity_obj_mapper',$objs);
|
||||
|
||||
if(array_key_exists($obj,$objs)) {
|
||||
return $objs[$obj];
|
||||
}
|
||||
@ -1601,11 +1704,12 @@ class Activity {
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Event') {
|
||||
|
||||
$s['obj'] = [];
|
||||
$s['obj']['asld'] = $act->obj;
|
||||
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
|
||||
$s['obj']['id'] = $act->obj['id'];
|
||||
$s['obj']['title'] = $act->obj['summary'];
|
||||
$s['obj']['title'] = $act->obj['name'];
|
||||
|
||||
if(strpos($act->obj['startTime'],'Z'))
|
||||
$s['obj']['adjust'] = true;
|
||||
@ -1863,6 +1967,15 @@ class Activity {
|
||||
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
||||
}
|
||||
|
||||
$hookinfo = [
|
||||
'act' => $act,
|
||||
's' => $s
|
||||
];
|
||||
|
||||
call_hooks('decode_note',$hookinfo);
|
||||
|
||||
$s = $hookinfo['s'];
|
||||
|
||||
return $s;
|
||||
|
||||
}
|
||||
@ -2052,9 +2165,17 @@ class Activity {
|
||||
break;
|
||||
|
||||
}
|
||||
if(! $item) {
|
||||
break;
|
||||
}
|
||||
|
||||
$hookinfo = [
|
||||
'a' => $a,
|
||||
'item' => $item
|
||||
];
|
||||
|
||||
call_hooks('fetch_and_store',$hookinfo);
|
||||
|
||||
$item = $hookinfo['item'];
|
||||
|
||||
if($item) {
|
||||
|
||||
array_unshift($p,[ $a, $item, $replies]);
|
||||
|
||||
@ -2062,6 +2183,7 @@ class Activity {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
$current_act = $a;
|
||||
$current_item = $item;
|
||||
}
|
||||
@ -2110,11 +2232,19 @@ class Activity {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(! $item) {
|
||||
break;
|
||||
}
|
||||
|
||||
$hookinfo = [
|
||||
'a' => $a,
|
||||
'item' => $item
|
||||
];
|
||||
|
||||
call_hooks('fetch_and_store',$hookinfo);
|
||||
|
||||
$item = $hookinfo['item'];
|
||||
|
||||
if($item) {
|
||||
array_unshift($p,[ $a, $item ]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2495,7 +2625,12 @@ class Activity {
|
||||
}
|
||||
|
||||
if($event) {
|
||||
$event['summary'] = html2bbcode($content['summary']);
|
||||
$event['summary'] = $content['name'];
|
||||
if(! $event['summary']) {
|
||||
if($content['summary']) {
|
||||
$event['summary'] = html2plain($content['summary']);
|
||||
}
|
||||
}
|
||||
$event['description'] = html2bbcode($content['content']);
|
||||
if($event['summary'] && $event['dtstart']) {
|
||||
$content['event'] = $event;
|
||||
|
@ -11,8 +11,10 @@ class Cache {
|
||||
|
||||
$hash = hash('whirlpool',$key);
|
||||
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
|
||||
dbesc($hash)
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
|
||||
dbesc($hash),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
|
||||
);
|
||||
|
||||
if ($r)
|
||||
@ -40,12 +42,5 @@ class Cache {
|
||||
dbesc(datetime_convert()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function clear() {
|
||||
q("DELETE FROM cache WHERE updated < '%s'",
|
||||
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class LDSignatures {
|
||||
'type' => 'RsaSignature2017',
|
||||
'nonce' => random_string(64),
|
||||
'creator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
|
||||
];
|
||||
|
||||
$ohash = self::hash(self::signable_options($options));
|
||||
|
@ -1223,9 +1223,39 @@ class Libzot {
|
||||
if($private) {
|
||||
$arr['item_private'] = true;
|
||||
}
|
||||
|
||||
if ($arr['mid'] === $arr['parent_mid']) {
|
||||
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
|
||||
$p = strstr($AS->obj['commentPolicy'],'until=');
|
||||
if($p !== false) {
|
||||
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
|
||||
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = $AS->obj['commentPolicy'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @FIXME - spoofable
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
|
||||
if (! array_key_exists('comment_policy',$arr)) {
|
||||
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||
// Anything else we'll say is zot - which could have a range of project names
|
||||
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||
dbesc($r[0]['hubloc_url'])
|
||||
);
|
||||
|
||||
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||
$arr['comment_policy'] = 'authenticated';
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
}
|
||||
}
|
||||
}
|
||||
if($AS->data['signed_data']) {
|
||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||
@ -1734,7 +1764,7 @@ class Libzot {
|
||||
// if it's a sourced post, call the post_local hooks as if it were
|
||||
// posted locally so that crosspost connectors will be triggered.
|
||||
|
||||
if(check_item_source($arr['uid'], $arr)) {
|
||||
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
|
||||
/**
|
||||
* @hooks post_local
|
||||
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
||||
@ -1819,6 +1849,10 @@ class Libzot {
|
||||
|
||||
$ret = [];
|
||||
|
||||
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($a['signature']['signer'])
|
||||
);
|
||||
|
||||
foreach($a['data']['orderedItems'] as $activity) {
|
||||
|
||||
$AS = new ActivityStreams($activity);
|
||||
@ -1877,6 +1911,23 @@ class Libzot {
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
}
|
||||
|
||||
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||
// Anything else we'll say is zot - which could have a range of project names
|
||||
|
||||
if ($signer) {
|
||||
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||
dbesc($signer[0]['hubloc_url'])
|
||||
);
|
||||
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||
$arr['comment_policy'] = 'authenticated';
|
||||
}
|
||||
else {
|
||||
$arr['comment_policy'] = 'contacts';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($AS->data['signed_data']) {
|
||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ class Queue {
|
||||
$host_crypto = null;
|
||||
|
||||
if($channel && $base) {
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
|
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
use DomDocument;
|
||||
|
||||
/**
|
||||
* SVGSantiizer
|
||||
*
|
||||
* Whitelist-based PHP SVG sanitizer.
|
||||
*
|
||||
* @link https://github.com/alister-/SVG-Sanitizer}
|
||||
* @author Alister Norris
|
||||
* @copyright Copyright (c) 2013 Alister Norris
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License
|
||||
* @package svgsanitizer
|
||||
*/
|
||||
|
||||
class SvgSanitizer {
|
||||
|
||||
private $xmlDoc; // PHP XML DOMDocument
|
||||
|
||||
private $removedattrs = [];
|
||||
|
||||
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
|
||||
|
||||
// defines the whitelist of elements and attributes allowed.
|
||||
private static $whitelist = [
|
||||
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
|
||||
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
|
||||
'defs' => [ ],
|
||||
'style' => [ 'type' ],
|
||||
'desc' => [ ],
|
||||
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
|
||||
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
|
||||
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
|
||||
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
|
||||
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
|
||||
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
|
||||
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
|
||||
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
|
||||
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
|
||||
'metadata' => [ 'class', 'id' ],
|
||||
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
|
||||
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
|
||||
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
|
||||
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
|
||||
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
|
||||
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
|
||||
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
|
||||
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
|
||||
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
|
||||
'title' => [ ],
|
||||
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
|
||||
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
|
||||
];
|
||||
|
||||
function __construct() {
|
||||
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
|
||||
$this->xmlDoc->preserveWhiteSpace = false;
|
||||
libxml_use_internal_errors(true);
|
||||
}
|
||||
|
||||
// load XML SVG
|
||||
function load($file) {
|
||||
$this->xmlDoc->load($file);
|
||||
}
|
||||
|
||||
function loadXML($str) {
|
||||
if (! $this->xmlDoc->loadXML($str)) {
|
||||
logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function sanitize()
|
||||
{
|
||||
// all elements in xml doc
|
||||
$allElements = $this->xmlDoc->getElementsByTagName('*');
|
||||
|
||||
// loop through all elements
|
||||
for($i = 0; $i < $allElements->length; $i++)
|
||||
{
|
||||
$this->removedattrs = [];
|
||||
|
||||
$currentNode = $allElements->item($i);
|
||||
|
||||
// logger('current_node: ' . print_r($currentNode,true));
|
||||
|
||||
// array of allowed attributes in specific element
|
||||
$whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
|
||||
|
||||
// does element exist in whitelist?
|
||||
if(isset($whitelist_attr_arr)) {
|
||||
$total = $currentNode->attributes->length;
|
||||
|
||||
for($x = 0; $x < $total; $x++) {
|
||||
|
||||
// get attributes name
|
||||
$attrName = $currentNode->attributes->item($x)->nodeName;
|
||||
|
||||
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
|
||||
$matches = false;
|
||||
|
||||
// check if attribute isn't in whitelist
|
||||
if(! in_array($attrName, $whitelist_attr_arr)) {
|
||||
$this->removedattrs[] = $attrName;
|
||||
}
|
||||
// check for disallowed functions
|
||||
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
|
||||
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
|
||||
if ($attrName === 'text') {
|
||||
continue;
|
||||
}
|
||||
foreach ($matches as $match) {
|
||||
if(! in_array($match[1],self::$allowed_functions)) {
|
||||
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
|
||||
$this->removedattrs[] = $attrName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->removedattrs) {
|
||||
foreach ($this->removedattrs as $attr) {
|
||||
$currentNode->removeAttribute($attr);
|
||||
logger('removed: ' . $attr, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// else remove element
|
||||
else {
|
||||
logger('remove_node: ' . print_r($currentNode,true));
|
||||
$currentNode->parentNode->removeChild($currentNode);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function saveSVG() {
|
||||
$this->xmlDoc->formatOutput = true;
|
||||
return($this->xmlDoc->saveXML());
|
||||
}
|
||||
}
|
@ -778,8 +778,6 @@ class ThreadItem {
|
||||
call_hooks('comment_buttons',$arr);
|
||||
$comment_buttons = $arr['comment_buttons'];
|
||||
|
||||
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
|
||||
|
||||
$comment_box = replace_macros($template,array(
|
||||
'$return_path' => '',
|
||||
'$threaded' => $this->is_threaded(),
|
||||
@ -814,8 +812,7 @@ class ThreadItem {
|
||||
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
|
||||
'$auto_save_draft' => $feature_auto_save_draft
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
|
||||
));
|
||||
|
||||
return $comment_box;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use \Zotlabs\Storage\GitRepo;
|
||||
use \Michelf\MarkdownExtra;
|
||||
|
||||
@ -253,14 +254,14 @@ class Addons {
|
||||
* Single plugin
|
||||
*/
|
||||
|
||||
if (\App::$argc == 3){
|
||||
$plugin = \App::$argv[2];
|
||||
if (App::$argc == 3){
|
||||
$plugin = App::$argv[2];
|
||||
if (!is_file("addon/$plugin/$plugin.php")){
|
||||
notice( t("Item not found.") );
|
||||
return '';
|
||||
}
|
||||
|
||||
$enabled = in_array($plugin,\App::$plugins);
|
||||
$enabled = in_array($plugin,App::$plugins);
|
||||
$info = get_plugin_info($plugin);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
@ -268,11 +269,11 @@ class Addons {
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($plugin, \App::$plugins);
|
||||
$idz = array_search($plugin, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($plugin);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
@ -281,19 +282,19 @@ class Addons {
|
||||
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
||||
$pinstalled = false;
|
||||
// Toggle plugin status
|
||||
$idx = array_search($plugin, \App::$plugins);
|
||||
$idx = array_search($plugin, App::$plugins);
|
||||
if ($idx !== false){
|
||||
unset(\App::$plugins[$idx]);
|
||||
unset(App::$plugins[$idx]);
|
||||
uninstall_plugin($plugin);
|
||||
$pinstalled = false;
|
||||
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
||||
} else {
|
||||
\App::$plugins[] = $plugin;
|
||||
App::$plugins[] = $plugin;
|
||||
install_plugin($plugin);
|
||||
$pinstalled = true;
|
||||
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
||||
}
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
|
||||
if($pinstalled) {
|
||||
@require_once("addon/$plugin/$plugin.php");
|
||||
@ -305,7 +306,7 @@ class Addons {
|
||||
|
||||
// display plugin details
|
||||
|
||||
if (in_array($plugin, \App::$plugins)){
|
||||
if (in_array($plugin, App::$plugins)){
|
||||
$status = 'on';
|
||||
$action = t('Disable');
|
||||
} else {
|
||||
@ -380,18 +381,18 @@ class Addons {
|
||||
|
||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||
$info = get_plugin_info($id);
|
||||
$enabled = in_array($id,\App::$plugins);
|
||||
$enabled = in_array($id,App::$plugins);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
// disable plugins which are installed but incompatible versions
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($id, \App::$plugins);
|
||||
$idz = array_search($id, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($id);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
|
@ -44,6 +44,12 @@ class Security {
|
||||
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
|
||||
set_config('system','embed_deny',$be);
|
||||
|
||||
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
||||
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
||||
|
||||
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
|
||||
set_config('system', 'inline_pdf' , $inline_pdf);
|
||||
|
||||
$ts = ((x($_POST,'transport_security')) ? True : False);
|
||||
set_config('system','transport_security_header',$ts);
|
||||
|
||||
@ -106,6 +112,8 @@ class Security {
|
||||
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
|
||||
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
|
||||
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
|
||||
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
|
||||
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
|
||||
|
||||
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
|
||||
|
||||
|
@ -73,7 +73,6 @@ class Site {
|
||||
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
|
||||
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
||||
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
|
||||
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
||||
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
|
||||
$pub_incl = escape_tags(trim($_POST['pub_incl']));
|
||||
$pub_excl = escape_tags(trim($_POST['pub_excl']));
|
||||
@ -100,7 +99,6 @@ class Site {
|
||||
set_config('system', 'from_email', $from_email);
|
||||
set_config('system', 'from_email_name' , $from_email_name);
|
||||
set_config('system', 'imagick_convert_path' , $imagick_path);
|
||||
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
||||
set_config('system', 'default_permissions_role', $permissions_role);
|
||||
set_config('system', 'pubstream_incl',$pub_incl);
|
||||
set_config('system', 'pubstream_excl',$pub_excl);
|
||||
@ -341,7 +339,6 @@ class Site {
|
||||
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
|
||||
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
|
||||
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
|
||||
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
|
||||
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
|
||||
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
|
||||
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
|
||||
|
@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$mimetype = $itm[0]['mimetype'];
|
||||
|
||||
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
|
||||
$content = $itm[0]['body'];
|
||||
|
||||
|
||||
|
||||
$rp = 'articles/' . $channel['channel_address'];
|
||||
|
||||
$x = array(
|
||||
@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
'ptyp' => $itm[0]['type'],
|
||||
'mimeselect' => false,
|
||||
'mimetype' => $itm[0]['mimetype'],
|
||||
'body' => undo_post_tagging($content),
|
||||
'body' => $summary . undo_post_tagging($content),
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||
|
@ -9,6 +9,7 @@ use Zotlabs\Lib\PermissionDescription;
|
||||
require_once('include/channel.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
class Articles extends Controller {
|
||||
@ -192,7 +193,7 @@ class Articles extends Controller {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
$r = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@ -200,15 +201,18 @@ class Articles extends Controller {
|
||||
intval(App::$profile['profile_uid']),
|
||||
dbesc($parents_str)
|
||||
);
|
||||
if($items) {
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,'updated');
|
||||
}
|
||||
else
|
||||
$items = [];
|
||||
}
|
||||
|
||||
// Add Opengraph markup
|
||||
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
|
||||
|
||||
$mode = 'articles';
|
||||
|
||||
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
|
||||
|
@ -910,8 +910,6 @@ class Cdav extends Controller {
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
head_add_css('cdav.css');
|
||||
|
||||
if(!cdav_principal($principalUri)) {
|
||||
$this->activate($pdo, $channel);
|
||||
if(!cdav_principal($principalUri)) {
|
||||
|
@ -13,6 +13,7 @@ require_once('include/items.php');
|
||||
require_once('include/security.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
/**
|
||||
@ -109,19 +110,20 @@ class Channel extends Controller {
|
||||
|
||||
// Run profile_load() here to make sure the theme is set before
|
||||
// we start loading content
|
||||
|
||||
profile_load($which,$profile);
|
||||
|
||||
App::$page['htmlhead'] .= '<meta property="og:title" content="' . htmlspecialchars($channel['channel_name']) . '">' . "\r\n";
|
||||
App::$page['htmlhead'] .= '<meta property="og:image" content="' . $channel['xchan_photo_l'] . '">' . "\r\n";
|
||||
// Add Opengraph markup
|
||||
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
|
||||
App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(App::$profile['about']) . '">' . "\r\n";
|
||||
}
|
||||
else {
|
||||
App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(sprintf( t('This is the home page of %s.'), $channel['channel_name'])) . '">' . "\r\n";
|
||||
}
|
||||
if($mid)
|
||||
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
|
||||
dbesc($mid),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
|
||||
opengraph_add_meta($r ? $r[0] : [], $channel);
|
||||
}
|
||||
|
||||
function get($update = 0, $load = false) {
|
||||
@ -362,7 +364,7 @@ class Channel extends Controller {
|
||||
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id
|
||||
$r = q("SELECT item.*, item.id AS item_id
|
||||
FROM item
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@ -371,8 +373,8 @@ class Channel extends Controller {
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,$ordering);
|
||||
|
||||
if($load && $mid && (! count($items))) {
|
||||
|
@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
||||
if (argc() > 1)
|
||||
$which = argv(1);
|
||||
|
||||
|
||||
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
construct_page();
|
||||
killme();
|
||||
}
|
||||
|
||||
$profile = 0;
|
||||
|
||||
if ($which)
|
||||
|
@ -322,7 +322,10 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
|
||||
'recent_label' => t('Recent activity'),
|
||||
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
|
||||
'oneway' => $oneway
|
||||
'oneway' => $oneway,
|
||||
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
|
||||
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
|
||||
'connect_hover' => t('Connect at this location')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||
$auth->observer = get_observer_hash();
|
||||
|
||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
||||
|
||||
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
||||
|
@ -287,7 +287,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
|
||||
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
|
||||
|
||||
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
|
||||
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
|
||||
|
||||
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
|
||||
|
||||
@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
'pdesc_label' => t('Description:'),
|
||||
'marital' => $marital,
|
||||
'homepage' => $homepage,
|
||||
'homepageurl' => linkify($homepageurl),
|
||||
'homepageurl' => linkify($homepageurl, true),
|
||||
'hometown' => $hometown,
|
||||
'hometown_label' => t('Hometown:'),
|
||||
'about' => $about,
|
||||
|
@ -817,11 +817,6 @@ class Item extends Controller {
|
||||
'revision' => $r['data']['revision']
|
||||
);
|
||||
}
|
||||
$ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
|
||||
if(strpos($r['data']['filetype'],'audio/') !== false)
|
||||
$attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
|
||||
elseif(strpos($r['data']['filetype'],'video/') !== false)
|
||||
$attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
|
||||
$body = str_replace($match[1][$i],$attach_link,$body);
|
||||
$i++;
|
||||
}
|
||||
@ -1232,13 +1227,7 @@ class Item extends Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(($parent) && ($parent != $post_id)) {
|
||||
// Store the comment signature information in case we need to relay to Diaspora
|
||||
//$ditem = $datarray;
|
||||
//$ditem['author'] = $observer;
|
||||
//store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
|
||||
}
|
||||
else {
|
||||
if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($post_id)
|
||||
);
|
||||
|
@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
|
||||
if($_REQUEST['menu_system'])
|
||||
$_REQUEST['menu_flags'] |= MENU_SYSTEM;
|
||||
|
||||
$menu_id = ((argc() > 1) ? intval(argv(1)) : 0);
|
||||
$menu_id = ((argc() > 2) ? intval(argv(2)) : 0);
|
||||
|
||||
if($menu_id) {
|
||||
$_REQUEST['menu_id'] = intval(argv(1));
|
||||
$_REQUEST['menu_id'] = $menu_id;
|
||||
$r = menu_edit($_REQUEST);
|
||||
if($r) {
|
||||
menu_sync_packet($uid,get_observer_hash(),$menu_id);
|
||||
|
@ -31,12 +31,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
$cache_mode = array(
|
||||
'on' => false,
|
||||
'age' => 86400,
|
||||
'exp' => true,
|
||||
'leak' => false
|
||||
);
|
||||
$cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
|
||||
call_hooks('cache_mode_hook', $cache_mode);
|
||||
|
||||
$observer_xchan = get_observer_hash();
|
||||
@ -144,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$resolution = 1;
|
||||
}
|
||||
|
||||
$r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||
dbesc($photo),
|
||||
intval($resolution)
|
||||
);
|
||||
@ -163,13 +158,10 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
if($u === PHOTO_CACHE) {
|
||||
// Validate cache
|
||||
if($cache_mode['on']) {
|
||||
$cache = array(
|
||||
'resid' => $photo,
|
||||
'status' => false
|
||||
);
|
||||
$cache = [ 'status' => false, 'item' => $r[0] ];
|
||||
call_hooks('cache_url_hook', $cache);
|
||||
if(! $cache['status']) {
|
||||
$url = html_entity_decode($r[0]['display_path'], ENT_QUOTES);
|
||||
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
|
||||
// SSLify if needed
|
||||
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
||||
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
||||
@ -229,7 +221,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
|
||||
header_remove('Pragma');
|
||||
|
||||
if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
|
||||
if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) {
|
||||
header_remove('Expires');
|
||||
header_remove('Cache-Control');
|
||||
header_remove('Set-Cookie');
|
||||
@ -272,7 +264,12 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$maxage = $expires - time();
|
||||
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
|
||||
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
|
||||
|
||||
// set CDN/Infrastructure caching much lower than maxage
|
||||
// in the event that infrastructure caching is present.
|
||||
$smaxage = intval($maxage/12);
|
||||
|
||||
header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1080,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$comments = '';
|
||||
if(! $r) {
|
||||
if($observer && ($can_post || $can_comment)) {
|
||||
$feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
|
||||
$commentbox = replace_macros($cmnt_tpl,array(
|
||||
'$return_path' => '',
|
||||
'$mode' => 'photos',
|
||||
@ -1096,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
'$submit' => t('Submit'),
|
||||
'$preview' => t('Preview'),
|
||||
'$ww' => '',
|
||||
'$feature_encrypt' => false,
|
||||
'$auto_save_draft' => $feature_auto_save_draft
|
||||
'$feature_encrypt' => false
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,22 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
if(strpos($r['data']['filetype'],'audio') === 0) {
|
||||
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
|
||||
echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
|
||||
$s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
|
||||
}
|
||||
if ($r['data']['filetype'] === 'image/svg+xml') {
|
||||
$x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
|
||||
if ($x) {
|
||||
$bb = svg2bb($x);
|
||||
if ($bb) {
|
||||
$s .= "\n\n" . $bb;
|
||||
}
|
||||
else {
|
||||
logger('empty return from svgbb');
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
|
||||
}
|
||||
}
|
||||
|
||||
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
|
||||
|
@ -64,6 +64,18 @@ class Well_known extends \Zotlabs\Web\Controller {
|
||||
echo file_get_contents('doc/dnt-policy.txt');
|
||||
killme();
|
||||
|
||||
case 'caldav':
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
|
||||
http_status('301', 'moved permanently');
|
||||
goaway(z_root() . '/cdav');
|
||||
};
|
||||
|
||||
case 'carddav':
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
|
||||
http_status('301', 'moved permanently');
|
||||
goaway(z_root() . '/cdav');
|
||||
};
|
||||
|
||||
default:
|
||||
if(file_exists(\App::$cmd)) {
|
||||
echo file_get_contents(\App::$cmd);
|
||||
|
@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
|
||||
|
||||
$result['project'] = 'Hubzilla';
|
||||
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
|
||||
$result['success'] = true;
|
||||
json_return_and_die($result);
|
||||
|
@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
* @return array Directory[]
|
||||
*/
|
||||
function ChannelList(&$auth) {
|
||||
$ret = array();
|
||||
$ret = [];
|
||||
|
||||
if (intval(get_config('system','cloud_disable_siteroot'))) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
|
||||
intval(PAGE_HIDDEN)
|
||||
@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
foreach ($r as $rr) {
|
||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
||||
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
||||
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
|
||||
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
|
||||
$ret[] = new Directory($rr['channel_address'], $auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class Router {
|
||||
$routes = Route::get();
|
||||
if($routes) {
|
||||
foreach($routes as $route) {
|
||||
if(is_array($route) && strtolower($route[1]) === $module) {
|
||||
if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
|
||||
include_once($route[0]);
|
||||
if(class_exists($modname)) {
|
||||
$this->controller = new $modname;
|
||||
|
@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
|
||||
|
||||
function write ($id, $data) {
|
||||
|
||||
// Pretend everything is hunky-dory, even though it isn't.
|
||||
// There probably isn't anything we can do about it in any event.
|
||||
// See: https://stackoverflow.com/a/43636110
|
||||
|
||||
if(! $id || ! $data) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Unless we authenticate somehow, only keep a session for 5 minutes
|
||||
// The viewer can extend this by performing any web action using the
|
||||
// original cookie, but this allows us to cleanup the hundreds or
|
||||
|
5
boot.php
5
boot.php
@ -50,7 +50,7 @@ require_once('include/attach.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
define ( 'PLATFORM_NAME', 'hubzilla' );
|
||||
define ( 'STD_VERSION', '4.4.1' );
|
||||
define ( 'STD_VERSION', '4.6' );
|
||||
define ( 'ZOT_REVISION', '6.0a' );
|
||||
|
||||
define ( 'DB_UPDATE_VERSION', 1234 );
|
||||
@ -1205,7 +1205,8 @@ class App {
|
||||
'$linkrel' => head_get_links(),
|
||||
'$js_strings' => js_strings(),
|
||||
'$zid' => get_my_address(),
|
||||
'$channel_id' => self::$profile['uid']
|
||||
'$channel_id' => self::$profile['uid'],
|
||||
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
|
||||
]
|
||||
) . self::$page['htmlhead'];
|
||||
|
||||
|
@ -28,19 +28,19 @@
|
||||
"ext-mbstring" : "*",
|
||||
"ext-xml" : "*",
|
||||
"ext-openssl" : "*",
|
||||
"sabre/dav" : "~3.2",
|
||||
"sabre/dav" : "^4.0",
|
||||
"michelf/php-markdown" : "^1.7",
|
||||
"bshaffer/oauth2-server-php": "^1.9",
|
||||
"ezyang/htmlpurifier": "^4.9",
|
||||
"simplepie/simplepie": "~1.5",
|
||||
"league/html-to-markdown": "^4.4",
|
||||
"pear/text_languagedetect": "^1.0",
|
||||
"commerceguys/intl": "~0.7",
|
||||
"lukasreschke/id3parser": "^0.0.1",
|
||||
"commerceguys/intl": "~1.0.5",
|
||||
"lukasreschke/id3parser": "^0.0.3",
|
||||
"smarty/smarty": "~3.1",
|
||||
"ramsey/uuid": "^3.8",
|
||||
"twbs/bootstrap": "^4.3.1",
|
||||
"blueimp/jquery-file-upload": "^9.25",
|
||||
"blueimp/jquery-file-upload": "^10.3",
|
||||
"desandro/imagesloaded": "^4.1"
|
||||
},
|
||||
"require-dev" : {
|
||||
|
218
composer.lock
generated
218
composer.lock
generated
@ -4,20 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f4dce457cd65f92a26d8197617f2f560",
|
||||
"content-hash": "1869554b567d2e0c8d16978035b7197e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "blueimp/jquery-file-upload",
|
||||
"version": "v9.31.0",
|
||||
"version": "v10.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
|
||||
"reference": "2485bf016e1085f0cd8308723064458cb0af5729"
|
||||
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/2485bf016e1085f0cd8308723064458cb0af5729",
|
||||
"reference": "2485bf016e1085f0cd8308723064458cb0af5729",
|
||||
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -59,7 +59,7 @@
|
||||
"upload",
|
||||
"widget"
|
||||
],
|
||||
"time": "2019-05-24T07:59:46+00:00"
|
||||
"time": "2019-11-04T09:18:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bshaffer/oauth2-server-php",
|
||||
@ -121,20 +121,20 @@
|
||||
},
|
||||
{
|
||||
"name": "commerceguys/intl",
|
||||
"version": "v0.7.5",
|
||||
"version": "v1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/commerceguys/intl.git",
|
||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6"
|
||||
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6",
|
||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6",
|
||||
"url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "1.*",
|
||||
@ -143,7 +143,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.x-dev"
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -161,7 +161,7 @@
|
||||
}
|
||||
],
|
||||
"description": "Internationalization library powered by CLDR data.",
|
||||
"time": "2017-12-29T00:13:05+00:00"
|
||||
"time": "2019-10-22T10:40:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "desandro/imagesloaded",
|
||||
@ -204,23 +204,23 @@
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.10.0",
|
||||
"version": "v4.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021"
|
||||
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
|
||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"simpletest/simpletest": "^1.1"
|
||||
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -233,7 +233,7 @@
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL"
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@ -247,20 +247,20 @@
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"time": "2018-02-23T01:58:20+00:00"
|
||||
"time": "2019-10-28T03:44:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
"version": "4.8.1",
|
||||
"version": "4.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
|
||||
"reference": "71319108e3db506250b8987721b13568fd9fa446"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
|
||||
"reference": "71319108e3db506250b8987721b13568fd9fa446",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -270,7 +270,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||
"phpunit/phpunit": "4.*",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"scrutinizer/ocular": "~1.1"
|
||||
},
|
||||
"bin": [
|
||||
@ -279,7 +279,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.9-dev"
|
||||
"dev-master": "4.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -292,17 +292,17 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nick Cernis",
|
||||
"email": "nick@cern.is",
|
||||
"homepage": "http://modernnerd.net",
|
||||
"role": "Original Author"
|
||||
},
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Nick Cernis",
|
||||
"email": "nick@cern.is",
|
||||
"homepage": "http://modernnerd.net",
|
||||
"role": "Original Author"
|
||||
}
|
||||
],
|
||||
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||
@ -311,20 +311,20 @@
|
||||
"html",
|
||||
"markdown"
|
||||
],
|
||||
"time": "2018-12-24T17:21:44+00:00"
|
||||
"time": "2019-11-02T14:54:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lukasreschke/id3parser",
|
||||
"version": "v0.0.1",
|
||||
"version": "v0.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/LukasReschke/ID3Parser.git",
|
||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a"
|
||||
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
||||
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -346,7 +346,7 @@
|
||||
"php",
|
||||
"tags"
|
||||
],
|
||||
"time": "2016-04-04T09:34:50+00:00"
|
||||
"time": "2016-09-22T15:10:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "michelf/php-markdown",
|
||||
@ -485,16 +485,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
|
||||
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -503,7 +503,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -528,7 +528,7 @@
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2018-11-20T15:27:04+00:00"
|
||||
"time": "2019-11-01T11:05:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
@ -614,16 +614,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sabre/dav",
|
||||
"version": "3.2.3",
|
||||
"version": "4.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/dav.git",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
|
||||
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -631,27 +631,28 @@
|
||||
"ext-date": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-spl": "*",
|
||||
"lib-libxml": ">=2.7.0",
|
||||
"php": ">=5.5.0",
|
||||
"php": ">=7.0.0",
|
||||
"psr/log": "^1.0",
|
||||
"sabre/event": ">=2.0.0, <4.0.0",
|
||||
"sabre/http": "^4.2.1",
|
||||
"sabre/uri": "^1.0.1",
|
||||
"sabre/vobject": "^4.1.0",
|
||||
"sabre/xml": "^1.4.0"
|
||||
"sabre/event": "^5.0",
|
||||
"sabre/http": "^5.0",
|
||||
"sabre/uri": "^2.0",
|
||||
"sabre/vobject": "^4.2.0-alpha1",
|
||||
"sabre/xml": "^2.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"evert/phpdoc-md": "~0.1.0",
|
||||
"monolog/monolog": "^1.18",
|
||||
"phpunit/phpunit": "> 4.8, <6.0.0",
|
||||
"sabre/cs": "^1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "*",
|
||||
"ext-imap": "*",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"bin": [
|
||||
@ -659,11 +660,6 @@
|
||||
"bin/naturalselection"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sabre\\DAV\\": "lib/DAV/",
|
||||
@ -693,28 +689,28 @@
|
||||
"framework",
|
||||
"iCalendar"
|
||||
],
|
||||
"time": "2018-10-19T09:58:27+00:00"
|
||||
"time": "2019-10-19T07:17:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/event",
|
||||
"version": "3.0.0",
|
||||
"version": "5.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/event.git",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
|
||||
"reference": "f5cf802d240df1257866d8813282b98aee3bc548"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
|
||||
"reference": "f5cf802d240df1257866d8813282b98aee3bc548",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"sabre/cs": "~0.0.4"
|
||||
"phpunit/phpunit": ">=6",
|
||||
"sabre/cs": "~1.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -744,38 +740,41 @@
|
||||
"keywords": [
|
||||
"EventEmitter",
|
||||
"async",
|
||||
"coroutine",
|
||||
"eventloop",
|
||||
"events",
|
||||
"hooks",
|
||||
"plugin",
|
||||
"promise",
|
||||
"reactor",
|
||||
"signal"
|
||||
],
|
||||
"time": "2015-11-05T20:14:39+00:00"
|
||||
"time": "2018-03-05T13:55:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/http",
|
||||
"version": "v4.2.4",
|
||||
"version": "5.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/http.git",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
|
||||
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.4",
|
||||
"sabre/event": ">=1.0.0,<4.0.0",
|
||||
"sabre/uri": "~1.0"
|
||||
"php": "^7.0",
|
||||
"sabre/event": ">=4.0 <6.0",
|
||||
"sabre/uri": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3",
|
||||
"sabre/cs": "~0.0.1"
|
||||
"phpunit/phpunit": "^6.0 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": " to make http requests with the Client class"
|
||||
@ -806,28 +805,27 @@
|
||||
"keywords": [
|
||||
"http"
|
||||
],
|
||||
"time": "2018-02-23T11:10:29+00:00"
|
||||
"time": "2019-10-09T20:27:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/uri",
|
||||
"version": "1.2.1",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/uri.git",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61"
|
||||
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.7"
|
||||
"php": ">=7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.0,<6.0",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -857,7 +855,7 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-02-20T19:59:28+00:00"
|
||||
"time": "2019-09-09T23:00:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
@ -957,16 +955,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
"version": "1.5.1",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/xml.git",
|
||||
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e"
|
||||
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e",
|
||||
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -974,12 +972,11 @@
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"lib-libxml": ">=2.6.20",
|
||||
"php": ">=5.5.5",
|
||||
"php": ">=7.0",
|
||||
"sabre/uri": ">=1.0,<3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8|~5.7",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -1016,20 +1013,20 @@
|
||||
"dom",
|
||||
"xml"
|
||||
],
|
||||
"time": "2019-01-09T13:51:57+00:00"
|
||||
"time": "2019-08-14T15:41:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "simplepie/simplepie",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/simplepie/simplepie.git",
|
||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263"
|
||||
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263",
|
||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263",
|
||||
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1088,28 +1085,31 @@
|
||||
"rss"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/simplepie/simplepie/tree/1.5.2",
|
||||
"source": "https://github.com/simplepie/simplepie/tree/1.5.3",
|
||||
"issues": "https://github.com/simplepie/simplepie/issues"
|
||||
},
|
||||
"time": "2018-08-02T05:43:58+00:00"
|
||||
"time": "2019-09-22T23:21:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "smarty/smarty",
|
||||
"version": "v3.1.33",
|
||||
"version": "v3.1.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/smarty-php/smarty.git",
|
||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
|
||||
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "6.4.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -1117,8 +1117,8 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"libs/bootstrap.php"
|
||||
"classmap": [
|
||||
"libs/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -1144,7 +1144,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2018-09-12T20:54:16+00:00"
|
||||
"time": "2019-02-28T06:42:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -1,3 +1,12 @@
|
||||
[h2]Database updates[/h2]
|
||||
|
||||
In the [observer.baseurl]/admin/dbsync page the administrator can check if any update was not successful and, if so, retry it.
|
||||
|
||||
If an update has failed but doesn't register as failed for some reason, the administrator can attempt to re-execute the update. For example for DB update #1999, by visiting the webpage:
|
||||
|
||||
https://hubzilla.com.bradmin/dbsync/1999
|
||||
|
||||
|
||||
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
|
||||
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
|
||||
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
|
||||
|
@ -1,7 +1,10 @@
|
||||
[h1]Advanced Configurations for Administrators[/h1]
|
||||
$Projectname contains many configuration options hidden from the main admin panel.
|
||||
|
||||
These are generally options considered too niche, confusing, or advanced for the average member. These settings can be activated from the the top level web directory with the syntax
|
||||
[i]This document assumes you're an administrator.[/i]
|
||||
|
||||
$Projectname contains many configuration options hidden from the main admin panel. These are generally options considered too niche, advanced or prone do confusion.
|
||||
|
||||
These settings can be modified through the shell, from the the top level web directory, with the syntax:
|
||||
|
||||
[code]util/config cat key value[/code]
|
||||
for a site configuration, or
|
||||
@ -9,8 +12,13 @@ for a site configuration, or
|
||||
[code]util/pconfig channel_id cat key value[/code]
|
||||
for a member configuration.
|
||||
|
||||
This document assumes you're an administrator.
|
||||
[h2]pconfig[/h2][dl terms="mb"]
|
||||
For a site configuration, another option is to add a line to .htconfig.php, with the syntax:
|
||||
[code]App::$config['cat']['key'] = 'value';[/code]
|
||||
|
||||
|
||||
[h2]Member configuration (pconfig)[/h2]
|
||||
|
||||
[dl terms="mb"]
|
||||
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
|
||||
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
|
||||
[*= system.default_cipher ] Set the default cipher used for E2EE items.
|
||||
@ -31,7 +39,10 @@ Options are:
|
||||
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
|
||||
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
|
||||
[/dl]
|
||||
[h2]Site config[/h2][dl terms="mb"]
|
||||
|
||||
[h2]Site configuration[/h2]
|
||||
|
||||
[dl terms="mb"]
|
||||
[*= randprofile.check ] When requesting a random profile, check that it actually exists first
|
||||
[*= randprofile.retry ] Number of times to retry getting a random profile
|
||||
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
|
||||
@ -62,6 +73,7 @@ Options are:
|
||||
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
|
||||
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
|
||||
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
|
||||
[*= system.object_cache_days] Set how long is cached embedded content can be used without refetching. Default is 30 days.
|
||||
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
|
||||
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
|
||||
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
|
||||
@ -87,13 +99,19 @@ Options are:
|
||||
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
|
||||
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
|
||||
[/dl]
|
||||
[h2]Directory config[/h2]
|
||||
[h3]Directory search defaults[/h3][dl terms="mb"]
|
||||
|
||||
|
||||
[h3]Directory config[/h3]
|
||||
|
||||
[h4]Directory search defaults[/h4]
|
||||
|
||||
[dl terms="mb"]
|
||||
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
|
||||
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
|
||||
[*= directory.safemode ] 0 or 1.
|
||||
[/dl]
|
||||
[h3]Directory server configuration[/h3][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
|
||||
|
||||
[h4]Directory server configuration[/h4][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
|
||||
|
||||
[dl terms="mb"]
|
||||
[*= system.directory_mode ]
|
||||
|
1
doc/hook/activity_decode_mapper.bb
Normal file
1
doc/hook/activity_decode_mapper.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]activity_decode_mapper[/h2]
|
1
doc/hook/activity_mapper.bb
Normal file
1
doc/hook/activity_mapper.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]activity_mapper[/h2]
|
1
doc/hook/activity_obj_decode_mapper.bb
Normal file
1
doc/hook/activity_obj_decode_mapper.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]activity_obj_decode_mapper[/h2]
|
1
doc/hook/activity_obj_mapper.bb
Normal file
1
doc/hook/activity_obj_mapper.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]activity_obj_mapper[/h2]
|
11
doc/hook/comments_are_now_closed.bb
Normal file
11
doc/hook/comments_are_now_closed.bb
Normal file
@ -0,0 +1,11 @@
|
||||
[h3]comments_are_now_closed[/h3]
|
||||
|
||||
Called when deciding whether or not commenting is closed for an item.
|
||||
|
||||
|
||||
Hook data (array):
|
||||
item => posted item
|
||||
closed => 'unset'
|
||||
|
||||
|
||||
To over-ride the default behaviour, change closed to true or false
|
1
doc/hook/encode_object.bb
Normal file
1
doc/hook/encode_object.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]encode_object[/h2]
|
1
doc/hook/fetch_and_store.bb
Normal file
1
doc/hook/fetch_and_store.bb
Normal file
@ -0,0 +1 @@
|
||||
[h2]fetch_and_store[/h2]
|
@ -34,6 +34,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
|
||||
Called when generating the list of filters for the network page
|
||||
|
||||
[zrl=[baseurl]/help/hook/activity_filter]activity_mapper[/zrl]
|
||||
Called when determining the activity type for transmission.
|
||||
|
||||
[zrl=[baseurl]/help/hook/activity_filter]activity_decode_mapper[/zrl]
|
||||
Called when determining the activity type for transmission.
|
||||
|
||||
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_mapper[/zrl]
|
||||
Called when determining the object type for transmission.
|
||||
|
||||
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_decode_mapper[/zrl]
|
||||
Called when determining the object type for transmission.
|
||||
|
||||
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
|
||||
Called when generating the list of order options for the network page
|
||||
|
||||
@ -142,6 +154,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
|
||||
Called when rendering the edit buttons for comments
|
||||
|
||||
[zrl=[baseurl]/help/hook/comments_are_now_closed]comments_are_now_closed[/zrl]
|
||||
Called when deciding whether or not to present a comment box for a post
|
||||
|
||||
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
|
||||
Called when connecting to a premium channel
|
||||
|
||||
@ -232,6 +247,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
|
||||
called when an 'item' is removed
|
||||
|
||||
[zrl=[baseurl]/help/hook/encode_object]encode_object[/zrl]
|
||||
called when encoding an object for transmission.
|
||||
|
||||
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
|
||||
called before any notification
|
||||
|
||||
@ -262,6 +280,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
|
||||
called from settings page when posting from 'addon/feature settings'
|
||||
|
||||
[zrl=[baseurl]/help/hook/fetch_and_store]fetch_and_store[/zrl]
|
||||
called to allow filtering of 'decoded' items before storage.
|
||||
|
||||
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
|
||||
called when generating thumbnail images for cloud page in 'view tiles' mode
|
||||
|
||||
|
@ -37,7 +37,8 @@
|
||||
<div class="flex-column">
|
||||
<a class="nav-link" href="/help/admin/administrator_guide">Guide</a>
|
||||
<a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a>
|
||||
<a class="nav-link" href="/help/database">Database Tables</a>
|
||||
<a class="nav-link" href="/help/database">Database</a>
|
||||
<a class="nav-link" href="/help/hidden_configs">Extra configs</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,6 +4,8 @@
|
||||
* @brief BBCode related functions for parsing, etc.
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\SvgSanitizer;
|
||||
|
||||
require_once('include/oembed.php');
|
||||
require_once('include/event.php');
|
||||
require_once('include/zot.php');
|
||||
@ -267,6 +269,22 @@ function bb_parse_app($match) {
|
||||
return Zotlabs\Lib\Apps::app_render($app);
|
||||
}
|
||||
|
||||
function bb_svg($match) {
|
||||
|
||||
$params = str_replace(['<br>', '"'], [ '', '"'],$match[1]);
|
||||
$Text = str_replace([ '[',']' ], [ '<','>' ], $match[2]);
|
||||
|
||||
$output = '<svg' . (($params) ? $params : ' width="100%" height="480" ') . '>' . str_replace(['<br>', '"', ' '], [ '', '"', ' '],$Text) . '</svg>';
|
||||
|
||||
$purify = new SvgSanitizer();
|
||||
$purify->loadXML($output);
|
||||
$purify->sanitize();
|
||||
$output = $purify->saveSVG();
|
||||
$output = preg_replace("/\<\?xml(.*?)\?\>/",'',$output);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
function bb_parse_element($match) {
|
||||
$j = json_decode(base64url_decode($match[1]),true);
|
||||
|
||||
@ -948,9 +966,9 @@ function bbcode($Text, $options = []) {
|
||||
|
||||
if (strpos($Text,'http') !== false) {
|
||||
if($tryoembed) {
|
||||
$Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
|
||||
$Text = preg_replace_callback("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
|
||||
}
|
||||
$Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
|
||||
$Text = preg_replace("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
|
||||
}
|
||||
|
||||
if (strpos($Text,'[/share]') !== false) {
|
||||
@ -1289,6 +1307,9 @@ function bbcode($Text, $options = []) {
|
||||
$Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
|
||||
}
|
||||
|
||||
// SVG stuff
|
||||
$Text = preg_replace_callback("/\[svg(.*?)\](.*?)\[\/svg\]/ism", 'bb_svg', $Text);
|
||||
|
||||
// Try to Oembed
|
||||
if ($tryoembed) {
|
||||
if (strpos($Text,'[/video]') !== false) {
|
||||
@ -1346,6 +1367,7 @@ function bbcode($Text, $options = []) {
|
||||
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
|
||||
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
|
||||
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
|
||||
$Text = preg_replace("/\[event\-timezone\](.*?)\[\/event\-timezone\]/ism",'',$Text);
|
||||
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
|
||||
|
||||
$Text = str_replace("\0",'$',$Text);
|
||||
|
@ -1718,9 +1718,9 @@ function advanced_profile() {
|
||||
|
||||
if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] );
|
||||
|
||||
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) );
|
||||
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage'], true) );
|
||||
|
||||
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) );
|
||||
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown'], true) );
|
||||
|
||||
if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']);
|
||||
|
||||
@ -2254,19 +2254,19 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
|
||||
$cover_width = 425;
|
||||
$size = 'hz_small';
|
||||
$cover_size = PHOTO_RES_COVER_425;
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||
} elseif($maxwidth <= 900) {
|
||||
$width = 900;
|
||||
$cover_width = 850;
|
||||
$size = 'hz_medium';
|
||||
$cover_size = PHOTO_RES_COVER_850;
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||
} elseif($maxwidth <= 1200) {
|
||||
$width = 1200;
|
||||
$cover_width = 1200;
|
||||
$size = 'hz_large';
|
||||
$cover_size = PHOTO_RES_COVER_1200;
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
|
||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||
}
|
||||
|
||||
// $scale = (float) $maxwidth / $width;
|
||||
|
@ -299,6 +299,11 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
|
||||
$r = q("delete from pgrp_member where xchan = '%s'",
|
||||
dbesc($xchan)
|
||||
);
|
||||
|
||||
// Cannot delete just one side of the conversation since we do not allow
|
||||
// you to block private mail replies. This would leave open a gateway for abuse.
|
||||
// Both participants are owners of the conversation and both can remove it.
|
||||
|
||||
$r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )",
|
||||
dbesc($xchan),
|
||||
dbesc($xchan)
|
||||
|
@ -276,6 +276,9 @@ function format_event_bbcode($ev) {
|
||||
if($ev['event_hash'])
|
||||
$o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
|
||||
|
||||
if($ev['timezone'])
|
||||
$o .= '[event-timezone]' . $ev['timezone'] . '[/event-timezone]';
|
||||
|
||||
if($ev['adjust'])
|
||||
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
|
||||
|
||||
@ -324,6 +327,9 @@ function bbtoevent($s) {
|
||||
if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match))
|
||||
$ev['event_hash'] = $match[1];
|
||||
$match = '';
|
||||
if(preg_match("/\[event\-timezone\](.*?)\[\/event\-timezone\]/is",$s,$match))
|
||||
$ev['timezone'] = $match[1];
|
||||
$match = '';
|
||||
if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match))
|
||||
$ev['adjust'] = $match[1];
|
||||
if(array_key_exists('dtstart',$ev)) {
|
||||
|
@ -449,6 +449,18 @@ function get_atom_elements($feed, $item) {
|
||||
|
||||
if (title_is_body($res['title'], $res['body']))
|
||||
$res['title'] = "";
|
||||
else {
|
||||
$res['title'] = bbcode($res['title'], [ 'tryoembed' => false ]);
|
||||
$res['title'] = html2plain($res['title'], 0, true);
|
||||
$res['title'] = html_entity_decode($res['title'], ENT_QUOTES, 'UTF-8');
|
||||
$res['title'] = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $res['title']);
|
||||
while (strpos($res['title'], "\n") !== false)
|
||||
$res['title'] = str_replace("\n", " ", $res['title']);
|
||||
while (strpos($res['title'], " ") !== false)
|
||||
$res['title'] = str_replace(" ", " ", $res['title']);
|
||||
$res['title'] = trim($res['title']);
|
||||
}
|
||||
|
||||
|
||||
if($res['plink'])
|
||||
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
|
||||
@ -1748,7 +1760,11 @@ function handle_feed($uid, $abook_id, $url) {
|
||||
if($z['success']) {
|
||||
consume_feed($z['body'], $channel, $x[0], 1);
|
||||
consume_feed($z['body'], $channel, $x[0], 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -142,7 +142,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
|
||||
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
|
||||
|
||||
|
||||
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options ",
|
||||
$r = q("select * from xchan where (xchan_addr = '%s' or xchan_url = '%s') $sql_options ",
|
||||
dbesc($url),
|
||||
dbesc($url)
|
||||
);
|
||||
|
@ -769,6 +769,23 @@ function import_items($channel, $items, $sync = false, $relocate = null) {
|
||||
* @param array $relocate default null
|
||||
*/
|
||||
function sync_items($channel, $items, $relocate = null) {
|
||||
|
||||
// Check if this is sync of not Zot-related content and we're connected to the top post owner
|
||||
// to avoid confusing with cloned channels
|
||||
$size = count($items);
|
||||
for($i = 0; $i < $size; $i++) {
|
||||
if(($items[$i]['owner']['network'] != 'zot') && ($items[$i]['owner']['network'] != 'zot6')) {
|
||||
$r = q("SELECT * FROM abook WHERE abook_channel = %d
|
||||
AND abook_xchan = ( SELECT xchan_hash FROM xchan WHERE xchan_guid = '%s' LIMIT 1 )
|
||||
AND abook_not_here = 0 AND abook_ignored = 0 AND abook_blocked = 0",
|
||||
intval($channel['channel_id']),
|
||||
dbesc($items[$i]['owner']['guid'])
|
||||
);
|
||||
if(! $r)
|
||||
unset($items[$i]);
|
||||
}
|
||||
}
|
||||
if(count($items) > 0)
|
||||
import_items($channel, $items, true, $relocate);
|
||||
}
|
||||
|
||||
@ -1190,9 +1207,9 @@ function sync_files($channel, $files) {
|
||||
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
|
||||
|
||||
if($x['success']) {
|
||||
$orig_attach = $x[0];
|
||||
$orig_attach = $x['data'];
|
||||
$attach_exists = true;
|
||||
$attach_id = $x[0]['id'];
|
||||
$attach_id = $orig_attach['id'];
|
||||
}
|
||||
|
||||
$newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
|
||||
|
@ -206,6 +206,25 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
|
||||
}
|
||||
|
||||
function comments_are_now_closed($item) {
|
||||
|
||||
$x = [
|
||||
'item' => $item,
|
||||
'closed' => 'unset'
|
||||
];
|
||||
|
||||
/**
|
||||
* @hooks comments_are_now_closed
|
||||
* Called to determine whether commenting should be closed
|
||||
* * \e array \b item
|
||||
* * \e boolean \b closed - return value
|
||||
*/
|
||||
|
||||
call_hooks('comments_are_now_closed', $x);
|
||||
|
||||
if ($x['closed'] != 'unset') {
|
||||
return $x['closed'];
|
||||
}
|
||||
|
||||
if($item['comments_closed'] > NULL_DATE) {
|
||||
$d = datetime_convert();
|
||||
if($d > $item['comments_closed'])
|
||||
@ -1640,20 +1659,14 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
||||
'allow_exec' => $allow_exec
|
||||
];
|
||||
|
||||
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
|
||||
/* Custom items are not stored by default
|
||||
because they require an addon to process. */
|
||||
$d['item']['cancel']=true;
|
||||
|
||||
call_hooks('item_custom',$d);
|
||||
}
|
||||
/**
|
||||
* @hooks item_store
|
||||
* Called when item_store() stores a record of type item.
|
||||
* * \e array \b item
|
||||
* * \e boolean \b allow_exec
|
||||
*/
|
||||
call_hooks('item_store', $d);
|
||||
call_hooks('item_store_before', $d);
|
||||
|
||||
$arr = $d['item'];
|
||||
$allow_exec = $d['allow_exec'];
|
||||
|
||||
@ -1961,6 +1974,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
||||
*/
|
||||
call_hooks('item_store', $arr);
|
||||
|
||||
|
||||
/**
|
||||
* @hooks post_remote
|
||||
* Called when an activity arrives from another site.
|
||||
@ -2129,14 +2143,6 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
|
||||
'allow_exec' => $allow_exec
|
||||
];
|
||||
|
||||
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
|
||||
/* Custom items are not stored by default
|
||||
because they require an addon to process. */
|
||||
$d['item']['cancel']=true;
|
||||
|
||||
call_hooks('item_custom_update',$d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hooks item_store_update
|
||||
* Called when item_store_update() is called to update a stored item. It
|
||||
@ -2144,7 +2150,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
|
||||
* * \e array \b item
|
||||
* * \e boolean \b allow_exec
|
||||
*/
|
||||
call_hooks('item_store_update', $d);
|
||||
call_hooks('item_store_update_before', $d);
|
||||
$arr = $d['item'];
|
||||
$allow_exec = $d['allow_exec'];
|
||||
|
||||
|
@ -247,6 +247,9 @@ function bb_to_markdown($Text, $options = []) {
|
||||
|
||||
$Text = $x['bbcode'];
|
||||
|
||||
// Replace spoiler tag before BBcode conversion
|
||||
$Text = preg_replace("/\[\/?spoiler\]/is", "\n--- " .t('spoiler') . " ---\n", $Text);
|
||||
|
||||
// Convert it to HTML - don't try oembed
|
||||
$Text = bbcode($Text, [ 'tryoembed' => false ]);
|
||||
|
||||
@ -265,6 +268,9 @@ function bb_to_markdown($Text, $options = []) {
|
||||
// Remove empty zrl links
|
||||
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
|
||||
|
||||
// Replace unprocessed <br> in code
|
||||
$Text = str_replace("<br></br>", "\n", $Text);
|
||||
|
||||
$Text = trim($Text);
|
||||
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ function nav($template = 'default') {
|
||||
|
||||
if($observer) {
|
||||
$userinfo = [
|
||||
'icon' => $observer['xchan_photo_m'],
|
||||
'icon' => $observer['xchan_photo_m'].'?rev='.strtotime($observer['xchan_photo_date']),
|
||||
'name' => $observer['xchan_addr'],
|
||||
];
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ function oembed_fetch_url($embedurl){
|
||||
$txt = Cache::get('[' . App::$videowidth . '] ' . $furl);
|
||||
}
|
||||
|
||||
if(strpos(strtolower($embedurl),'.pdf') !== false) {
|
||||
if(strpos(strtolower($embedurl),'.pdf') !== false && get_config('system','inline_pdf')) {
|
||||
$action = 'allow';
|
||||
$j = [
|
||||
'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>',
|
||||
|
72
include/opengraph.php
Normal file
72
include/opengraph.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* @file include/opengraph.php
|
||||
* @brief Add Opengraph metadata and related functions.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds Opengraph meta tags into HTML head
|
||||
*
|
||||
* @param array $item
|
||||
* @param array $channel
|
||||
*
|
||||
*/
|
||||
|
||||
function opengraph_add_meta($item, $channel) {
|
||||
|
||||
if(! empty($item)) {
|
||||
|
||||
if(! empty($item['title']))
|
||||
$ogtitle = $item['title'];
|
||||
|
||||
// find first image if exist
|
||||
if(preg_match("/\[[zi]mg(=[0-9]+x[0-9]+)?\]([^\[]+)/is", $item['body'], $matches)) {
|
||||
$ogimage = $matches[2];
|
||||
$ogimagetype = guess_image_type($ogimage);
|
||||
}
|
||||
|
||||
// use summary as description if exist
|
||||
$ogdesc = (empty($item['summary']) ? $item['body'] : $item['summary'] );
|
||||
|
||||
$ogdesc = str_replace("#^[", "[", $ogdesc);
|
||||
|
||||
$ogdesc = bbcode($ogdesc, [ 'tryoembed' => false ]);
|
||||
$ogdesc = trim(html2plain($ogdesc, 0, true));
|
||||
$ogdesc = html_entity_decode($ogdesc, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// remove all URLs
|
||||
$ogdesc = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $ogdesc);
|
||||
|
||||
// shorten description
|
||||
$ogdesc = substr($ogdesc, 0, 300);
|
||||
$ogdesc = str_replace("\n", " ", $ogdesc);
|
||||
while (strpos($ogdesc, " ") !== false)
|
||||
$ogdesc = str_replace(" ", " ", $ogdesc);
|
||||
$ogdesc = (strlen($ogdesc) < 298 ? $ogdesc : rtrim(substr($ogdesc, 0, strrpos($ogdesc, " ")), "?.,:;!-") . "...");
|
||||
|
||||
$ogtype = "article";
|
||||
}
|
||||
|
||||
if(! isset($ogdesc)) {
|
||||
if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
|
||||
$ogdesc = App::$profile['about'];
|
||||
}
|
||||
else {
|
||||
$ogdesc = sprintf( t('This is the home page of %s.'), $channel['channel_name']);
|
||||
}
|
||||
}
|
||||
|
||||
if(! isset($ogimage)) {
|
||||
$ogimage = $channel['xchan_photo_l'];
|
||||
$ogimagetype = $channel['xchan_photo_mimetype'];
|
||||
}
|
||||
|
||||
App::$page['htmlhead'] .= '<meta property="og:title" content="' . htmlspecialchars((isset($ogtitle) ? $ogtitle : $channel['channel_name'])) . '">' . "\r\n";
|
||||
App::$page['htmlhead'] .= '<meta property="og:image" content="' . $ogimage . '">' . "\r\n";
|
||||
App::$page['htmlhead'] .= '<meta property="og:image:type" content="' . $ogimagetype . '">' . "\r\n";
|
||||
App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars($ogdesc) . '">' . "\r\n";
|
||||
App::$page['htmlhead'] .= '<meta property="og:type" content="' . (isset($ogtype) ? $ogtype : "profile") . '">' . "\r\n";
|
||||
|
||||
return true;
|
||||
}
|
@ -286,7 +286,7 @@ function queue_deliver($outq, $immediate = false) {
|
||||
$host_crypto = null;
|
||||
|
||||
if($channel && $base) {
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
|
||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
|
||||
dbesc($base)
|
||||
);
|
||||
if($h) {
|
||||
|
@ -9,6 +9,8 @@ use Michelf\MarkdownExtra;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||
|
||||
use Zotlabs\Lib\SvgSanitizer;
|
||||
|
||||
require_once("include/bbcode.php");
|
||||
|
||||
// random string, there are 86 characters max in text mode, 128 for hex
|
||||
@ -842,9 +844,9 @@ function get_tags($s) {
|
||||
$ret = array();
|
||||
$match = array();
|
||||
|
||||
// ignore anything in a code block
|
||||
|
||||
// ignore anything in a code or svg block
|
||||
$s = preg_replace('/\[code(.*?)\](.*?)\[\/code\]/sm','',$s);
|
||||
$s = preg_replace('/\[svg(.*?)\](.*?)\[\/svg\]/sm','',$s);
|
||||
|
||||
// ignore anything in [style= ]
|
||||
$s = preg_replace('/\[style=(.*?)\]/sm','',$s);
|
||||
@ -2795,6 +2797,9 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
|
||||
// select someone by attag or nick and the name passed in
|
||||
|
||||
if(! $r) {
|
||||
// strip user-supplied wildcards before running a wildcard search
|
||||
$newname = str_replace('%','',$newname);
|
||||
|
||||
$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE xchan_addr like ('%s') AND abook_channel = %d ",
|
||||
dbesc(((strpos($newname,'@')) ? $newname : $newname . '@%')),
|
||||
@ -3420,17 +3425,19 @@ function cleanup_bbcode($body) {
|
||||
$body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','\red_escape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[svg(.*?)\[\/(svg)\]/ism','\red_escape_codeblock',$body);
|
||||
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
+\,\(\)]+)/ismu", '\nakedoembed', $body);
|
||||
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
+\,\(\)]+)/ismu", '\red_zrl_callback', $body);
|
||||
|
||||
|
||||
$body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','\red_unescape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','\red_unescape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[\$b64svg(.*?)\[\/(svg)\]/ism','\red_unescape_codeblock',$body);
|
||||
|
||||
// fix any img tags that should be zmg
|
||||
|
||||
@ -3656,3 +3663,23 @@ function new_uuid() {
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
|
||||
function svg2bb($s) {
|
||||
|
||||
$s = preg_replace("/\<text (.*?)\>(.*?)\<(.*?)\<\/text\>/", '<text $1>$2<$3</text>', $s);
|
||||
$s = preg_replace("/\<text (.*?)\>(.*?)\>(.*?)\<\/text\>/", '<text $1>$2>$3</text>', $s);
|
||||
$s = preg_replace("/\<text (.*?)\>(.*?)\[(.*?)\<\/text\>/", '<text $1>$2[$3</text>', $s);
|
||||
$s = preg_replace("/\<text (.*?)\>(.*?)\](.*?)\<\/text\>/", '<text $1>$2]$3</text>', $s);
|
||||
$s = utf8_encode($s);
|
||||
$purify = new SvgSanitizer();
|
||||
if ($purify->loadXML($s)) {
|
||||
$purify->sanitize();
|
||||
$output = $purify->saveSVG();
|
||||
$output = preg_replace("/\<\?xml(.*?)\>/",'',$output);
|
||||
$output = preg_replace("/\<\!\-\-(.*?)\-\-\>/",'',$output);
|
||||
$output = str_replace(['<','>'],['[',']'],$output);
|
||||
return $output;
|
||||
}
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
@ -1776,17 +1776,14 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
|
||||
|
||||
$DR = new Zotlabs\Lib\DReport(z_root(),$sender['hash'],$d['hash'],$arr['mid']);
|
||||
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
dbesc($d['hash'])
|
||||
);
|
||||
$channel = channelx_by_hash($d['hash']);
|
||||
|
||||
if(! $r) {
|
||||
if(! $channel) {
|
||||
$DR->update('recipient not found');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
}
|
||||
|
||||
$channel = $r[0];
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
/* blacklisted channels get a permission denied, no special message to tip them off */
|
||||
@ -2032,7 +2029,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
|
||||
// if it's a sourced post, call the post_local hooks as if it were
|
||||
// posted locally so that crosspost connectors will be triggered.
|
||||
|
||||
if(check_item_source($arr['uid'], $arr)) {
|
||||
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
|
||||
/**
|
||||
* @hooks post_local
|
||||
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
||||
@ -2392,7 +2389,6 @@ function process_mail_delivery($sender, $arr, $deliveries) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$r = q("select id, conv_guid from mail where mid = '%s' and channel_id = %d limit 1",
|
||||
dbesc($arr['mid']),
|
||||
intval($channel['channel_id'])
|
||||
|
@ -595,8 +595,8 @@ CREATE TABLE IF NOT EXISTS `item` (
|
||||
`layout_mid` char(191) NOT NULL DEFAULT '',
|
||||
`postopts` text NOT NULL,
|
||||
`route` text NOT NULL,
|
||||
`llink` char(191) NOT NULL DEFAULT '',
|
||||
`plink` char(191) NOT NULL DEFAULT '',
|
||||
`llink` text NOT NULL,
|
||||
`plink` text NOT NULL,
|
||||
`resource_id` char(191) NOT NULL DEFAULT '',
|
||||
`resource_type` char(16) NOT NULL DEFAULT '',
|
||||
`attach` mediumtext NOT NULL,
|
||||
@ -659,7 +659,6 @@ CREATE TABLE IF NOT EXISTS `item` (
|
||||
KEY `commented` (`commented`),
|
||||
KEY `verb` (`verb`),
|
||||
KEY `obj_type` (`obj_type`),
|
||||
KEY `llink` (`llink`),
|
||||
KEY `expires` (`expires`),
|
||||
KEY `revision` (`revision`),
|
||||
KEY `mimetype` (`mimetype`),
|
||||
|
@ -644,7 +644,6 @@ create index "item_resource_type" on item ("resource_type");
|
||||
create index "item_commented" on item ("commented");
|
||||
create index "item_verb" on item ("verb");
|
||||
create index "item_obj_type" on item ("obj_type");
|
||||
create index "item_llink" on item ("llink");
|
||||
create index "item_expires" on item ("expires");
|
||||
create index "item_revision" on item ("revision");
|
||||
create index "item_mimetype" on item ("mimetype");
|
||||
|
2
library/jquery.i18n/.gitignore
vendored
2
library/jquery.i18n/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
build/compiler.jar
|
||||
|
@ -1,19 +0,0 @@
|
||||
Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
|
||||
|
||||
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.
|
@ -1,152 +0,0 @@
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
_jQuery-i18n_ is a jQuery plugin for doing client-side translations in javascript. It is based heavily on [javascript i18n that almost doesn't suck](http://markos.gaivo.net/blog/?p=100) by Marko Samastur, and is licensed under the [MIT license](http://www.opensource.org/licenses/mit-license.php).
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You'll need to download the [jQuery library](http://docs.jquery.com/Downloading_jQuery#Current_Release), and include it before _jquery.i18n.js_ in your HTML source. See the _examples_ folder for examples.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Before you can do any translation you have to initialise the plugin with a 'dictionary' (basically a property list mapping keys to their translations).
|
||||
|
||||
```javascript
|
||||
var my_dictionary = {
|
||||
'some text': 'a translation',
|
||||
'some more text': 'another translation'
|
||||
}
|
||||
$.i18n.setDictionary(my_dictionary);
|
||||
```
|
||||
|
||||
Once you've initialised it with a dictionary, you can translate strings using the $.i18n._() function, for example:
|
||||
|
||||
```javascript
|
||||
$('div#example').text($.i18n._('some text'));
|
||||
```
|
||||
|
||||
or using $('selector')._t() function
|
||||
|
||||
```javascript
|
||||
$('div#example')._t('some text');
|
||||
```
|
||||
|
||||
Wildcards
|
||||
---------
|
||||
|
||||
It's straightforward to pass dynamic data into your translations. First, add _%s_ in the translation for each variable you want to swap in :
|
||||
|
||||
```javascript
|
||||
var my_dictionary = {
|
||||
"wildcard example" : "We have been passed two values : %s and %s."
|
||||
}
|
||||
$.i18n.setDictionary(my_dictionary);
|
||||
```
|
||||
|
||||
Next, pass an array of values in as the second argument when you perform the translation :
|
||||
|
||||
```javascript
|
||||
$('div#example').text($.i18n._('wildcard example', [100, 200]));
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```javascript
|
||||
$('div#example')._t('wildcard example', [100, 200]);
|
||||
```
|
||||
|
||||
This will output _We have been passed two values : 100 and 200._
|
||||
|
||||
Because some languages will need to order arguments differently to english, you can also specify the order in which the variables appear :
|
||||
|
||||
```javascript
|
||||
var my_dictionary = {
|
||||
"wildcard example" : "We have been passed two values : %2$s and %1$s."
|
||||
}
|
||||
$.i18n.setDictionary(my_dictionary);
|
||||
|
||||
$('div#example').text($.i18n._('wildcard example', [100, 200]));
|
||||
```
|
||||
|
||||
This will output: _We have been passed two values: 200 and 100._
|
||||
|
||||
Building From Scratch
|
||||
---------------------
|
||||
|
||||
You can build the regular, un-minified version simply by running _ant_:
|
||||
|
||||
```bash
|
||||
$ ant
|
||||
Buildfile: build.xml
|
||||
|
||||
jquery.i18n:
|
||||
[echo] Building ./jquery.i18n.js
|
||||
[echo] ./jquery.i18n.js built.
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
Total time: 0 seconds
|
||||
```
|
||||
|
||||
Before you can build the minified version yourself, you'll need to download the [Google Closure Compiler](http://closure-compiler.googlecode.com/files/compiler-latest.zip) and put it in a folder called _build_:
|
||||
|
||||
```bash
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ wget http://closure-compiler.googlecode.com/files/compiler-latest.zip
|
||||
$ unzip compiler-latest.zip
|
||||
```
|
||||
|
||||
Once you have the compiler, you can build the minified version by running _ant min_:
|
||||
|
||||
```bash
|
||||
$ ant min
|
||||
Buildfile: build.xml
|
||||
|
||||
jquery.i18n:
|
||||
[echo] Building ./jquery.i18n.js
|
||||
[echo] ./jquery.i18n.js built.
|
||||
|
||||
min:
|
||||
[echo] Building ./jquery.i18n.min.js
|
||||
[apply] Applied java to 1 file and 0 directories.
|
||||
[delete] Deleting: /Users/dave/Documents/Code/jquery/jquery-i18n/tmpmin
|
||||
[echo] ./jquery.i18n.min.js built.
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
Total time: 1 second
|
||||
```
|
||||
|
||||
Bug Reports
|
||||
-----------
|
||||
|
||||
If you come across any problems, please [create a ticket](https://github.com/recurser/jquery-i18n/issues) and we'll try to get it fixed as soon as possible.
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Once you've made your commits:
|
||||
|
||||
1. [Fork](http://help.github.com/fork-a-repo/) jquery-i18n
|
||||
2. Create a topic branch - `git checkout -b my_branch`
|
||||
3. Push to your branch - `git push origin my_branch`
|
||||
4. Create a [Pull Request](http://help.github.com/pull-requests/) from your branch
|
||||
5. That's it!
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
Dave Perrett :: mail@recursive-design.com :: [@recurser](http://twitter.com/recurser)
|
||||
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
Copyright (c) 2010 Dave Perrett. See [License](https://github.com/recurser/jquery-i18n/blob/master/LICENSE) for details.
|
||||
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
0.9.2
|
@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="jquery.i18n" default="jquery.i18n" basedir=".">
|
||||
|
||||
<tstamp />
|
||||
|
||||
<loadfile property="version" srcfile="VERSION"/>
|
||||
|
||||
<property description="Folder for jquery.i18n and min target" name="dist" value="."/>
|
||||
<property name="JQI" value="${dist}/jquery.i18n.js"/>
|
||||
<property name="JQI_MIN" value="${dist}/jquery.i18n.min.js"/>
|
||||
|
||||
<target name="jquery.i18n" description="Main jquery.i18n build, concatenates source files and replaces @VERSION">
|
||||
<echo message="Building ${JQI}"/>
|
||||
<mkdir dir="${dist}"/>
|
||||
<concat destfile="${JQI}">
|
||||
<fileset file="src/jquery.i18n.js"/>
|
||||
</concat>
|
||||
<replaceregexp match="@VERSION" replace="${version}" flags="g" byline="true" file="${JQI}"/>
|
||||
<replaceregexp match="@DATE" replace="${DSTAMP}${TSTAMP}" file="${JQI}"/>
|
||||
<echo message="${JQI} built."/>
|
||||
</target>
|
||||
|
||||
<target name="min" depends="jquery.i18n" description="Remove all comments and whitespace, no compression, great in combination with GZip">
|
||||
<echo message="Building ${JQI_MIN}"/>
|
||||
<apply executable="java" parallel="false" verbose="true" dest="${dist}">
|
||||
<fileset dir="${dist}">
|
||||
<include name="jquery.i18n.js"/>
|
||||
</fileset>
|
||||
<arg line="-jar"/>
|
||||
<arg path="build/compiler.jar"/>
|
||||
<arg value="--warning_level"/>
|
||||
<arg value="QUIET"/>
|
||||
<arg value="--js_output_file"/>
|
||||
<targetfile/>
|
||||
<arg value="--js"/>
|
||||
<mapper type="glob" from="jquery.i18n.js" to="tmpmin"/>
|
||||
</apply>
|
||||
<concat destfile="${JQI_MIN}">
|
||||
<filelist files="${JQI}, tmpmin"/>
|
||||
<filterchain>
|
||||
<headfilter lines="11"/>
|
||||
</filterchain>
|
||||
</concat>
|
||||
<concat destfile="${JQI_MIN}" append="yes">
|
||||
<filelist files="tmpmin"/>
|
||||
</concat>
|
||||
<delete file="tmpmin"/>
|
||||
<echo message="${JQI_MIN} built."/>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="tmpmin"/>
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1,78 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
|
||||
<title>jQuery i18n Plugin</title>
|
||||
<script type="text/javascript" src="jquery-1.4.2.js"></script>
|
||||
<script type="text/javascript" src="../jquery.i18n.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
i18n_dict = {
|
||||
"Example 1" : "teiän veen",
|
||||
"Example 2" : "tei'än ve'en",
|
||||
"Example 3" : "teiä vede",
|
||||
"Example 4" : "teirän veren",
|
||||
"Example 5" : "teilän velen",
|
||||
"Example 6" : "teijjän vejen",
|
||||
"Example 7" : "teidän veden",
|
||||
"Example 8" : "teitän veten",
|
||||
"Example 9" : "teiðän veðen",
|
||||
"Example 10" : "teidhän vethen",
|
||||
"Dynamic Content" : "Your browser window is %s x %s",
|
||||
"Ordered Dynamic Content": "%2$s is the height of your browser window, and %1$s is the width."
|
||||
};
|
||||
|
||||
$.i18n.setDictionary(i18n_dict);
|
||||
|
||||
$('input#translate_button').click( function(event) {
|
||||
$('div#example1').text($.i18n._('Example 1'));
|
||||
$('div#example2').text($.i18n._('Example 2'));
|
||||
$('div#example3').text($.i18n._('Example 3'));
|
||||
$('div#example4').text($.i18n._('Example 4'));
|
||||
$('div#example5').text($.i18n._('Example 5'));
|
||||
$('div#example6').text($.i18n._('Example 6'));
|
||||
$('div#example7').text($.i18n._('Example 7'));
|
||||
$('div#example8').text($.i18n._('Example 8'));
|
||||
$('div#example9').text($.i18n._('Example 9'));
|
||||
$('div#example10').text($.i18n._('Example 10'));
|
||||
$('div#dynamic').text($.i18n._('Dynamic Content', [$(document).width(), $(document).height()]));
|
||||
$('div#orderedDynamic').text($.i18n._('Ordered Dynamic Content', [$(document).width(), $(document).height()]));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
input {
|
||||
font-size: 30px;
|
||||
}
|
||||
p {
|
||||
font-size: 17px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
Click the button to translate the following text into some random Finnish from the
|
||||
<a href='http://en.wikipedia.org/wiki/Finnish_phonology'>Wikipedia Finnish Phonology Article</a>
|
||||
</p>
|
||||
|
||||
<div id='example1'>Example 1</div>
|
||||
<div id='example2'>Example 2</div>
|
||||
<div id='example3'>Example 3</div>
|
||||
<div id='example4'>Example 4</div>
|
||||
<div id='example5'>Example 5</div>
|
||||
<div id='example6'>Example 6</div>
|
||||
<div id='example7'>Example 7</div>
|
||||
<div id='example8'>Example 8</div>
|
||||
<div id='example9'>Example 9</div>
|
||||
<div id='example10'>Example 10</div>
|
||||
<div id='dynamic'>Dynamic Content</div>
|
||||
<div id='orderedDynamic'>Ordered Dynamic Content</div>
|
||||
|
||||
<input type='button' id='translate_button' value='Internationalize!' />
|
||||
</body>
|
||||
</html>
|
6240
library/jquery.i18n/examples/jquery-1.4.2.js
vendored
6240
library/jquery.i18n/examples/jquery-1.4.2.js
vendored
File diff suppressed because it is too large
Load Diff
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* jQuery i18n plugin
|
||||
* @requires jQuery v1.1 or later
|
||||
*
|
||||
* See http://recursive-design.com/projects/jquery-i18n/
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Version: 0.9.2 (201204070102)
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* i18n provides a mechanism for translating strings using a jscript dictionary.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* i18n property list
|
||||
*/
|
||||
$.i18n = {
|
||||
|
||||
dict: null,
|
||||
|
||||
/**
|
||||
* setDictionary()
|
||||
* Initialise the dictionary and translate nodes
|
||||
*
|
||||
* @param property_list i18n_dict : The dictionary to use for translation
|
||||
*/
|
||||
setDictionary: function(i18n_dict) {
|
||||
this.dict = i18n_dict;
|
||||
},
|
||||
|
||||
/**
|
||||
* _()
|
||||
* The actual translation function. Looks the given string up in the
|
||||
* dictionary and returns the translation if one exists. If a translation
|
||||
* is not found, returns the original word
|
||||
*
|
||||
* @param string str : The string to translate
|
||||
* @param property_list params : params for using printf() on the string
|
||||
* @return string : Translated word
|
||||
*
|
||||
*/
|
||||
_: function (str, params) {
|
||||
var transl = str;
|
||||
if (this.dict && this.dict[str]) {
|
||||
transl = this.dict[str];
|
||||
}
|
||||
return this.printf(transl, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* toEntity()
|
||||
* Change non-ASCII characters to entity representation
|
||||
*
|
||||
* @param string str : The string to transform
|
||||
* @return string result : Original string with non-ASCII content converted to entities
|
||||
*
|
||||
*/
|
||||
toEntity: function (str) {
|
||||
var result = '';
|
||||
for (var i=0;i<str.length; i++) {
|
||||
if (str.charCodeAt(i) > 128)
|
||||
result += "&#"+str.charCodeAt(i)+";";
|
||||
else
|
||||
result += str.charAt(i);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* stripStr()
|
||||
*
|
||||
* @param string str : The string to strip
|
||||
* @return string result : Stripped string
|
||||
*
|
||||
*/
|
||||
stripStr: function(str) {
|
||||
return str.replace(/^\s*/, "").replace(/\s*$/, "");
|
||||
},
|
||||
|
||||
/**
|
||||
* stripStrML()
|
||||
*
|
||||
* @param string str : The multi-line string to strip
|
||||
* @return string result : Stripped string
|
||||
*
|
||||
*/
|
||||
stripStrML: function(str) {
|
||||
// Split because m flag doesn't exist before JS1.5 and we need to
|
||||
// strip newlines anyway
|
||||
var parts = str.split('\n');
|
||||
for (var i=0; i<parts.length; i++)
|
||||
parts[i] = stripStr(parts[i]);
|
||||
|
||||
// Don't join with empty strings, because it "concats" words
|
||||
// And strip again
|
||||
return stripStr(parts.join(" "));
|
||||
},
|
||||
|
||||
/*
|
||||
* printf()
|
||||
* C-printf like function, which substitutes %s with parameters
|
||||
* given in list. %%s is used to escape %s.
|
||||
*
|
||||
* Doesn't work in IE5.0 (splice)
|
||||
*
|
||||
* @param string S : string to perform printf on.
|
||||
* @param string L : Array of arguments for printf()
|
||||
*/
|
||||
printf: function(S, L) {
|
||||
if (!L) return S;
|
||||
|
||||
var nS = "";
|
||||
var search = /%(\d+)\$s/g;
|
||||
// replace %n1$ where n is a number
|
||||
while (result = search.exec(S)) {
|
||||
var index = parseInt(result[1], 10) - 1;
|
||||
S = S.replace('%' + result[1] + '\$s', (L[index]));
|
||||
L.splice(index, 1);
|
||||
}
|
||||
var tS = S.split("%s");
|
||||
|
||||
if (tS.length > 1) {
|
||||
for(var i=0; i<L.length; i++) {
|
||||
if (tS[i].lastIndexOf('%') == tS[i].length-1 && i != L.length-1)
|
||||
tS[i] += "s"+tS.splice(i+1,1)[0];
|
||||
nS += tS[i] + L[i];
|
||||
}
|
||||
}
|
||||
return nS + tS[tS.length-1];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* _t
|
||||
* Allows you to translate a jQuery selector
|
||||
*
|
||||
* eg $('h1')._t('some text')
|
||||
*
|
||||
* @param string str : The string to translate
|
||||
* @param property_list params : params for using printf() on the string
|
||||
* @return element : chained and translated element(s)
|
||||
*/
|
||||
$.fn._t = function(str, params) {
|
||||
return $(this).text($.i18n._(str, params));
|
||||
};
|
||||
|
||||
|
||||
})(jQuery);
|
13
library/jquery.i18n/jquery.i18n.min.js
vendored
13
library/jquery.i18n/jquery.i18n.min.js
vendored
@ -1,13 +0,0 @@
|
||||
/*
|
||||
* jQuery i18n plugin
|
||||
* @requires jQuery v1.1 or later
|
||||
*
|
||||
* See http://recursive-design.com/projects/jquery-i18n/
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Version: 0.9.2 (201204070102)
|
||||
*/
|
||||
(function(f){f.i18n={dict:null,setDictionary:function(a){this.dict=a},_:function(a,b){var d=a;if(this.dict&&this.dict[a])d=this.dict[a];return this.printf(d,b)},toEntity:function(a){for(var b="",d=0;d<a.length;d++)b+=a.charCodeAt(d)>128?"&#"+a.charCodeAt(d)+";":a.charAt(d);return b},stripStr:function(a){return a.replace(/^\s*/,"").replace(/\s*$/,"")},stripStrML:function(a){a=a.split("\n");for(var b=0;b<a.length;b++)a[b]=stripStr(a[b]);return stripStr(a.join(" "))},printf:function(a,b){if(!b)return a;
|
||||
for(var d="",e=/%(\d+)\$s/g;result=e.exec(a);){var c=parseInt(result[1],10)-1;a=a.replace("%"+result[1]+"$s",b[c]);b.splice(c,1)}e=a.split("%s");if(e.length>1)for(c=0;c<b.length;c++){if(e[c].lastIndexOf("%")==e[c].length-1&&c!=b.length-1)e[c]+="s"+e.splice(c+1,1)[0];d+=e[c]+b[c]}return d+e[e.length-1]}};f.fn._t=function(a,b){return f(this).text(f.i18n._(a,b))}})(jQuery);
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* jQuery i18n plugin
|
||||
* @requires jQuery v1.1 or later
|
||||
*
|
||||
* See http://recursive-design.com/projects/jquery-i18n/
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Version: @VERSION (@DATE)
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* i18n provides a mechanism for translating strings using a jscript dictionary.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* i18n property list
|
||||
*/
|
||||
$.i18n = {
|
||||
|
||||
dict: null,
|
||||
|
||||
/**
|
||||
* setDictionary()
|
||||
* Initialise the dictionary and translate nodes
|
||||
*
|
||||
* @param property_list i18n_dict : The dictionary to use for translation
|
||||
*/
|
||||
setDictionary: function(i18n_dict) {
|
||||
this.dict = i18n_dict;
|
||||
},
|
||||
|
||||
/**
|
||||
* _()
|
||||
* The actual translation function. Looks the given string up in the
|
||||
* dictionary and returns the translation if one exists. If a translation
|
||||
* is not found, returns the original word
|
||||
*
|
||||
* @param string str : The string to translate
|
||||
* @param property_list params : params for using printf() on the string
|
||||
* @return string : Translated word
|
||||
*
|
||||
*/
|
||||
_: function (str, params) {
|
||||
var transl = str;
|
||||
if (this.dict && this.dict[str]) {
|
||||
transl = this.dict[str];
|
||||
}
|
||||
return this.printf(transl, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* toEntity()
|
||||
* Change non-ASCII characters to entity representation
|
||||
*
|
||||
* @param string str : The string to transform
|
||||
* @return string result : Original string with non-ASCII content converted to entities
|
||||
*
|
||||
*/
|
||||
toEntity: function (str) {
|
||||
var result = '';
|
||||
for (var i=0;i<str.length; i++) {
|
||||
if (str.charCodeAt(i) > 128)
|
||||
result += "&#"+str.charCodeAt(i)+";";
|
||||
else
|
||||
result += str.charAt(i);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* stripStr()
|
||||
*
|
||||
* @param string str : The string to strip
|
||||
* @return string result : Stripped string
|
||||
*
|
||||
*/
|
||||
stripStr: function(str) {
|
||||
return str.replace(/^\s*/, "").replace(/\s*$/, "");
|
||||
},
|
||||
|
||||
/**
|
||||
* stripStrML()
|
||||
*
|
||||
* @param string str : The multi-line string to strip
|
||||
* @return string result : Stripped string
|
||||
*
|
||||
*/
|
||||
stripStrML: function(str) {
|
||||
// Split because m flag doesn't exist before JS1.5 and we need to
|
||||
// strip newlines anyway
|
||||
var parts = str.split('\n');
|
||||
for (var i=0; i<parts.length; i++)
|
||||
parts[i] = stripStr(parts[i]);
|
||||
|
||||
// Don't join with empty strings, because it "concats" words
|
||||
// And strip again
|
||||
return stripStr(parts.join(" "));
|
||||
},
|
||||
|
||||
/*
|
||||
* printf()
|
||||
* C-printf like function, which substitutes %s with parameters
|
||||
* given in list. %%s is used to escape %s.
|
||||
*
|
||||
* Doesn't work in IE5.0 (splice)
|
||||
*
|
||||
* @param string S : string to perform printf on.
|
||||
* @param string L : Array of arguments for printf()
|
||||
*/
|
||||
printf: function(S, L) {
|
||||
if (!L) return S;
|
||||
|
||||
var nS = "";
|
||||
var search = /%(\d+)\$s/g;
|
||||
// replace %n1$ where n is a number
|
||||
while (result = search.exec(S)) {
|
||||
var index = parseInt(result[1], 10) - 1;
|
||||
S = S.replace('%' + result[1] + '\$s', (L[index]));
|
||||
L.splice(index, 1);
|
||||
}
|
||||
var tS = S.split("%s");
|
||||
|
||||
if (tS.length > 1) {
|
||||
for(var i=0; i<L.length; i++) {
|
||||
if (tS[i].lastIndexOf('%') == tS[i].length-1 && i != L.length-1)
|
||||
tS[i] += "s"+tS.splice(i+1,1)[0];
|
||||
nS += tS[i] + L[i];
|
||||
}
|
||||
}
|
||||
return nS + tS[tS.length-1];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* _t
|
||||
* Allows you to translate a jQuery selector
|
||||
*
|
||||
* eg $('h1')._t('some text')
|
||||
*
|
||||
* @param string str : The string to translate
|
||||
* @param property_list params : params for using printf() on the string
|
||||
* @return element : chained and translated element(s)
|
||||
*/
|
||||
$.fn._t = function(str, params) {
|
||||
return $(this).text($.i18n._(str, params));
|
||||
};
|
||||
|
||||
|
||||
})(jQuery);
|
@ -1,4 +0,0 @@
|
||||
This is jquery.autocomplete from
|
||||
|
||||
http://www.devbridge.com/projects/autocomplete/jquery/
|
||||
|
@ -1,400 +0,0 @@
|
||||
/**
|
||||
* Ajax Autocomplete for jQuery, version 1.1.3
|
||||
* (c) 2010 Tomas Kirda
|
||||
*
|
||||
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
|
||||
* For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/
|
||||
*
|
||||
* Last Review: 04/19/2010
|
||||
* Heavily modified for contact completion in Friendica (add photos, hover tips. etc.) 11-May-2012 mike@macgirvin.com
|
||||
*/
|
||||
|
||||
/*jslint onevar: true, evil: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
|
||||
/*global window: true, document: true, clearInterval: true, setInterval: true, jQuery: true */
|
||||
|
||||
(function($) {
|
||||
|
||||
var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');
|
||||
|
||||
function fnFormatResult(value, data, currentValue) {
|
||||
var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
|
||||
return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
|
||||
}
|
||||
|
||||
function Autocomplete(el, options) {
|
||||
this.el = $(el);
|
||||
this.el.attr('autocomplete', 'off');
|
||||
this.suggestions = [];
|
||||
this.data = [];
|
||||
this.badQueries = [];
|
||||
this.selectedIndex = -1;
|
||||
this.currentValue = this.el.val();
|
||||
this.intervalId = 0;
|
||||
this.cachedResponse = [];
|
||||
this.onChangeInterval = null;
|
||||
this.ignoreValueChange = false;
|
||||
this.serviceUrl = options.serviceUrl;
|
||||
this.isLocal = false;
|
||||
this.id = options.id;
|
||||
this.options = {
|
||||
autoSubmit: false,
|
||||
minChars: 1,
|
||||
maxHeight: 300,
|
||||
deferRequestBy: 0,
|
||||
width: 0,
|
||||
highlight: true,
|
||||
params: {},
|
||||
fnFormatResult: fnFormatResult,
|
||||
delimiter: null,
|
||||
zIndex: 999
|
||||
};
|
||||
this.initialize();
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
$.fn.autocomplete = function(options) {
|
||||
return new Autocomplete(this.get(0)||$('<input />'), options);
|
||||
};
|
||||
|
||||
|
||||
Autocomplete.prototype = {
|
||||
|
||||
killerFn: null,
|
||||
|
||||
initialize: function() {
|
||||
|
||||
var me, uid, autocompleteElId;
|
||||
me = this;
|
||||
uid = Math.floor(Math.random()*0x100000).toString(16);
|
||||
autocompleteElId = 'Autocomplete_' + uid;
|
||||
|
||||
this.killerFn = function(e) {
|
||||
if ($(e.target).parents('.autocomplete').size() === 0) {
|
||||
me.killSuggestions();
|
||||
me.disableKillerFn();
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.options.width) { this.options.width = this.el.width(); }
|
||||
this.mainContainerId = 'AutocompleteContainter_' + uid;
|
||||
|
||||
$('<div id="' + this.mainContainerId + '" style="position:absolute;z-index:999;"><div class="autocomplete-w1" id="'+this.id+'"><div class="autocomplete" id="' + autocompleteElId + '" style="display:none; width:300px;"></div></div></div>').appendTo('body');
|
||||
|
||||
this.container = $('#' + autocompleteElId);
|
||||
this.fixPosition();
|
||||
if (window.opera) {
|
||||
this.el.keypress(function(e) { me.onKeyPress(e); });
|
||||
} else {
|
||||
this.el.keydown(function(e) { me.onKeyPress(e); });
|
||||
}
|
||||
this.el.keyup(function(e) { me.onKeyUp(e); });
|
||||
this.el.blur(function() { me.enableKillerFn(); });
|
||||
this.el.focus(function() { me.fixPosition(); });
|
||||
},
|
||||
|
||||
setOptions: function(options){
|
||||
var o = this.options;
|
||||
$.extend(o, options);
|
||||
if(o.lookup){
|
||||
this.isLocal = true;
|
||||
if($.isArray(o.lookup)){ o.lookup = { suggestions:o.lookup, data:[] }; }
|
||||
}
|
||||
$('#'+this.mainContainerId).css({ zIndex:o.zIndex });
|
||||
this.container.css({ maxHeight: o.maxHeight + 'px', width:o.width });
|
||||
},
|
||||
|
||||
clearCache: function(){
|
||||
this.cachedResponse = [];
|
||||
this.badQueries = [];
|
||||
},
|
||||
|
||||
disable: function(){
|
||||
this.disabled = true;
|
||||
},
|
||||
|
||||
enable: function(){
|
||||
this.disabled = false;
|
||||
},
|
||||
|
||||
fixPosition: function() {
|
||||
var offset = this.el.offset();
|
||||
$('#' + this.mainContainerId).css({ top: (offset.top + this.el.innerHeight()) + 'px', left: offset.left + 'px' });
|
||||
},
|
||||
|
||||
enableKillerFn: function() {
|
||||
var me = this;
|
||||
$(document).bind('click', me.killerFn);
|
||||
},
|
||||
|
||||
disableKillerFn: function() {
|
||||
var me = this;
|
||||
$(document).unbind('click', me.killerFn);
|
||||
},
|
||||
|
||||
killSuggestions: function() {
|
||||
var me = this;
|
||||
this.stopKillSuggestions();
|
||||
this.intervalId = window.setInterval(function() { me.hide(); me.stopKillSuggestions(); }, 300);
|
||||
},
|
||||
|
||||
stopKillSuggestions: function() {
|
||||
window.clearInterval(this.intervalId);
|
||||
},
|
||||
|
||||
onKeyPress: function(e) {
|
||||
if (this.disabled || !this.enabled) { return; }
|
||||
// return will exit the function
|
||||
// and event will not be prevented
|
||||
switch (e.keyCode) {
|
||||
case 27: //KEY_ESC:
|
||||
this.el.val(this.currentValue);
|
||||
this.hide();
|
||||
break;
|
||||
case 9: //KEY_TAB:
|
||||
case 13: //KEY_RETURN:
|
||||
if (this.selectedIndex === -1) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
this.select(this.selectedIndex);
|
||||
if(e.keyCode === 9){ return; }
|
||||
break;
|
||||
case 38: //KEY_UP:
|
||||
this.moveUp();
|
||||
break;
|
||||
case 40: //KEY_DOWN:
|
||||
this.moveDown();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
// if(e.keyCode != 13) {
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
//}
|
||||
},
|
||||
|
||||
onKeyUp: function(e) {
|
||||
if(this.disabled){ return; }
|
||||
switch (e.keyCode) {
|
||||
case 38: //KEY_UP:
|
||||
case 40: //KEY_DOWN:
|
||||
return;
|
||||
}
|
||||
clearInterval(this.onChangeInterval);
|
||||
if (this.currentValue !== this.el.val()) {
|
||||
if (this.options.deferRequestBy > 0) {
|
||||
// Defer lookup in case when value changes very quickly:
|
||||
var me = this;
|
||||
this.onChangeInterval = setInterval(function() { me.onValueChange(); }, this.options.deferRequestBy);
|
||||
} else {
|
||||
this.onValueChange();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onValueChange: function() {
|
||||
clearInterval(this.onChangeInterval);
|
||||
this.currentValue = this.el.val();
|
||||
var q = this.getQuery(this.currentValue);
|
||||
this.selectedIndex = -1;
|
||||
if (this.ignoreValueChange) {
|
||||
this.ignoreValueChange = false;
|
||||
return;
|
||||
}
|
||||
if (q === '' || q.length < this.options.minChars) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.getSuggestions(q);
|
||||
}
|
||||
},
|
||||
|
||||
getQuery: function(val) {
|
||||
var d, arr;
|
||||
d = this.options.delimiter;
|
||||
if (!d) { return $.trim(val); }
|
||||
arr = val.split(d);
|
||||
return $.trim(arr[arr.length - 1]);
|
||||
},
|
||||
|
||||
getSuggestionsLocal: function(q) {
|
||||
var ret, arr, len, val, i;
|
||||
arr = this.options.lookup;
|
||||
len = arr.suggestions.length;
|
||||
ret = { suggestions:[], data:[] };
|
||||
q = q.toLowerCase();
|
||||
for(i=0; i< len; i++){
|
||||
val = arr.suggestions[i];
|
||||
if(val.toLowerCase().indexOf(q) === 0){
|
||||
ret.suggestions.push(val);
|
||||
ret.data.push(arr.data[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
getSuggestions: function(q) {
|
||||
var cr, me;
|
||||
cr = this.isLocal ? this.getSuggestionsLocal(q) : this.cachedResponse[q];
|
||||
if (cr && $.isArray(cr.suggestions)) {
|
||||
this.suggestions = cr.suggestions;
|
||||
this.data = cr.data;
|
||||
this.suggest();
|
||||
} else if (!this.isBadQuery(q)) {
|
||||
me = this;
|
||||
me.options.params.query = q;
|
||||
$('#nav-search-spinner').show();
|
||||
$.get(this.serviceUrl, me.options.params, function(txt) { me.processResponse(txt); }, 'text');
|
||||
}
|
||||
},
|
||||
|
||||
isBadQuery: function(q) {
|
||||
var i = this.badQueries.length;
|
||||
while (i--) {
|
||||
if (q.indexOf(this.badQueries[i]) === 0) { return true; }
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.enabled = false;
|
||||
this.selectedIndex = -1;
|
||||
this.container.hide();
|
||||
},
|
||||
|
||||
suggest: function() {
|
||||
if (this.suggestions.length === 0) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var me, len, div, f, v, i, s, mOver, mClick, l, img;
|
||||
me = this;
|
||||
len = this.suggestions.length;
|
||||
f = this.options.fnFormatResult;
|
||||
v = this.getQuery(this.currentValue);
|
||||
mOver = function(xi) { return function() { me.activate(xi); }; };
|
||||
mClick = function(xi) { return function() { me.select(xi); }; };
|
||||
this.container.hide().empty();
|
||||
for (i = 0; i < len; i++) {
|
||||
s = this.suggestions[i];
|
||||
l = this.links[i];
|
||||
img = '<img height="24" width="24" src="' + this.photos[i] + '" alt="' + s + '" /> ';
|
||||
div = $((me.selectedIndex === i ? '<div class="selected"' : '<div') + ' title="' + l + '">' + img + f(s, this.data[i], v) + '</div>');
|
||||
div.mouseover(mOver(i));
|
||||
div.click(mClick(i));
|
||||
this.container.append(div);
|
||||
}
|
||||
this.enabled = true;
|
||||
this.container.show();
|
||||
},
|
||||
|
||||
processResponse: function(text) {
|
||||
var response;
|
||||
try {
|
||||
response = eval('(' + text + ')');
|
||||
} catch (err) { return; }
|
||||
if (!$.isArray(response.data)) { response.data = []; }
|
||||
if(!this.options.noCache){
|
||||
this.cachedResponse[response.query] = response;
|
||||
if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
|
||||
}
|
||||
if (response.query === this.getQuery(this.currentValue)) {
|
||||
this.photos = response.photos;
|
||||
this.links = response.links;
|
||||
this.suggestions = response.suggestions;
|
||||
this.data = response.data;
|
||||
this.suggest();
|
||||
}
|
||||
$('#nav-search-spinner').hide();
|
||||
},
|
||||
|
||||
activate: function(index) {
|
||||
var divs, activeItem;
|
||||
divs = this.container.children();
|
||||
// Clear previous selection:
|
||||
if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
|
||||
$(divs.get(this.selectedIndex)).removeClass();
|
||||
}
|
||||
this.selectedIndex = index;
|
||||
if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
|
||||
activeItem = divs.get(this.selectedIndex);
|
||||
$(activeItem).addClass('selected');
|
||||
}
|
||||
return activeItem;
|
||||
},
|
||||
|
||||
deactivate: function(div, index) {
|
||||
div.className = '';
|
||||
if (this.selectedIndex === index) { this.selectedIndex = -1; }
|
||||
},
|
||||
|
||||
select: function(i) {
|
||||
var selectedValue, f;
|
||||
selectedValue = this.suggestions[i];
|
||||
if (selectedValue) {
|
||||
this.el.val(selectedValue);
|
||||
if (this.options.autoSubmit) {
|
||||
f = this.el.parents('form');
|
||||
if (f.length > 0) { f.get(0).submit(); }
|
||||
}
|
||||
this.ignoreValueChange = true;
|
||||
this.hide();
|
||||
this.onSelect(i);
|
||||
}
|
||||
},
|
||||
|
||||
moveUp: function() {
|
||||
if (this.selectedIndex === -1) { return; }
|
||||
if (this.selectedIndex === 0) {
|
||||
this.container.children().get(0).className = '';
|
||||
this.selectedIndex = -1;
|
||||
this.el.val(this.currentValue);
|
||||
return;
|
||||
}
|
||||
this.adjustScroll(this.selectedIndex - 1);
|
||||
},
|
||||
|
||||
moveDown: function() {
|
||||
if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
|
||||
this.adjustScroll(this.selectedIndex + 1);
|
||||
},
|
||||
|
||||
adjustScroll: function(i) {
|
||||
var activeItem, offsetTop, upperBound, lowerBound;
|
||||
activeItem = this.activate(i);
|
||||
offsetTop = activeItem.offsetTop;
|
||||
upperBound = this.container.scrollTop();
|
||||
lowerBound = upperBound + this.options.maxHeight - 25;
|
||||
if (offsetTop < upperBound) {
|
||||
this.container.scrollTop(offsetTop);
|
||||
} else if (offsetTop > lowerBound) {
|
||||
this.container.scrollTop(offsetTop - this.options.maxHeight + 25);
|
||||
}
|
||||
this.el.val(this.getValue(this.suggestions[i]));
|
||||
},
|
||||
|
||||
onSelect: function(i) {
|
||||
var me, fn, s, d;
|
||||
me = this;
|
||||
fn = me.options.onSelect;
|
||||
s = me.suggestions[i];
|
||||
d = me.data[i];
|
||||
me.el.val(me.getValue(s));
|
||||
if ($.isFunction(fn)) { fn(s, d, me.el); }
|
||||
},
|
||||
|
||||
getValue: function(value){
|
||||
var del, currVal, arr, me;
|
||||
me = this;
|
||||
del = me.options.delimiter;
|
||||
if (!del) { return value; }
|
||||
currVal = me.currentValue;
|
||||
arr = currVal.split(del);
|
||||
if (arr.length === 1) { return value; }
|
||||
return currVal.substr(0, currVal.length - arr[arr.length - 1].length) + value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}(jQuery));
|
19
library/jquery_ac/jquery-1.3.2.min.js
vendored
19
library/jquery_ac/jquery-1.3.2.min.js
vendored
File diff suppressed because one or more lines are too long
11
library/jquery_ac/jquery.autocomplete-min.js
vendored
11
library/jquery_ac/jquery.autocomplete-min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,390 +0,0 @@
|
||||
/**
|
||||
* Ajax Autocomplete for jQuery, version 1.1.3
|
||||
* (c) 2010 Tomas Kirda
|
||||
*
|
||||
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
|
||||
* For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/
|
||||
*
|
||||
* Last Review: 04/19/2010
|
||||
*/
|
||||
|
||||
/*jslint onevar: true, evil: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
|
||||
/*global window: true, document: true, clearInterval: true, setInterval: true, jQuery: true */
|
||||
|
||||
(function($) {
|
||||
|
||||
var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');
|
||||
|
||||
function fnFormatResult(value, data, currentValue) {
|
||||
var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
|
||||
return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
|
||||
}
|
||||
|
||||
function Autocomplete(el, options) {
|
||||
this.el = $(el);
|
||||
this.el.attr('autocomplete', 'off');
|
||||
this.suggestions = [];
|
||||
this.data = [];
|
||||
this.badQueries = [];
|
||||
this.selectedIndex = -1;
|
||||
this.currentValue = this.el.val();
|
||||
this.intervalId = 0;
|
||||
this.cachedResponse = [];
|
||||
this.onChangeInterval = null;
|
||||
this.ignoreValueChange = false;
|
||||
this.serviceUrl = options.serviceUrl;
|
||||
this.isLocal = false;
|
||||
this.options = {
|
||||
autoSubmit: false,
|
||||
minChars: 1,
|
||||
maxHeight: 300,
|
||||
deferRequestBy: 0,
|
||||
width: 0,
|
||||
highlight: true,
|
||||
params: {},
|
||||
fnFormatResult: fnFormatResult,
|
||||
delimiter: null,
|
||||
zIndex: 9999
|
||||
};
|
||||
this.initialize();
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
$.fn.autocomplete = function(options) {
|
||||
return new Autocomplete(this.get(0)||$('<input />'), options);
|
||||
};
|
||||
|
||||
|
||||
Autocomplete.prototype = {
|
||||
|
||||
killerFn: null,
|
||||
|
||||
initialize: function() {
|
||||
|
||||
var me, uid, autocompleteElId;
|
||||
me = this;
|
||||
uid = Math.floor(Math.random()*0x100000).toString(16);
|
||||
autocompleteElId = 'Autocomplete_' + uid;
|
||||
|
||||
this.killerFn = function(e) {
|
||||
if ($(e.target).parents('.autocomplete').size() === 0) {
|
||||
me.killSuggestions();
|
||||
me.disableKillerFn();
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.options.width) { this.options.width = this.el.width(); }
|
||||
this.mainContainerId = 'AutocompleteContainter_' + uid;
|
||||
|
||||
$('<div id="' + this.mainContainerId + '" style="position:absolute;z-index:9999;"><div class="autocomplete-w1"><div class="autocomplete" id="' + autocompleteElId + '" style="display:none; width:300px;"></div></div></div>').appendTo('body');
|
||||
|
||||
this.container = $('#' + autocompleteElId);
|
||||
this.fixPosition();
|
||||
if (window.opera) {
|
||||
this.el.keypress(function(e) { me.onKeyPress(e); });
|
||||
} else {
|
||||
this.el.keydown(function(e) { me.onKeyPress(e); });
|
||||
}
|
||||
this.el.keyup(function(e) { me.onKeyUp(e); });
|
||||
this.el.blur(function() { me.enableKillerFn(); });
|
||||
this.el.focus(function() { me.fixPosition(); });
|
||||
},
|
||||
|
||||
setOptions: function(options){
|
||||
var o = this.options;
|
||||
$.extend(o, options);
|
||||
if(o.lookup){
|
||||
this.isLocal = true;
|
||||
if($.isArray(o.lookup)){ o.lookup = { suggestions:o.lookup, data:[] }; }
|
||||
}
|
||||
$('#'+this.mainContainerId).css({ zIndex:o.zIndex });
|
||||
this.container.css({ maxHeight: o.maxHeight + 'px', width:o.width });
|
||||
},
|
||||
|
||||
clearCache: function(){
|
||||
this.cachedResponse = [];
|
||||
this.badQueries = [];
|
||||
},
|
||||
|
||||
disable: function(){
|
||||
this.disabled = true;
|
||||
},
|
||||
|
||||
enable: function(){
|
||||
this.disabled = false;
|
||||
},
|
||||
|
||||
fixPosition: function() {
|
||||
var offset = this.el.offset();
|
||||
$('#' + this.mainContainerId).css({ top: (offset.top + this.el.innerHeight()) + 'px', left: offset.left + 'px' });
|
||||
},
|
||||
|
||||
enableKillerFn: function() {
|
||||
var me = this;
|
||||
$(document).bind('click', me.killerFn);
|
||||
},
|
||||
|
||||
disableKillerFn: function() {
|
||||
var me = this;
|
||||
$(document).unbind('click', me.killerFn);
|
||||
},
|
||||
|
||||
killSuggestions: function() {
|
||||
var me = this;
|
||||
this.stopKillSuggestions();
|
||||
this.intervalId = window.setInterval(function() { me.hide(); me.stopKillSuggestions(); }, 300);
|
||||
},
|
||||
|
||||
stopKillSuggestions: function() {
|
||||
window.clearInterval(this.intervalId);
|
||||
},
|
||||
|
||||
onKeyPress: function(e) {
|
||||
if (this.disabled || !this.enabled) { return; }
|
||||
// return will exit the function
|
||||
// and event will not be prevented
|
||||
switch (e.keyCode) {
|
||||
case 27: //KEY_ESC:
|
||||
this.el.val(this.currentValue);
|
||||
this.hide();
|
||||
break;
|
||||
case 9: //KEY_TAB:
|
||||
case 13: //KEY_RETURN:
|
||||
if (this.selectedIndex === -1) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
this.select(this.selectedIndex);
|
||||
if(e.keyCode === 9){ return; }
|
||||
break;
|
||||
case 38: //KEY_UP:
|
||||
this.moveUp();
|
||||
break;
|
||||
case 40: //KEY_DOWN:
|
||||
this.moveDown();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
onKeyUp: function(e) {
|
||||
if(this.disabled){ return; }
|
||||
switch (e.keyCode) {
|
||||
case 38: //KEY_UP:
|
||||
case 40: //KEY_DOWN:
|
||||
return;
|
||||
}
|
||||
clearInterval(this.onChangeInterval);
|
||||
if (this.currentValue !== this.el.val()) {
|
||||
if (this.options.deferRequestBy > 0) {
|
||||
// Defer lookup in case when value changes very quickly:
|
||||
var me = this;
|
||||
this.onChangeInterval = setInterval(function() { me.onValueChange(); }, this.options.deferRequestBy);
|
||||
} else {
|
||||
this.onValueChange();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onValueChange: function() {
|
||||
clearInterval(this.onChangeInterval);
|
||||
this.currentValue = this.el.val();
|
||||
var q = this.getQuery(this.currentValue);
|
||||
this.selectedIndex = -1;
|
||||
if (this.ignoreValueChange) {
|
||||
this.ignoreValueChange = false;
|
||||
return;
|
||||
}
|
||||
if (q === '' || q.length < this.options.minChars) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.getSuggestions(q);
|
||||
}
|
||||
},
|
||||
|
||||
getQuery: function(val) {
|
||||
var d, arr;
|
||||
d = this.options.delimiter;
|
||||
if (!d) { return $.trim(val); }
|
||||
arr = val.split(d);
|
||||
return $.trim(arr[arr.length - 1]);
|
||||
},
|
||||
|
||||
getSuggestionsLocal: function(q) {
|
||||
var ret, arr, len, val, i;
|
||||
arr = this.options.lookup;
|
||||
len = arr.suggestions.length;
|
||||
ret = { suggestions:[], data:[] };
|
||||
q = q.toLowerCase();
|
||||
for(i=0; i< len; i++){
|
||||
val = arr.suggestions[i];
|
||||
if(val.toLowerCase().indexOf(q) === 0){
|
||||
ret.suggestions.push(val);
|
||||
ret.data.push(arr.data[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
getSuggestions: function(q) {
|
||||
var cr, me;
|
||||
cr = this.isLocal ? this.getSuggestionsLocal(q) : this.cachedResponse[q];
|
||||
if (cr && $.isArray(cr.suggestions)) {
|
||||
this.suggestions = cr.suggestions;
|
||||
this.data = cr.data;
|
||||
this.suggest();
|
||||
} else if (!this.isBadQuery(q)) {
|
||||
me = this;
|
||||
me.options.params.query = q;
|
||||
$.get(this.serviceUrl, me.options.params, function(txt) { me.processResponse(txt); }, 'text');
|
||||
}
|
||||
},
|
||||
|
||||
isBadQuery: function(q) {
|
||||
var i = this.badQueries.length;
|
||||
while (i--) {
|
||||
if (q.indexOf(this.badQueries[i]) === 0) { return true; }
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.enabled = false;
|
||||
this.selectedIndex = -1;
|
||||
this.container.hide();
|
||||
},
|
||||
|
||||
suggest: function() {
|
||||
if (this.suggestions.length === 0) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var me, len, div, f, v, i, s, mOver, mClick;
|
||||
me = this;
|
||||
len = this.suggestions.length;
|
||||
f = this.options.fnFormatResult;
|
||||
v = this.getQuery(this.currentValue);
|
||||
mOver = function(xi) { return function() { me.activate(xi); }; };
|
||||
mClick = function(xi) { return function() { me.select(xi); }; };
|
||||
this.container.hide().empty();
|
||||
for (i = 0; i < len; i++) {
|
||||
s = this.suggestions[i];
|
||||
div = $((me.selectedIndex === i ? '<div class="selected"' : '<div') + ' title="' + s + '">' + f(s, this.data[i], v) + '</div>');
|
||||
div.mouseover(mOver(i));
|
||||
div.click(mClick(i));
|
||||
this.container.append(div);
|
||||
}
|
||||
this.enabled = true;
|
||||
this.container.show();
|
||||
},
|
||||
|
||||
processResponse: function(text) {
|
||||
var response;
|
||||
try {
|
||||
response = eval('(' + text + ')');
|
||||
} catch (err) { return; }
|
||||
if (!$.isArray(response.data)) { response.data = []; }
|
||||
if(!this.options.noCache){
|
||||
this.cachedResponse[response.query] = response;
|
||||
if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
|
||||
}
|
||||
if (response.query === this.getQuery(this.currentValue)) {
|
||||
this.suggestions = response.suggestions;
|
||||
this.data = response.data;
|
||||
this.suggest();
|
||||
}
|
||||
},
|
||||
|
||||
activate: function(index) {
|
||||
var divs, activeItem;
|
||||
divs = this.container.children();
|
||||
// Clear previous selection:
|
||||
if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
|
||||
$(divs.get(this.selectedIndex)).removeClass();
|
||||
}
|
||||
this.selectedIndex = index;
|
||||
if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
|
||||
activeItem = divs.get(this.selectedIndex);
|
||||
$(activeItem).addClass('selected');
|
||||
}
|
||||
return activeItem;
|
||||
},
|
||||
|
||||
deactivate: function(div, index) {
|
||||
div.className = '';
|
||||
if (this.selectedIndex === index) { this.selectedIndex = -1; }
|
||||
},
|
||||
|
||||
select: function(i) {
|
||||
var selectedValue, f;
|
||||
selectedValue = this.suggestions[i];
|
||||
if (selectedValue) {
|
||||
this.el.val(selectedValue);
|
||||
if (this.options.autoSubmit) {
|
||||
f = this.el.parents('form');
|
||||
if (f.length > 0) { f.get(0).submit(); }
|
||||
}
|
||||
this.ignoreValueChange = true;
|
||||
this.hide();
|
||||
this.onSelect(i);
|
||||
}
|
||||
},
|
||||
|
||||
moveUp: function() {
|
||||
if (this.selectedIndex === -1) { return; }
|
||||
if (this.selectedIndex === 0) {
|
||||
this.container.children().get(0).className = '';
|
||||
this.selectedIndex = -1;
|
||||
this.el.val(this.currentValue);
|
||||
return;
|
||||
}
|
||||
this.adjustScroll(this.selectedIndex - 1);
|
||||
},
|
||||
|
||||
moveDown: function() {
|
||||
if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
|
||||
this.adjustScroll(this.selectedIndex + 1);
|
||||
},
|
||||
|
||||
adjustScroll: function(i) {
|
||||
var activeItem, offsetTop, upperBound, lowerBound;
|
||||
activeItem = this.activate(i);
|
||||
offsetTop = activeItem.offsetTop;
|
||||
upperBound = this.container.scrollTop();
|
||||
lowerBound = upperBound + this.options.maxHeight - 25;
|
||||
if (offsetTop < upperBound) {
|
||||
this.container.scrollTop(offsetTop);
|
||||
} else if (offsetTop > lowerBound) {
|
||||
this.container.scrollTop(offsetTop - this.options.maxHeight + 25);
|
||||
}
|
||||
this.el.val(this.getValue(this.suggestions[i]));
|
||||
},
|
||||
|
||||
onSelect: function(i) {
|
||||
var me, fn, s, d;
|
||||
me = this;
|
||||
fn = me.options.onSelect;
|
||||
s = me.suggestions[i];
|
||||
d = me.data[i];
|
||||
me.el.val(me.getValue(s));
|
||||
if ($.isFunction(fn)) { fn(s, d, me.el); }
|
||||
},
|
||||
|
||||
getValue: function(value){
|
||||
var del, currVal, arr, me;
|
||||
me = this;
|
||||
del = me.options.delimiter;
|
||||
if (!del) { return value; }
|
||||
currVal = me.currentValue;
|
||||
arr = currVal.split(del);
|
||||
if (arr.length === 1) { return value; }
|
||||
return currVal.substr(0, currVal.length - arr[arr.length - 1].length) + value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}(jQuery));
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
@ -1,6 +0,0 @@
|
||||
|
||||
.autocomplete-w1 { background:url(img/shadow.png) no-repeat bottom right; position:absolute; top:0px; left:0px; margin:8px 0 0 6px; /* IE6 fix: */ _background:none; _margin:0; }
|
||||
.autocomplete { border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px; _margin:0; _overflow-x:hidden; }
|
||||
.autocomplete .selected { background:#F0F0F0; }
|
||||
.autocomplete div { padding:2px 5px; white-space:nowrap; }
|
||||
.autocomplete strong { font-weight:normal; color:#3399FF; }
|
@ -1,535 +0,0 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
### 2.13.0 [See full changelog](https://gist.github.com/ichernev/0132fcf5b61f7fc140b0bb0090480d49)
|
||||
|
||||
## Enhancements:
|
||||
* [#2982](https://github.com/moment/moment/pull/2982) Add 'date' as alias to 'day' for startOf() and endOf().
|
||||
* [#2955](https://github.com/moment/moment/pull/2955) Add parsing negative components in durations when ISO 8601
|
||||
* [#2991](https://github.com/moment/moment/pull/2991) isBetween support for both open and closed intervals
|
||||
* [#3105](https://github.com/moment/moment/pull/3105) Add localeSorted argument to weekday listers
|
||||
* [#3102](https://github.com/moment/moment/pull/3102) Add k and kk formatting tokens
|
||||
|
||||
## Bugfixes
|
||||
* [#3109](https://github.com/moment/moment/pull/3109) Fix [#1756](https://github.com/moment/moment/issues/1756) Resolved thread-safe issue on server side.
|
||||
* [#3078](https://github.com/moment/moment/pull/3078) Fix parsing for months/weekdays with weird characters
|
||||
* [#3098](https://github.com/moment/moment/pull/3098) Use Z suffix when in UTC mode ([#3020](https://github.com/moment/moment/issues/3020))
|
||||
* [#2995](https://github.com/moment/moment/pull/2995) Fix floating point rounding errors in durations
|
||||
* [#3059](https://github.com/moment/moment/pull/3059) fix bug where diff returns -0 in month-related diffs
|
||||
* [#3045](https://github.com/moment/moment/pull/3045) Fix mistaking any input for 'a' token
|
||||
* [#2877](https://github.com/moment/moment/pull/2877) Use explicit .valueOf() calls instead of coercion
|
||||
* [#3036](https://github.com/moment/moment/pull/3036) Year setter should keep time when DST changes
|
||||
|
||||
Plus 3 new locales and locale fixes.
|
||||
|
||||
### 2.12.0 [See full changelog](https://gist.github.com/ichernev/6e5bfdf8d6522fc4ac73)
|
||||
|
||||
## Enhancements:
|
||||
* [#2932](https://github.com/moment/moment/pull/2932) List loaded locales
|
||||
* [#2818](https://github.com/moment/moment/pull/2818) Parse ISO-8061 duration containing both day and week values
|
||||
* [#2774](https://github.com/moment/moment/pull/2774) Implement locale inheritance and locale updating
|
||||
|
||||
## Bugfixes:
|
||||
* [#2970](https://github.com/moment/moment/pull/2970) change add subtract to handle decimal values by rounding
|
||||
* [#2887](https://github.com/moment/moment/pull/2887) Fix toJSON casting of invalid moment
|
||||
* [#2897](https://github.com/moment/moment/pull/2897) parse string arguments for month() correctly, closes #2884
|
||||
* [#2946](https://github.com/moment/moment/pull/2946) Fix usage suggestions for min and max
|
||||
|
||||
## New locales:
|
||||
* [#2917](https://github.com/moment/moment/pull/2917) Locale Punjabi(Gurmukhi) India format conversion
|
||||
|
||||
And more
|
||||
|
||||
### 2.11.2 (Fix ReDoS attack vector)
|
||||
|
||||
* [#2939](https://github.com/moment/moment/pull/2939) use full-string match to speed up aspnet regex match
|
||||
|
||||
### 2.11.1 [See full changelog](https://gist.github.com/ichernev/8ec3ee25b749b4cff3c2)
|
||||
|
||||
## Bugfixes:
|
||||
* [#2881](https://github.com/moment/moment/pull/2881) Revert "Merge pull request #2746 from mbad0la:develop" Sep->Sept
|
||||
* [#2868](https://github.com/moment/moment/pull/2868) Add format and parse token Y, so it actually works
|
||||
* [#2865](https://github.com/moment/moment/pull/2865) Use typeof checks for undefined for global variables
|
||||
* [#2858](https://github.com/moment/moment/pull/2858) Fix Date mocking regression introduced in 2.11.0
|
||||
* [#2864](https://github.com/moment/moment/pull/2864) Include changelog in npm release
|
||||
* [#2830](https://github.com/moment/moment/pull/2830) dep: add grunt-cli
|
||||
* [#2869](https://github.com/moment/moment/pull/2869) Fix months parsing for some locales
|
||||
|
||||
### 2.11.0 [See full changelog](https://gist.github.com/ichernev/6594bc29719dde6b2f66)
|
||||
|
||||
* [#2624](https://github.com/moment/moment/pull/2624) Proper handling of invalid moments
|
||||
* [#2634](https://github.com/moment/moment/pull/2634) Fix strict month parsing issue in cs,ru,sk
|
||||
* [#2735](https://github.com/moment/moment/pull/2735) Reset the locale back to 'en' after defining all locales in min/locales.js
|
||||
* [#2702](https://github.com/moment/moment/pull/2702) Week rework
|
||||
* [#2746](https://github.com/moment/moment/pull/2746) Changed September Abbreviation to "Sept" in locale-specific english
|
||||
files and default locale file
|
||||
* [#2646](https://github.com/moment/moment/pull/2646) Fix [#2645](https://github.com/moment/moment/pull/2645) - invalid dates pre-1970
|
||||
|
||||
* [#2641](https://github.com/moment/moment/pull/2641) Implement basic format and comma as ms separator in ISO 8601
|
||||
* [#2665](https://github.com/moment/moment/pull/2665) Implement stricter weekday parsing
|
||||
* [#2700](https://github.com/moment/moment/pull/2700) Add [Hh]mm and [Hh]mmss formatting tokens, so you can parse 123 with
|
||||
hmm for example
|
||||
* [#2565](https://github.com/moment/moment/pull/2565) [#2835](https://github.com/moment/moment/pull/2835) Expose arguments used for moment creation with creationData
|
||||
(fix [#2443](https://github.com/moment/moment/pull/2443))
|
||||
* [#2648](https://github.com/moment/moment/pull/2648) fix issue [#2640](https://github.com/moment/moment/pull/2640): support instanceof operator
|
||||
* [#2709](https://github.com/moment/moment/pull/2709) Add isSameOrAfter and isSameOrBefore comparison methods
|
||||
* [#2721](https://github.com/moment/moment/pull/2721) Fix moment creation from object with strings values
|
||||
* [#2740](https://github.com/moment/moment/pull/2740) Enable 'd hh:mm:ss.sss' format for durations
|
||||
* [#2766](https://github.com/moment/moment/pull/2766) [#2833](https://github.com/moment/moment/pull/2833) Alternate Clock Source Support
|
||||
|
||||
### 2.10.6
|
||||
|
||||
[#2515](https://github.com/moment/moment/pull/2515) Fix regression introduced
|
||||
in `2.10.5` related to `moment.ISO_8601` parsing.
|
||||
|
||||
### 2.10.5 [See full changelog](https://gist.github.com/ichernev/6ec13ac7efc396da44b2)
|
||||
|
||||
Important changes:
|
||||
* [#2357](https://github.com/moment/moment/pull/2357) Improve unit bubbling for ISO dates
|
||||
this fixes day to year conversions to work around end-of-year (~365 days). As
|
||||
a side effect 365 days is 11 months and 30 days, and 366 days is one year.
|
||||
* [#2438](https://github.com/moment/moment/pull/2438) Fix inconsistent moment.min and moment.max results
|
||||
Return invalid result if any of the inputs is invalid
|
||||
* [#2494](https://github.com/moment/moment/pull/2494) Fix two digit year parsing with YYYY format
|
||||
This brings the benefits of YY to YYYY
|
||||
* [#2368](https://github.com/moment/moment/pull/2368) perf: use faster form of copying dates, across the board improvement
|
||||
|
||||
|
||||
### 2.10.3 [See full changelog](https://gist.github.com/ichernev/f264b9bed5b00f8b1b7f)
|
||||
|
||||
* add `moment.fn.to` and `moment.fn.toNow` (similar to `from` and `fromNow`)
|
||||
* new locales (Sinhalese (si), Montenegrin (me), Javanese (ja))
|
||||
* performance improvements
|
||||
|
||||
### 2.10.2
|
||||
|
||||
* fixed moment-with-locales in browser env caused by esperanto change
|
||||
|
||||
### 2.10.1
|
||||
|
||||
* regression: Add moment.duration.fn back
|
||||
|
||||
### 2.10.0
|
||||
|
||||
Ported code to es6 modules.
|
||||
|
||||
### 2.9.0 [See full changelog](https://gist.github.com/ichernev/0c9a9b49951111a27ce7)
|
||||
|
||||
languages:
|
||||
* [2104](https://github.com/moment/moment/issues/2104) Frisian (fy) language file with unit test
|
||||
* [2097](https://github.com/moment/moment/issues/2097) add ar-tn locale
|
||||
|
||||
deprecations:
|
||||
* [2074](https://github.com/moment/moment/issues/2074) Implement `moment.fn.utcOffset`, deprecate `moment.fn.zone`
|
||||
|
||||
features:
|
||||
* [2088](https://github.com/moment/moment/issues/2088) add moment.fn.isBetween
|
||||
* [2054](https://github.com/moment/moment/issues/2054) Call updateOffset when creating moment (needed for default timezone in
|
||||
moment-timezone)
|
||||
* [1893](https://github.com/moment/moment/issues/1893) Add moment.isDate method
|
||||
* [1825](https://github.com/moment/moment/issues/1825) Implement toJSON function on Duration
|
||||
* [1809](https://github.com/moment/moment/issues/1809) Allowing moment.set() to accept a hash of units
|
||||
* [2128](https://github.com/moment/moment/issues/2128) Add firstDayOfWeek, firstDayOfYear locale getters
|
||||
* [2131](https://github.com/moment/moment/issues/2131) Add quarter diff support
|
||||
|
||||
Some bugfixes and language improvements -- [full changelog](https://gist.github.com/ichernev/0c9a9b49951111a27ce7)
|
||||
|
||||
### 2.8.4 [See full changelog](https://gist.github.com/ichernev/a4fcb0a46d74e4b9b996)
|
||||
|
||||
Features:
|
||||
|
||||
* [#2000](https://github.com/moment/moment/issues/2000) Add LTS localised format that includes seconds
|
||||
* [#1960](https://github.com/moment/moment/issues/1960) added formatToken 'x' for unix offset in milliseconds #1938
|
||||
* [#1965](https://github.com/moment/moment/issues/1965) Support 24:00:00.000 to mean next day, at midnight.
|
||||
* [#2002](https://github.com/moment/moment/issues/2002) Accept 'date' key when creating moment with object
|
||||
* [#2009](https://github.com/moment/moment/issues/2009) Use native toISOString when we can
|
||||
|
||||
Some bugfixes and language improvements -- [full changelog](https://gist.github.com/ichernev/a4fcb0a46d74e4b9b996)
|
||||
|
||||
### 2.8.3
|
||||
|
||||
Bugfixes:
|
||||
|
||||
* [#1801](https://github.com/moment/moment/issues/1801) proper pluralization for Arabic
|
||||
* [#1833](https://github.com/moment/moment/issues/1833) improve spm integration
|
||||
* [#1871](https://github.com/moment/moment/issues/1871) fix zone bug caused by Firefox 24
|
||||
* [#1882](https://github.com/moment/moment/issues/1882) Use hh:mm in Czech
|
||||
* [#1883](https://github.com/moment/moment/issues/1883) Fix 2.8.0 regression in duration as conversions
|
||||
* [#1890](https://github.com/moment/moment/issues/1890) Faster travis builds
|
||||
* [#1892](https://github.com/moment/moment/issues/1892) Faster isBefore/After/Same
|
||||
* [#1848](https://github.com/moment/moment/issues/1848) Fix flaky month diffs
|
||||
* [#1895](https://github.com/moment/moment/issues/1895) Fix 2.8.0 regression in moment.utc with format array
|
||||
* [#1896](https://github.com/moment/moment/issues/1896) Support setting invalid instance locale (noop)
|
||||
* [#1897](https://github.com/moment/moment/issues/1897) Support moment([str]) in addition to moment([int])
|
||||
|
||||
### 2.8.2
|
||||
|
||||
Minor bugfixes:
|
||||
|
||||
* [#1874](https://github.com/moment/moment/issues/1874) use `Object.prototype.hasOwnProperty`
|
||||
instead of `obj.hasOwnProperty` (ie8 bug)
|
||||
* [#1873](https://github.com/moment/moment/issues/1873) add `duration#toString()`
|
||||
* [#1859](https://github.com/moment/moment/issues/1859) better month/weekday names in norwegian
|
||||
* [#1812](https://github.com/moment/moment/issues/1812) meridiem parsing for greek
|
||||
* [#1804](https://github.com/moment/moment/issues/1804) spanish del -> de
|
||||
* [#1800](https://github.com/moment/moment/issues/1800) korean LT improvement
|
||||
|
||||
### 2.8.1
|
||||
|
||||
* bugfix [#1813](https://github.com/moment/moment/issues/1813): fix moment().lang([key]) incompatibility
|
||||
|
||||
### 2.8.0 [See changelog](https://gist.github.com/ichernev/ac3899324a5fa6c8c9b4)
|
||||
|
||||
* incompatible changes
|
||||
* [#1761](https://github.com/moment/moment/issues/1761): moments created without a language are no longer following the global language, in case it changes. Only newly created moments take the global language by default. In case you're affected by this, wait, comment on [#1797](https://github.com/moment/moment/issues/1797) and wait for a proper reimplementation
|
||||
* [#1642](https://github.com/moment/moment/issues/1642): 45 days is no longer "a month" according to humanize, cutoffs for month, and year have changed. Hopefully your code does not depend on a particular answer from humanize (which it shouldn't anyway)
|
||||
* [#1784](https://github.com/moment/moment/issues/1784): if you use the human readable English datetime format in a weird way (like storing them in a database) that would break when the format changes you're at risk.
|
||||
|
||||
* deprecations (old behavior will be dropped in 3.0)
|
||||
* [#1761](https://github.com/moment/moment/issues/1761) `lang` is renamed to `locale`, `langData` -> `localeData`. Also there is now `defineLocale` that should be used when creating new locales
|
||||
* [#1763](https://github.com/moment/moment/issues/1763) `add(unit, value)` and `subtract(unit, value)` are now deprecated. Use `add(value, unit)` and `subtract(value, unit)` instead.
|
||||
* [#1759](https://github.com/moment/moment/issues/1759) rename `duration.toIsoString` to `duration.toISOString`. The js standard library and moment's `toISOString` follow that convention.
|
||||
|
||||
* new locales
|
||||
* [#1789](https://github.com/moment/moment/issues/1789) Tibetan (bo)
|
||||
* [#1786](https://github.com/moment/moment/issues/1786) Africaans (af)
|
||||
* [#1778](https://github.com/moment/moment/issues/1778) Burmese (my)
|
||||
* [#1727](https://github.com/moment/moment/issues/1727) Belarusian (be)
|
||||
|
||||
* bugfixes, locale bugfixes, performance improvements, features
|
||||
|
||||
### 2.7.0 [See changelog](https://gist.github.com/ichernev/b0a3d456d5a84c9901d7)
|
||||
|
||||
* new languages
|
||||
|
||||
* [#1678](https://github.com/moment/moment/issues/1678) Bengali (bn)
|
||||
* [#1628](https://github.com/moment/moment/issues/1628) Azerbaijani (az)
|
||||
* [#1633](https://github.com/moment/moment/issues/1633) Arabic, Saudi Arabia (ar-sa)
|
||||
* [#1648](https://github.com/moment/moment/issues/1648) Austrian German (de-at)
|
||||
|
||||
* features
|
||||
|
||||
* [#1663](https://github.com/moment/moment/issues/1663) configurable relative time thresholds
|
||||
* [#1554](https://github.com/moment/moment/issues/1554) support anchor time in moment.calendar
|
||||
* [#1693](https://github.com/moment/moment/issues/1693) support moment.ISO_8601 as parsing format
|
||||
* [#1637](https://github.com/moment/moment/issues/1637) add moment.min and moment.max and deprecate min/max instance methods
|
||||
* [#1704](https://github.com/moment/moment/issues/1704) support string value in add/subtract
|
||||
* [#1647](https://github.com/moment/moment/issues/1647) add spm support (package manager)
|
||||
|
||||
* bugfixes
|
||||
|
||||
### 2.6.0 [See changelog](https://gist.github.com/ichernev/10544682)
|
||||
|
||||
* languages
|
||||
* [#1529](https://github.com/moment/moment/issues/1529) Serbian-Cyrillic (sr-cyr)
|
||||
* [#1544](https://github.com/moment/moment/issues/1544), [#1546](https://github.com/moment/moment/issues/1546) Khmer Cambodia (km)
|
||||
|
||||
* features
|
||||
* [#1419](https://github.com/moment/moment/issues/1419), [#1468](https://github.com/moment/moment/issues/1468), [#1467](https://github.com/moment/moment/issues/1467), [#1546](https://github.com/moment/moment/issues/1546) better handling of timezone-d moments around DST
|
||||
* [#1462](https://github.com/moment/moment/issues/1462) add weeksInYear and isoWeeksInYear
|
||||
* [#1475](https://github.com/moment/moment/issues/1475) support ordinal parsing
|
||||
* [#1499](https://github.com/moment/moment/issues/1499) composer support
|
||||
* [#1577](https://github.com/moment/moment/issues/1577), [#1604](https://github.com/moment/moment/issues/1604) put Date parsing in moment.createFromInputFallback so it can be properly deprecated and controlled in the future
|
||||
* [#1545](https://github.com/moment/moment/issues/1545) extract two-digit year parsing in moment.parseTwoDigitYear, so it can be overwritten
|
||||
* [#1590](https://github.com/moment/moment/issues/1590) (see [#1574](https://github.com/moment/moment/issues/1574)) set AMD global before module definition to better support non AMD module dependencies used in AMD environment
|
||||
* [#1589](https://github.com/moment/moment/issues/1589) remove global in Node.JS environment (was not working before, nobody complained, was scheduled for removal anyway)
|
||||
* [#1586](https://github.com/moment/moment/issues/1586) support quarter setting and parsing
|
||||
|
||||
* 18 bugs fixed
|
||||
|
||||
### 2.5.1
|
||||
|
||||
* languages
|
||||
* [#1392](https://github.com/moment/moment/issues/1392) Armenian (hy-am)
|
||||
|
||||
* bugfixes
|
||||
* [#1429](https://github.com/moment/moment/issues/1429) fixes [#1423](https://github.com/moment/moment/issues/1423) weird chrome-32 bug with js object creation
|
||||
* [#1421](https://github.com/moment/moment/issues/1421) remove html entities from Welsh
|
||||
* [#1418](https://github.com/moment/moment/issues/1418) fixes [#1401](https://github.com/moment/moment/issues/1401) improved non-padded tokens in strict matching
|
||||
* [#1417](https://github.com/moment/moment/issues/1417) fixes [#1404](https://github.com/moment/moment/issues/1404) handle buggy moment object created by property cloning
|
||||
* [#1398](https://github.com/moment/moment/issues/1398) fixes [#1397](https://github.com/moment/moment/issues/1397) fix Arabic-like week number parsing
|
||||
* [#1396](https://github.com/moment/moment/issues/1396) add leftZeroFill(4) to GGGG and gggg formats
|
||||
* [#1373](https://github.com/moment/moment/issues/1373) use lowercase for months and days in Catalan
|
||||
|
||||
* testing
|
||||
* [#1374](https://github.com/moment/moment/issues/1374) run tests on multiple browser/os combos via SauceLabs and Travis
|
||||
|
||||
### 2.5.0 [See changelog](https://gist.github.com/ichernev/8104451)
|
||||
|
||||
* New languages
|
||||
* Luxemburish (lb) [1247](https://github.com/moment/moment/issues/1247)
|
||||
* Serbian (rs) [1319](https://github.com/moment/moment/issues/1319)
|
||||
* Tamil (ta) [1324](https://github.com/moment/moment/issues/1324)
|
||||
* Macedonian (mk) [1337](https://github.com/moment/moment/issues/1337)
|
||||
|
||||
* Features
|
||||
* [1311](https://github.com/moment/moment/issues/1311) Add quarter getter and format token `Q`
|
||||
* [1303](https://github.com/moment/moment/issues/1303) strict parsing now respects number of digits per token (fix [1196](https://github.com/moment/moment/issues/1196))
|
||||
* 0d30bb7 add jspm support
|
||||
* [1347](https://github.com/moment/moment/issues/1347) improve zone parsing
|
||||
* [1362](https://github.com/moment/moment/issues/1362) support merideam parsing in Korean
|
||||
|
||||
* 22 bugfixes
|
||||
|
||||
### 2.4.0
|
||||
|
||||
* **Deprecate** globally exported moment, will be removed in next major
|
||||
* New languages
|
||||
* Farose (fo) [#1206](https://github.com/moment/moment/issues/1206)
|
||||
* Tagalog/Filipino (tl-ph) [#1197](https://github.com/moment/moment/issues/1197)
|
||||
* Welsh (cy) [#1215](https://github.com/moment/moment/issues/1215)
|
||||
* Bugfixes
|
||||
* properly handle Z at the end of iso RegExp [#1187](https://github.com/moment/moment/issues/1187)
|
||||
* chinese meridian time improvements [#1076](https://github.com/moment/moment/issues/1076)
|
||||
* fix language tests [#1177](https://github.com/moment/moment/issues/1177)
|
||||
* remove some failing tests (that should have never existed :))
|
||||
[#1185](https://github.com/moment/moment/issues/1185)
|
||||
[#1183](https://github.com/moment/moment/issues/1183)
|
||||
* handle russian noun cases in weird cases [#1195](https://github.com/moment/moment/issues/1195)
|
||||
|
||||
### 2.3.1
|
||||
|
||||
Removed a trailing comma [1169] and fixed a bug with `months`, `weekdays` getters [#1171](https://github.com/moment/moment/issues/1171).
|
||||
|
||||
### 2.3.0 [See changelog](https://gist.github.com/ichernev/6864354)
|
||||
|
||||
Changed isValid, added strict parsing.
|
||||
Week tokens parsing.
|
||||
|
||||
### 2.2.1
|
||||
|
||||
Fixed bug in string prototype test.
|
||||
Updated authors and contributors.
|
||||
|
||||
### 2.2.0 [See changelog](https://gist.github.com/ichernev/00f837a9baf46a3565e4)
|
||||
|
||||
Added bower support.
|
||||
|
||||
Language files now use UMD.
|
||||
|
||||
Creating moment defaults to current date/month/year.
|
||||
|
||||
Added a bundle of moment and all language files.
|
||||
|
||||
### 2.1.0 [See changelog](https://gist.github.com/timrwood/b8c2d90d528eddb53ab5)
|
||||
|
||||
Added better week support.
|
||||
|
||||
Added ability to set offset with `moment#zone`.
|
||||
|
||||
Added ability to set month or weekday from a string.
|
||||
|
||||
Added `moment#min` and `moment#max`
|
||||
|
||||
### 2.0.0 [See changelog](https://gist.github.com/timrwood/e72f2eef320ed9e37c51)
|
||||
|
||||
Added short form localized tokens.
|
||||
|
||||
Added ability to define language a string should be parsed in.
|
||||
|
||||
Added support for reversed add/subtract arguments.
|
||||
|
||||
Added support for `endOf('week')` and `startOf('week')`.
|
||||
|
||||
Fixed the logic for `moment#diff(Moment, 'months')` and `moment#diff(Moment, 'years')`
|
||||
|
||||
`moment#diff` now floors instead of rounds.
|
||||
|
||||
Normalized `moment#toString`.
|
||||
|
||||
Added `isSame`, `isAfter`, and `isBefore` methods.
|
||||
|
||||
Added better week support.
|
||||
|
||||
Added `moment#toJSON`
|
||||
|
||||
Bugfix: Fixed parsing of first century dates
|
||||
|
||||
Bugfix: Parsing 10Sep2001 should work as expected
|
||||
|
||||
Bugfix: Fixed weirdness with `moment.utc()` parsing.
|
||||
|
||||
Changed language ordinal method to return the number + ordinal instead of just the ordinal.
|
||||
|
||||
Changed two digit year parsing cutoff to match strptime.
|
||||
|
||||
Removed `moment#sod` and `moment#eod` in favor of `moment#startOf` and `moment#endOf`.
|
||||
|
||||
Removed `moment.humanizeDuration()` in favor of `moment.duration().humanize()`.
|
||||
|
||||
Removed the lang data objects from the top level namespace.
|
||||
|
||||
Duplicate `Date` passed to `moment()` instead of referencing it.
|
||||
|
||||
### 1.7.2 [See discussion](https://github.com/timrwood/moment/issues/456)
|
||||
|
||||
Bugfixes
|
||||
|
||||
### 1.7.1 [See discussion](https://github.com/timrwood/moment/issues/384)
|
||||
|
||||
Bugfixes
|
||||
|
||||
### 1.7.0 [See discussion](https://github.com/timrwood/moment/issues/288)
|
||||
|
||||
Added `moment.fn.endOf()` and `moment.fn.startOf()`.
|
||||
|
||||
Added validation via `moment.fn.isValid()`.
|
||||
|
||||
Made formatting method 3x faster. http://jsperf.com/momentjs-cached-format-functions
|
||||
|
||||
Add support for month/weekday callbacks in `moment.fn.format()`
|
||||
|
||||
Added instance specific languages.
|
||||
|
||||
Added two letter weekday abbreviations with the formatting token `dd`.
|
||||
|
||||
Various language updates.
|
||||
|
||||
Various bugfixes.
|
||||
|
||||
### 1.6.0 [See discussion](https://github.com/timrwood/moment/pull/268)
|
||||
|
||||
Added Durations.
|
||||
|
||||
Revamped parser to support parsing non-separated strings (YYYYMMDD vs YYYY-MM-DD).
|
||||
|
||||
Added support for millisecond parsing and formatting tokens (S SS SSS)
|
||||
|
||||
Added a getter for `moment.lang()`
|
||||
|
||||
Various bugfixes.
|
||||
|
||||
There are a few things deprecated in the 1.6.0 release.
|
||||
|
||||
1. The format tokens `z` and `zz` (timezone abbreviations like EST CST MST etc) will no longer be supported. Due to inconsistent browser support, we are unable to consistently produce this value. See [this issue](https://github.com/timrwood/moment/issues/162) for more background.
|
||||
|
||||
2. The method `moment.fn.native` is deprecated in favor of `moment.fn.toDate`. There continue to be issues with Google Closure Compiler throwing errors when using `native`, even in valid instances.
|
||||
|
||||
3. The way to customize am/pm strings is being changed. This would only affect you if you created a custom language file. For more information, see [this issue](https://github.com/timrwood/moment/pull/222).
|
||||
|
||||
### 1.5.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=10&page=1&state=closed)
|
||||
|
||||
Added UTC mode.
|
||||
|
||||
Added automatic ISO8601 parsing.
|
||||
|
||||
Various bugfixes.
|
||||
|
||||
### 1.4.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=8&state=closed)
|
||||
|
||||
Added `moment.fn.toDate` as a replacement for `moment.fn.native`.
|
||||
|
||||
Added `moment.fn.sod` and `moment.fn.eod` to get the start and end of day.
|
||||
|
||||
Various bugfixes.
|
||||
|
||||
### 1.3.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=7&state=closed)
|
||||
|
||||
Added support for parsing month names in the current language.
|
||||
|
||||
Added escape blocks for parsing tokens.
|
||||
|
||||
Added `moment.fn.calendar` to format strings like 'Today 2:30 PM', 'Tomorrow 1:25 AM', and 'Last Sunday 4:30 AM'.
|
||||
|
||||
Added `moment.fn.day` as a setter.
|
||||
|
||||
Various bugfixes
|
||||
|
||||
### 1.2.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=4&state=closed)
|
||||
|
||||
Added timezones to parser and formatter.
|
||||
|
||||
Added `moment.fn.isDST`.
|
||||
|
||||
Added `moment.fn.zone` to get the timezone offset in minutes.
|
||||
|
||||
### 1.1.2 [See milestone](https://github.com/timrwood/moment/issues?milestone=6&state=closed)
|
||||
|
||||
Various bugfixes
|
||||
|
||||
### 1.1.1 [See milestone](https://github.com/timrwood/moment/issues?milestone=5&state=closed)
|
||||
|
||||
Added time specific diffs (months, days, hours, etc)
|
||||
|
||||
### 1.1.0
|
||||
|
||||
Added `moment.fn.format` localized masks. 'L LL LLL LLLL' [issue 29](https://github.com/timrwood/moment/pull/29)
|
||||
|
||||
Fixed [issue 31](https://github.com/timrwood/moment/pull/31).
|
||||
|
||||
### 1.0.1
|
||||
|
||||
Added `moment.version` to get the current version.
|
||||
|
||||
Removed `window !== undefined` when checking if module exists to support browserify. [issue 25](https://github.com/timrwood/moment/pull/25)
|
||||
|
||||
### 1.0.0
|
||||
|
||||
Added convenience methods for getting and setting date parts.
|
||||
|
||||
Added better support for `moment.add()`.
|
||||
|
||||
Added better lang support in NodeJS.
|
||||
|
||||
Renamed library from underscore.date to Moment.js
|
||||
|
||||
### 0.6.1
|
||||
|
||||
Added Portuguese, Italian, and French language support
|
||||
|
||||
### 0.6.0
|
||||
|
||||
Added _date.lang() support.
|
||||
Added support for passing multiple formats to try to parse a date. _date("07-10-1986", ["MM-DD-YYYY", "YYYY-MM-DD"]);
|
||||
Made parse from string and single format 25% faster.
|
||||
|
||||
### 0.5.2
|
||||
|
||||
Bugfix for [issue 8](https://github.com/timrwood/underscore.date/pull/8) and [issue 9](https://github.com/timrwood/underscore.date/pull/9).
|
||||
|
||||
### 0.5.1
|
||||
|
||||
Bugfix for [issue 5](https://github.com/timrwood/underscore.date/pull/5).
|
||||
|
||||
### 0.5.0
|
||||
|
||||
Dropped the redundant `_date.date()` in favor of `_date()`.
|
||||
Removed `_date.now()`, as it is a duplicate of `_date()` with no parameters.
|
||||
Removed `_date.isLeapYear(yearNumber)`. Use `_date([yearNumber]).isLeapYear()` instead.
|
||||
Exposed customization options through the `_date.relativeTime`, `_date.weekdays`, `_date.weekdaysShort`, `_date.months`, `_date.monthsShort`, and `_date.ordinal` variables instead of the `_date.customize()` function.
|
||||
|
||||
### 0.4.1
|
||||
|
||||
Added date input formats for input strings.
|
||||
|
||||
### 0.4.0
|
||||
|
||||
Added underscore.date to npm. Removed dependencies on underscore.
|
||||
|
||||
### 0.3.2
|
||||
|
||||
Added `'z'` and `'zz'` to `_.date().format()`. Cleaned up some redundant code to trim off some bytes.
|
||||
|
||||
### 0.3.1
|
||||
|
||||
Cleaned up the namespace. Moved all date manipulation and display functions to the _.date() object.
|
||||
|
||||
### 0.3.0
|
||||
|
||||
Switched to the Underscore methodology of not mucking with the native objects' prototypes.
|
||||
Made chaining possible.
|
||||
|
||||
### 0.2.1
|
||||
|
||||
Changed date names to be a more pseudo standardized 'dddd, MMMM Do YYYY, h:mm:ss a'.
|
||||
Added `Date.prototype` functions `add`, `subtract`, `isdst`, and `isleapyear`.
|
||||
|
||||
### 0.2.0
|
||||
|
||||
Changed function names to be more concise.
|
||||
Changed date format from php date format to custom format.
|
||||
|
||||
### 0.1.0
|
||||
|
||||
Initial release
|
||||
|
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors
|
||||
|
||||
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.
|
@ -1,58 +0,0 @@
|
||||
[](https://gitter.im/moment/moment?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![MIT License][license-image]][license-url] [![Build Status][travis-image]][travis-url]
|
||||
[](https://coveralls.io/r/moment/moment?branch=develop)
|
||||
|
||||
A lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
|
||||
|
||||
**[Documentation](http://momentjs.com/docs/)**
|
||||
|
||||
## Port to ECMAScript 6 (version 2.10.0)
|
||||
|
||||
Moment 2.10.0 does not bring any new features, but the code is now written in
|
||||
ECMAScript 6 modules and placed inside `src/`. Previously `moment.js`, `locale/*.js` and
|
||||
`test/moment/*.js`, `test/locale/*.js` contained the source of the project. Now
|
||||
the source is in `src/`, temporary build (ECMAScript 5) files are placed under
|
||||
`build/umd/` (for running tests during development), and the `moment.js` and
|
||||
`locale/*.js` files are updated only on release.
|
||||
|
||||
If you want to use a particular revision of the code, make sure to run
|
||||
`grunt transpile update-index`, so `moment.js` and `locales/*.js` are synced
|
||||
with `src/*`. We might place that in a commit hook in the future.
|
||||
|
||||
## Upgrading to 2.0.0
|
||||
|
||||
There are a number of small backwards incompatible changes with version 2.0.0. [See the full descriptions here](https://gist.github.com/timrwood/e72f2eef320ed9e37c51#backwards-incompatible-changes)
|
||||
|
||||
* Changed language ordinal method to return the number + ordinal instead of just the ordinal.
|
||||
|
||||
* Changed two digit year parsing cutoff to match strptime.
|
||||
|
||||
* Removed `moment#sod` and `moment#eod` in favor of `moment#startOf` and `moment#endOf`.
|
||||
|
||||
* Removed `moment.humanizeDuration()` in favor of `moment.duration().humanize()`.
|
||||
|
||||
* Removed the lang data objects from the top level namespace.
|
||||
|
||||
* Duplicate `Date` passed to `moment()` instead of referencing it.
|
||||
|
||||
## [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
|
||||
|
||||
## [Contributing](https://github.com/moment/moment/blob/develop/CONTRIBUTING.md)
|
||||
|
||||
We're looking for co-maintainers! If you want to become a master of time please
|
||||
write to [ichernev](https://github.com/ichernev).
|
||||
|
||||
## License
|
||||
|
||||
Moment.js is freely distributable under the terms of the [MIT license](https://github.com/moment/moment/blob/develop/LICENSE).
|
||||
|
||||
[license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat
|
||||
[license-url]: LICENSE
|
||||
|
||||
[npm-url]: https://npmjs.org/package/moment
|
||||
[npm-version-image]: http://img.shields.io/npm/v/moment.svg?style=flat
|
||||
[npm-downloads-image]: http://img.shields.io/npm/dm/moment.svg?style=flat
|
||||
|
||||
[travis-url]: http://travis-ci.org/moment/moment
|
||||
[travis-image]: http://img.shields.io/travis/moment/moment/develop.svg?style=flat
|
File diff suppressed because it is too large
Load Diff
7
library/moment/moment.min.js
vendored
7
library/moment/moment.min.js
vendored
File diff suppressed because one or more lines are too long
@ -139,7 +139,7 @@ class LanguageTest extends UnitTestCase {
|
||||
'en-gb',
|
||||
'British English',
|
||||
[
|
||||
'de' => 'Britisches Englisch',
|
||||
'de' => 'Englisch (Vereinigtes Königreich)',
|
||||
'nb' => 'engelsk (Storbritannia)'
|
||||
]
|
||||
],
|
||||
@ -147,7 +147,7 @@ class LanguageTest extends UnitTestCase {
|
||||
'en-au',
|
||||
'Australian English',
|
||||
[
|
||||
'de' => 'Australisches Englisch',
|
||||
'de' => 'Englisch (Australien)',
|
||||
'nb' => 'engelsk (Australia)'
|
||||
]
|
||||
],
|
||||
|
24266
util/hmessages.po
24266
util/hmessages.po
File diff suppressed because it is too large
Load Diff
@ -52,7 +52,7 @@ function po2php_run($argc,$argv) {
|
||||
if ($l[0]=="#") $l="";
|
||||
if (substr($l,0,15)=='"Plural-Forms: '){
|
||||
$match=Array();
|
||||
preg_match("|nplurals=([0-9]*);\s*plural=(.*)[;\\\\]|", $l, $match);
|
||||
preg_match("|nplurals=([0-9]*);\s*plural=([^;\\\\]*)|", $l, $match);
|
||||
$cond = str_replace('n','$n',$match[2]);
|
||||
$out .= 'if(! function_exists("' . 'string_plural_select_' . $lang .'")) {' . "\n";
|
||||
$out .= 'function string_plural_select_' . $lang . '($n){'."\n";
|
||||
|
@ -17,7 +17,7 @@ if($x) {
|
||||
$width = $xx['width'];
|
||||
$height = $xx['height'];
|
||||
|
||||
$n = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale > 0",
|
||||
$n = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale > 0 ORDER BY imgscale",
|
||||
dbesc($xx['resource_id'])
|
||||
);
|
||||
|
||||
|
@ -16,6 +16,13 @@ Extract somewere and launch zotsh.py
|
||||
Description
|
||||
-----------
|
||||
|
||||
Update: 2019-08-14
|
||||
|
||||
Have just looked at this after several years of bitrot and made some updates.
|
||||
it functions for cli DAV access on your assigned hub, but magic-auth to dav repos on other hubs
|
||||
(e.g. the host command) needs to be updated to work with openwebauth.
|
||||
|
||||
----
|
||||
ZotSH is a command line WebDAV client for Hubzilla.
|
||||
It knows how to magic-auth to remote hubs using Zot.
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -31,7 +31,7 @@ File = namedtuple('File', ['name', 'size', 'mtime', 'ctime', 'contenttype'])
|
||||
|
||||
def prop(elem, name, default=None):
|
||||
child = elem.find('.//{DAV:}' + name)
|
||||
return default if child is None else child.text
|
||||
return default if child is None or child.text is None else child.text
|
||||
|
||||
|
||||
def elem2file(elem):
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user