aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Daemon/Master.php5
-rw-r--r--Zotlabs/Module/Acl.php7
-rw-r--r--Zotlabs/Module/Linkinfo.php4
-rw-r--r--Zotlabs/Module/Network.php59
-rw-r--r--Zotlabs/Module/Ping.php23
-rw-r--r--Zotlabs/Widget/Activity_filter.php59
-rw-r--r--Zotlabs/Widget/Activity_order.php4
-rwxr-xr-xboot.php2
-rwxr-xr-xinclude/dba/dba_driver.php2
-rwxr-xr-xinclude/items.php21
-rw-r--r--library/blueimp_upload/.gitignore3
-rw-r--r--library/blueimp_upload/.jshintrc81
-rw-r--r--library/blueimp_upload/.npmignore20
-rw-r--r--library/blueimp_upload/LICENSE20
-rw-r--r--library/blueimp_upload/LICENSE.txt21
-rw-r--r--library/blueimp_upload/README.md4
-rw-r--r--library/blueimp_upload/angularjs.html18
-rw-r--r--library/blueimp_upload/basic-plus.html10
-rw-r--r--library/blueimp_upload/basic.html6
-rw-r--r--library/blueimp_upload/bower.json6
-rw-r--r--library/blueimp_upload/cors/postmessage.html2
-rw-r--r--library/blueimp_upload/css/jquery-ui-demo-ie8.css (renamed from library/blueimp_upload/css/demo-ie8.css)0
-rw-r--r--library/blueimp_upload/css/jquery-ui-demo.css (renamed from library/blueimp_upload/css/demo.css)0
-rw-r--r--library/blueimp_upload/index.html18
-rw-r--r--library/blueimp_upload/jquery-ui.html24
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-angular.js1
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-ui.js1
-rw-r--r--library/blueimp_upload/js/jquery.fileupload.js32
-rw-r--r--library/blueimp_upload/js/vendor/jquery.ui.widget.js1302
-rw-r--r--library/blueimp_upload/package.json2
-rw-r--r--library/blueimp_upload/server/php/Dockerfile2
-rwxr-xr-xlibrary/blueimp_upload/server/php/UploadHandler.php48
-rw-r--r--library/blueimp_upload/server/php/docker-compose.yml15
-rw-r--r--library/blueimp_upload/test/index.html12
-rw-r--r--view/js/autocomplete.js46
-rw-r--r--view/theme/redbasic/css/style.css6
-rwxr-xr-xview/tpl/build_query.tpl2
-rw-r--r--view/tpl/notifications_widget.tpl2
38 files changed, 1141 insertions, 749 deletions
diff --git a/Zotlabs/Daemon/Master.php b/Zotlabs/Daemon/Master.php
index 3a71ee578..0656ca05b 100644
--- a/Zotlabs/Daemon/Master.php
+++ b/Zotlabs/Daemon/Master.php
@@ -60,7 +60,8 @@ class Master {
$k = explode('_',$worker['k']);
q("delete from config where cat='queueworkers' and k='%s'",
'workerstarted_'.$k[1]);
- q("update config set k='workitem' where cat='queuework' and k='%s'",
+ q("update config set k='%s' where cat='queuework' and k='%s'",
+ dbesc(uniqid('workitem:',true)),
'workitem_'.$k[1]);
unset($workers[$idx]);
}
@@ -69,7 +70,7 @@ class Master {
return false;
}
}
- return uniqid();
+ return uniqid('',true);
}
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index ea131e08c..738e8fbe2 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -83,7 +83,8 @@ class Acl extends \Zotlabs\Web\Controller {
if($search) {
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
$sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
-
+ $sql_extra2_xchan = "AND ( xchan_name LIKE " . protect_sprintf( "'" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
+
// This horrible mess is needed because position also returns 0 if nothing is found.
// Would be MUCH easier if it instead returned a very large value
// Otherwise we could just
@@ -226,7 +227,7 @@ class Acl extends \Zotlabs\Web\Controller {
else { // Visitors
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan left join xlink on xlink_link = xchan_hash
- WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
+ WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2_xchan order by $order_extra2 xchan_name asc" ,
dbesc(get_observer_hash())
);
@@ -270,7 +271,7 @@ class Acl extends \Zotlabs\Web\Controller {
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan
- WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2 order by $order_extra2 xchan_name asc"
+ WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2_xchan order by $order_extra2 xchan_name asc"
);
if($r2) {
$r = array_merge($r,$r2);
diff --git a/Zotlabs/Module/Linkinfo.php b/Zotlabs/Module/Linkinfo.php
index f0d62b5e0..a0ad17e68 100644
--- a/Zotlabs/Module/Linkinfo.php
+++ b/Zotlabs/Module/Linkinfo.php
@@ -228,8 +228,8 @@ class Linkinfo extends \Zotlabs\Web\Controller {
$header = $result['header'];
$body = $result['body'];
-
- $body = mb_convert_encoding($body, 'UTF-8', 'UTF-8');
+
+ $body = mb_convert_encoding($body, 'UTF-8', (preg_match('/meta.+content=["|\']text\/html;\s+charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'UTF-8'));
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$doc = new \DOMDocument();
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index 792f92418..294e11c52 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -128,11 +128,12 @@ class Network extends \Zotlabs\Web\Controller {
$xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
$net = ((x($_GET,'net')) ? $_GET['net'] : '');
$pf = ((x($_GET,'pf')) ? $_GET['pf'] : '');
+ $unseen = ((x($_GET,'unseen')) ? $_GET['unseen'] : '');
$deftag = '';
- if(x($_GET,'search') || $file || (!$pf && $cid) || $hashtags || $verb || $category)
+ if(x($_GET,'search') || $file || (!$pf && $cid) || $hashtags || $verb || $category || $conv || $unseen)
$nouveau = true;
if($cid) {
@@ -220,6 +221,7 @@ class Network extends \Zotlabs\Web\Controller {
$sql_extra = '';
if($group) {
+
$contact_str = '';
$contacts = group_get_members($group);
if($contacts) {
@@ -232,7 +234,6 @@ class Network extends \Zotlabs\Web\Controller {
}
}
$item_thread_top = '';
-
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash(local_channel(), $group_hash);
@@ -252,15 +253,35 @@ class Network extends \Zotlabs\Web\Controller {
if($load || $update) {
if(!$pf && $nouveau) {
+ // This is for nouveau view cid queries (not a public forum)
$sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ";
}
+ elseif($pf && $unseen && $nouveau) {
+
+ // This is for nouveau view public forum cid queries (if a forum notification is clicked)
+ $p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
+ intval(local_channel()),
+ intval(TERM_FORUM),
+ dbesc($cid_r[0]['xchan_name'])
+ );
+
+ $p_str = ids_to_querystr($p, 'parent');
+ if($p_str)
+ $p_sql = " OR item.parent IN ( $p_str ) ";
+
+ $sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 ";
+ }
else {
+ // This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)
$ttype = (($pf) ? TERM_FORUM : TERM_MENTION);
$p1 = q("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal ");
$p2 = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'");
$p_str = ids_to_querystr(array_merge($p1,$p2),'parent');
+ if(! $p_str)
+ killme();
+
$sql_extra = " AND item.parent IN ( $p_str ) ";
}
}
@@ -345,7 +366,8 @@ class Network extends \Zotlabs\Web\Controller {
'$verb' => $verb,
'$net' => $net,
'$dbegin' => $datequery2,
- '$pf' => (($pf) ? $pf : '0'),
+ '$pf' => (($pf) ? $pf : '0'),
+ '$unseen' => $unseen
));
}
@@ -386,15 +408,7 @@ class Network extends \Zotlabs\Web\Controller {
if($conv) {
$item_thread_top = '';
-
- if($nouveau) {
- $sql_extra .= " AND author_xchan = '" . dbesc($channel['channel_hash']) . "' ";
- }
- else {
- $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan = '%s' or item_mentionsme = 1 )) ",
- dbesc(protect_sprintf($channel['channel_hash']))
- );
- }
+ $sql_extra .= " AND ( author_xchan = '" . dbesc($channel['channel_hash']) . "' OR item_mentionsme = 1 ) ";
}
if($update && ! $load) {
@@ -441,9 +455,11 @@ class Network extends \Zotlabs\Web\Controller {
$page_mode = 'list';
else
$page_mode = 'client';
-
- $simple_update = (($update) ? " and item_unseen = 1 " : '');
+ $parents_str = '';
+ $update_unseen = '';
+
+ $simple_update = (($update) ? " and item_unseen = 1 " : '');
// This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day
// or three and look at your matrix page - after opening up your browser. The first page loads just as it
@@ -459,15 +475,15 @@ class Network extends \Zotlabs\Web\Controller {
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
- if($load)
- $simple_update = '';
+
+ if($load)
+ $simple_update = '';
if($static && $simple_update)
$simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
if($nouveau && $load) {
// "New Item View" - show all items unthreaded in reverse created date order
-
$items = q("SELECT item.*, item.id AS item_id, created FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
$net_query
@@ -478,7 +494,12 @@ class Network extends \Zotlabs\Web\Controller {
$net_query2
ORDER BY item.created DESC $pager_sql "
);
-
+
+ $parents_str = ids_to_querystr($items,'item_id');
+ if($parents_str) {
+ $update_unseen = " AND id IN ( " . dbesc($parents_str) . " )";
+ }
+
require_once('include/items.php');
xchan_query($items);
@@ -521,8 +542,6 @@ class Network extends \Zotlabs\Web\Controller {
}
// Then fetch all the children of the parents that are on this page
- $parents_str = '';
- $update_unseen = '';
if($r) {
diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php
index 14627f56e..75e8843d6 100644
--- a/Zotlabs/Module/Ping.php
+++ b/Zotlabs/Module/Ping.php
@@ -634,23 +634,30 @@ class Ping extends \Zotlabs\Web\Controller {
if($vnotify & VNOTIFY_FORUMS) {
$forums = get_forum_channels(local_channel());
- if(! $forums) {
- $result['forums'] = 0;
- }
- else {
-
- $perms_sql = item_permissions_sql(local_channel()) . item_normal();
+ if($forums) {
+ $perms_sql = item_permissions_sql(local_channel());
+ $item_normal = item_normal();
$fcount = count($forums);
$forums['total'] = 0;
for($x = 0; $x < $fcount; $x ++) {
+ $p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
+ intval(local_channel()),
+ intval(TERM_FORUM),
+ dbesc($forums[$x]['xchan_hash'])
+ );
+
+ $p_str = ids_to_querystr($p, 'parent');
+ $p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
+
$r = q("select sum(item_unseen) as unseen from item
- where uid = %d and owner_xchan = '%s' and item_unseen = 1 $perms_sql ",
+ where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $perms_sql $item_normal",
intval(local_channel()),
+ dbesc($forums[$x]['xchan_hash']),
dbesc($forums[$x]['xchan_hash'])
);
if($r[0]['unseen']) {
- $forums[$x]['notify_link'] = (($forums[$x]['private_forum']) ? $forums[$x]['xchan_url'] : z_root() . '/network/?f=&pf=1&cid=' . $forums[$x]['abook_id']);
+ $forums[$x]['notify_link'] = (($forums[$x]['private_forum']) ? $forums[$x]['xchan_url'] : z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id']);
$forums[$x]['name'] = $forums[$x]['xchan_name'];
$forums[$x]['url'] = $forums[$x]['xchan_url'];
$forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php
index 4ea0086dd..32ab10c77 100644
--- a/Zotlabs/Widget/Activity_filter.php
+++ b/Zotlabs/Widget/Activity_filter.php
@@ -16,35 +16,6 @@ class Activity_filter {
$tabs = [];
- if(feature_enabled(local_channel(),'personal_tab')) {
- if(x($_GET,'conv')) {
- $conv_active = (($_GET['conv'] == 1) ? 'active' : '');
- $filter_active = 'personal';
- }
-
- $tabs[] = [
- 'label' => t('Personal Posts'),
- 'icon' => 'user-circle',
- 'url' => z_root() . '/' . $cmd . '/?f=&conv=1',
- 'sel' => $conv_active,
- 'title' => t('Show posts that mention or involve me')
- ];
- }
-
- if(feature_enabled(local_channel(),'star_posts')) {
- if(x($_GET,'star')) {
- $starred_active = (($_GET['star'] == 1) ? 'active' : '');
- $filter_active = 'star';
- }
-
- $tabs[] = [
- 'label' => t('Starred Posts'),
- 'icon' => 'star',
- 'url'=>z_root() . '/' . $cmd . '/?f=&star=1',
- 'sel'=>$starred_active,
- 'title' => t('Show posts that I have starred')
- ];
- }
if(Apps::system_app_installed(local_channel(), 'Privacy Groups')) {
$groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
@@ -110,6 +81,36 @@ class Activity_filter {
}
}
+ if(feature_enabled(local_channel(),'star_posts')) {
+ if(x($_GET,'star')) {
+ $starred_active = (($_GET['star'] == 1) ? 'active' : '');
+ $filter_active = 'star';
+ }
+
+ $tabs[] = [
+ 'label' => t('Starred Posts'),
+ 'icon' => 'star',
+ 'url'=>z_root() . '/' . $cmd . '/?f=&star=1',
+ 'sel'=>$starred_active,
+ 'title' => t('Show posts that I have starred')
+ ];
+ }
+
+ if(feature_enabled(local_channel(),'personal_tab')) {
+ if(x($_GET,'conv')) {
+ $conv_active = (($_GET['conv'] == 1) ? 'active' : '');
+ $filter_active = 'personal';
+ }
+
+ $tabs[] = [
+ 'label' => t('Personal Posts'),
+ 'icon' => 'user-circle',
+ 'url' => z_root() . '/' . $cmd . '/?f=&conv=1',
+ 'sel' => $conv_active,
+ 'title' => t('Show posts that mention or involve me')
+ ];
+ }
+
if(feature_enabled(local_channel(),'filing')) {
$terms = q("select distinct term from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
diff --git a/Zotlabs/Widget/Activity_order.php b/Zotlabs/Widget/Activity_order.php
index 1cba1ce8c..d3fe2a30f 100644
--- a/Zotlabs/Widget/Activity_order.php
+++ b/Zotlabs/Widget/Activity_order.php
@@ -54,8 +54,8 @@ class Activity_order {
}
}
- // override order for search, filer and cid results
- if(x($_GET,'search') || x($_GET,'file') || (! x($_GET,'pf') && x($_GET,'cid')) || x($_GET,'verb') || x($_GET,'tag') || x($_GET,'cat')) {
+ // override order for some filter results
+ if(x($_GET,'search') || x($_GET,'file') || (! x($_GET,'pf') && x($_GET,'cid')) || x($_GET,'verb') || x($_GET,'tag') || x($_GET,'cat') || x($_GET,'conv') || x($_GET,'unseen')) {
$unthreaded_active = 'active';
$commentord_active = $postord_active = 'disabled';
}
diff --git a/boot.php b/boot.php
index aa1941d19..e01763ca5 100755
--- a/boot.php
+++ b/boot.php
@@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
-define ( 'STD_VERSION', '3.8.1' );
+define ( 'STD_VERSION', '3.8.2' );
define ( 'ZOT_REVISION', '6.0a' );
diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php
index 9e9f24bb3..9533acc7f 100755
--- a/include/dba/dba_driver.php
+++ b/include/dba/dba_driver.php
@@ -484,4 +484,4 @@ function db_columns($table) {
}
return [];
-} \ No newline at end of file
+}
diff --git a/include/items.php b/include/items.php
index 58461cc3a..cae380b01 100755
--- a/include/items.php
+++ b/include/items.php
@@ -2150,6 +2150,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
unset($arr['created']);
unset($arr['author_xchan']);
unset($arr['owner_xchan']);
+ unset($arr['source_xchan']);
unset($arr['thr_parent']);
unset($arr['llink']);
@@ -2514,7 +2515,7 @@ function tag_deliver($uid, $item_id) {
// Just start the second delivery chain to deliver the updated post
// after resetting ownership and permission bits
logger('updating edited tag_deliver post for ' . $u[0]['channel_address']);
- start_delivery_chain($u[0], $item, $item_id, 0);
+ start_delivery_chain($u[0], $item, $item_id, 0, true);
return;
}
@@ -2941,7 +2942,7 @@ function tgroup_check($uid, $item) {
* @param int $item_id
* @param boolean $parent
*/
-function start_delivery_chain($channel, $item, $item_id, $parent) {
+function start_delivery_chain($channel, $item, $item_id, $parent, $edit = false) {
$sourced = check_item_source($channel['channel_id'],$item);
@@ -2950,7 +2951,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
intval($channel['channel_id']),
dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan'])
);
- if($r) {
+ if($r && ! $edit) {
$t = trim($r[0]['src_tag']);
if($t) {
$tags = explode(',',$t);
@@ -3017,9 +3018,17 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
}
else {
$item_uplink = 1;
- $r = q("update item set source_xchan = owner_xchan where id = %d",
- intval($item_id)
- );
+
+ // if this is an edit, item_store_update() will have already updated the item
+ // with the correct value for source_xchan (by ignoring it). We cannot set to owner_xchan
+ // in this case because owner_xchan will point to the parent of this chain
+ // and not the original sender.
+
+ if(! $edit) {
+ $r = q("update item set source_xchan = owner_xchan where id = %d",
+ intval($item_id)
+ );
+ }
}
$title = $item['title'];
diff --git a/library/blueimp_upload/.gitignore b/library/blueimp_upload/.gitignore
new file mode 100644
index 000000000..29a41a8c4
--- /dev/null
+++ b/library/blueimp_upload/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+*.pyc
+node_modules
diff --git a/library/blueimp_upload/.jshintrc b/library/blueimp_upload/.jshintrc
new file mode 100644
index 000000000..4ad82e664
--- /dev/null
+++ b/library/blueimp_upload/.jshintrc
@@ -0,0 +1,81 @@
+{
+ "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
+ "camelcase" : true, // true: Identifiers must be in camelCase
+ "curly" : true, // true: Require {} for every new block or scope
+ "eqeqeq" : true, // true: Require triple equals (===) for comparison
+ "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
+ "immed" : true, // true: Require immediate invocations to be wrapped in parens
+ // e.g. `(function () { } ());`
+ "indent" : 4, // {int} Number of spaces to use for indentation
+ "latedef" : true, // true: Require variables/functions to be defined before being used
+ "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
+ "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
+ "noempty" : true, // true: Prohibit use of empty blocks
+ "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
+ "plusplus" : false, // true: Prohibit use of `++` & `--`
+ "quotmark" : "single", // Quotation mark consistency:
+ // false : do nothing (default)
+ // true : ensure whatever is used is consistent
+ // "single" : require single quotes
+ // "double" : require double quotes
+ "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
+ "unused" : true, // true: Require all defined variables be used
+ "strict" : true, // true: Requires all functions run in ES5 Strict Mode
+ "trailing" : true, // true: Prohibit trailing whitespaces
+ "maxparams" : false, // {int} Max number of formal params allowed per function
+ "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
+ "maxstatements" : false, // {int} Max number statements per function
+ "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
+ "maxlen" : false, // {int} Max number of characters per line
+
+ // Relaxing
+ "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+ "boss" : false, // true: Tolerate assignments where comparisons would be expected
+ "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
+ "eqnull" : false, // true: Tolerate use of `== null`
+ "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
+ "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
+ "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+ // (ex: `for each`, multiple try/catch, function expression…)
+ "evil" : false, // true: Tolerate use of `eval` and `new Function()`
+ "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
+ "funcscope" : false, // true: Tolerate defining variables inside control statements"
+ "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
+ "iterator" : false, // true: Tolerate using the `__iterator__` property
+ "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+ "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
+ "laxcomma" : false, // true: Tolerate comma-first style coding
+ "loopfunc" : false, // true: Tolerate functions being defined in loops
+ "multistr" : false, // true: Tolerate multi-line strings
+ "proto" : false, // true: Tolerate using the `__proto__` property
+ "scripturl" : false, // true: Tolerate script-targeted URLs
+ "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
+ "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+ "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+ "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
+ "validthis" : false, // true: Tolerate using this in a non-constructor function
+
+ // Environments
+ "browser" : false, // Web Browser (window, document, etc)
+ "couch" : false, // CouchDB
+ "devel" : false, // Development/debugging (alert, confirm, etc)
+ "dojo" : false, // Dojo Toolkit
+ "jquery" : false, // jQuery
+ "mootools" : false, // MooTools
+ "node" : false, // Node.js
+ "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
+ "prototypejs" : false, // Prototype and Scriptaculous
+ "rhino" : false, // Rhino
+ "worker" : false, // Web Workers
+ "wsh" : false, // Windows Scripting Host
+ "yui" : false, // Yahoo User Interface
+
+ // Legacy
+ "nomen" : true, // true: Prohibit dangling `_` in variables
+ "onevar" : true, // true: Allow only one `var` statement per function
+ "passfail" : false, // true: Stop on first error
+ "white" : true, // true: Check against strict whitespace and indentation rules
+
+ // Custom Globals
+ "globals" : {} // additional predefined global variables
+}
diff --git a/library/blueimp_upload/.npmignore b/library/blueimp_upload/.npmignore
new file mode 100644
index 000000000..0530f5dbd
--- /dev/null
+++ b/library/blueimp_upload/.npmignore
@@ -0,0 +1,20 @@
+*
+!css/jquery.fileupload-noscript.css
+!css/jquery.fileupload-ui-noscript.css
+!css/jquery.fileupload-ui.css
+!css/jquery.fileupload.css
+!img/loading.gif
+!img/progressbar.gif
+!js/cors/jquery.postmessage-transport.js
+!js/cors/jquery.xdr-transport.js
+!js/vendor/jquery.ui.widget.js
+!js/jquery.fileupload-angular.js
+!js/jquery.fileupload-audio.js
+!js/jquery.fileupload-image.js
+!js/jquery.fileupload-jquery-ui.js
+!js/jquery.fileupload-process.js
+!js/jquery.fileupload-ui.js
+!js/jquery.fileupload-validate.js
+!js/jquery.fileupload-video.js
+!js/jquery.fileupload.js
+!js/jquery.iframe-transport.js
diff --git a/library/blueimp_upload/LICENSE b/library/blueimp_upload/LICENSE
deleted file mode 100644
index 0ecca3e8c..000000000
--- a/library/blueimp_upload/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017 jQuery-File-Upload Authors
-
-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.
diff --git a/library/blueimp_upload/LICENSE.txt b/library/blueimp_upload/LICENSE.txt
new file mode 100644
index 000000000..87a644638
--- /dev/null
+++ b/library/blueimp_upload/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright © 2010 Sebastian Tschan, https://blueimp.net
+
+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.
diff --git a/library/blueimp_upload/README.md b/library/blueimp_upload/README.md
index 56785b847..76bdf89d5 100644
--- a/library/blueimp_upload/README.md
+++ b/library/blueimp_upload/README.md
@@ -39,7 +39,7 @@ Supports cross-domain, chunked and resumable file uploads and client-side image
* **Multiple plugin instances:**
Allows to use multiple plugin instances on the same webpage.
* **Customizable and extensible:**
- Provides an API to set individual options and define callBack methods for various upload events.
+ Provides an API to set individual options and define callback methods for various upload events.
* **Multipart and file contents stream uploads:**
Files can be uploaded as standard "multipart/form-data" or file contents stream (HTTP PUT file upload).
* **Compatible with any server-side application platform:**
@@ -60,7 +60,7 @@ Supports cross-domain, chunked and resumable file uploads and client-side image
* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+
* [Glyphicons](http://glyphicons.com/)
-The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/).
+The user interface of all versions, except the jQuery UI version, is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/).
### Cross-domain requirements
[Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server.
diff --git a/library/blueimp_upload/angularjs.html b/library/blueimp_upload/angularjs.html
index 4858c8600..2051bbf79 100644
--- a/library/blueimp_upload/angularjs.html
+++ b/library/blueimp_upload/angularjs.html
@@ -22,11 +22,11 @@
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for AngularJS. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
-<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- blueimp Gallery styles -->
-<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<link rel="stylesheet" href="https://blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="css/jquery.fileupload.css">
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
@@ -79,7 +79,7 @@
</blockquote>
<br>
<!-- The file upload form used as target for the file upload widget -->
- <form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
+ <form id="fileupload" action="https://jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
<!-- Redirect browsers with JavaScript disabled to the origin page -->
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
@@ -177,18 +177,18 @@
<a class="play-pause"></a>
<ol class="indicator"></ol>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
-<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
-<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
-<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<script src="https://blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
diff --git a/library/blueimp_upload/basic-plus.html b/library/blueimp_upload/basic-plus.html
index 9e5c2321f..acee24843 100644
--- a/library/blueimp_upload/basic-plus.html
+++ b/library/blueimp_upload/basic-plus.html
@@ -20,7 +20,7 @@
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
-<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
@@ -96,15 +96,15 @@
</div>
</div>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
-<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
diff --git a/library/blueimp_upload/basic.html b/library/blueimp_upload/basic.html
index c0df639b4..232a24624 100644
--- a/library/blueimp_upload/basic.html
+++ b/library/blueimp_upload/basic.html
@@ -20,7 +20,7 @@
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support and progress bar for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
-<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
@@ -96,7 +96,7 @@
</div>
</div>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
@@ -104,7 +104,7 @@
<!-- The basic File Upload plugin -->
<script src="js/jquery.fileupload.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
-<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
/*jslint unparam: true */
/*global window, $ */
diff --git a/library/blueimp_upload/bower.json b/library/blueimp_upload/bower.json
index 90c74c792..4f4cd8adb 100644
--- a/library/blueimp_upload/bower.json
+++ b/library/blueimp_upload/bower.json
@@ -1,6 +1,6 @@
{
"name": "blueimp-file-upload",
- "version": "9.18.0",
+ "version": "9.23.0",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images.",
"keywords": [
@@ -53,8 +53,8 @@
"ignore": [
"/*.*",
"/cors",
- "css/demo-ie8.css",
- "css/demo.css",
+ "css/jquery-ui-demo-ie8.css",
+ "css/jquery-ui-demo.css",
"css/style.css",
"js/app.js",
"js/main.js",
diff --git a/library/blueimp_upload/cors/postmessage.html b/library/blueimp_upload/cors/postmessage.html
index 6db288cf9..6a56cf0b6 100644
--- a/library/blueimp_upload/cors/postmessage.html
+++ b/library/blueimp_upload/cors/postmessage.html
@@ -15,7 +15,7 @@
<head>
<meta charset="utf-8">
<title>jQuery File Upload Plugin postMessage API</title>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<script>
diff --git a/library/blueimp_upload/css/demo-ie8.css b/library/blueimp_upload/css/jquery-ui-demo-ie8.css
index e0e8ea9b0..e0e8ea9b0 100644
--- a/library/blueimp_upload/css/demo-ie8.css
+++ b/library/blueimp_upload/css/jquery-ui-demo-ie8.css
diff --git a/library/blueimp_upload/css/demo.css b/library/blueimp_upload/css/jquery-ui-demo.css
index d7d524df5..d7d524df5 100644
--- a/library/blueimp_upload/css/demo.css
+++ b/library/blueimp_upload/css/jquery-ui-demo.css
diff --git a/library/blueimp_upload/index.html b/library/blueimp_upload/index.html
index 2a8dc1521..c8c66ad8b 100644
--- a/library/blueimp_upload/index.html
+++ b/library/blueimp_upload/index.html
@@ -22,11 +22,11 @@
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
-<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- blueimp Gallery styles -->
-<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<link rel="stylesheet" href="https://blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="css/jquery.fileupload.css">
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
@@ -73,7 +73,7 @@
</blockquote>
<br>
<!-- The file upload form used as target for the file upload widget -->
- <form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
+ <form id="fileupload" action="https://jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
<!-- Redirect browsers with JavaScript disabled to the origin page -->
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
@@ -216,19 +216,19 @@
</tr>
{% } %}
</script>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
-<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
-<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
-<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<script src="https://blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
diff --git a/library/blueimp_upload/jquery-ui.html b/library/blueimp_upload/jquery-ui.html
index 83fe9acd1..842dd4ca7 100644
--- a/library/blueimp_upload/jquery-ui.html
+++ b/library/blueimp_upload/jquery-ui.html
@@ -22,11 +22,13 @@
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- jQuery UI styles -->
-<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/dark-hive/jquery-ui.css" id="theme">
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/dark-hive/jquery-ui.css" id="theme">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
<!-- Demo styles -->
-<link rel="stylesheet" href="css/demo.css">
+<link rel="stylesheet" href="css/jquery-ui-demo.css">
<!--[if lte IE 8]>
-<link rel="stylesheet" href="css/demo-ie8.css">
+<link rel="stylesheet" href="css/jquery-ui-demo-ie8.css">
<![endif]-->
<style>
/* Adjust the jQuery UI widget font-size: */
@@ -35,7 +37,7 @@
}
</style>
<!-- blueimp Gallery styles -->
-<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<link rel="stylesheet" href="https://blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="css/jquery.fileupload.css">
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
@@ -95,7 +97,7 @@
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
</blockquote>
<!-- The file upload form used as target for the file upload widget -->
-<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
+<form id="fileupload" action="https://jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
<!-- Redirect browsers with JavaScript disabled to the origin page -->
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
@@ -199,16 +201,16 @@
</tr>
{% } %}
</script>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
-<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
-<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
-<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- blueimp Gallery script -->
-<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<script src="https://blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
diff --git a/library/blueimp_upload/js/jquery.fileupload-angular.js b/library/blueimp_upload/js/jquery.fileupload-angular.js
index 1c2055276..185907d36 100644
--- a/library/blueimp_upload/js/jquery.fileupload-angular.js
+++ b/library/blueimp_upload/js/jquery.fileupload-angular.js
@@ -315,6 +315,7 @@
'fileuploadpaste',
'fileuploaddrop',
'fileuploaddragover',
+ 'fileuploadchunkbeforesend',
'fileuploadchunksend',
'fileuploadchunkdone',
'fileuploadchunkfail',
diff --git a/library/blueimp_upload/js/jquery.fileupload-ui.js b/library/blueimp_upload/js/jquery.fileupload-ui.js
index 83e7449e6..5058084b4 100644
--- a/library/blueimp_upload/js/jquery.fileupload-ui.js
+++ b/library/blueimp_upload/js/jquery.fileupload-ui.js
@@ -30,6 +30,7 @@
require('jquery'),
require('blueimp-tmpl'),
require('./jquery.fileupload-image'),
+ require('./jquery.fileupload-audio'),
require('./jquery.fileupload-video'),
require('./jquery.fileupload-validate')
);
diff --git a/library/blueimp_upload/js/jquery.fileupload.js b/library/blueimp_upload/js/jquery.fileupload.js
index 5ff151b53..700f9013c 100644
--- a/library/blueimp_upload/js/jquery.fileupload.js
+++ b/library/blueimp_upload/js/jquery.fileupload.js
@@ -43,7 +43,7 @@
'|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
).test(window.navigator.userAgent) ||
// Feature detection for all other devices:
- $('<input type="file">').prop('disabled'));
+ $('<input type="file"/>').prop('disabled'));
// The FileReader API is not actually used, but works as feature detection,
// as some Safari versions (5?) support XHR file uploads via the FormData API,
@@ -261,6 +261,9 @@
// Callback for dragover events of the dropZone(s):
// dragover: function (e) {}, // .bind('fileuploaddragover', func);
+ // Callback before the start of each chunk upload request (before form data initialization):
+ // chunkbeforesend: function (e, data) {}, // .bind('fileuploadchunkbeforesend', func);
+
// Callback for the start of each chunk upload request:
// chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
@@ -434,6 +437,13 @@
}
},
+ _deinitProgressListener: function (options) {
+ var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
+ if (xhr.upload) {
+ $(xhr.upload).unbind('progress');
+ }
+ },
+
_isInstanceOf: function (type, obj) {
// Cross-frame instanceof check
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
@@ -453,7 +463,7 @@
}
if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
options.headers['Content-Disposition'] = 'attachment; filename="' +
- encodeURI(file.name) + '"';
+ encodeURI(file.uploadName || file.name) + '"';
}
if (!multipart) {
options.contentType = file.type || 'application/octet-stream';
@@ -489,7 +499,11 @@
});
}
if (options.blob) {
- formData.append(paramName, options.blob, file.name);
+ formData.append(
+ paramName,
+ options.blob,
+ file.uploadName || file.name
+ );
} else {
$.each(options.files, function (index, file) {
// This check allows the tests to run with
@@ -730,7 +744,7 @@
promise = dfd.promise(),
jqXHR,
upload;
- if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
+ if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||
options.data) {
return false;
}
@@ -753,7 +767,7 @@
o.blob = slice.call(
file,
ub,
- ub + mcs,
+ ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
file.type
);
// Store the current chunk size, as the blob itself
@@ -762,6 +776,8 @@
// Expose the chunk bytes position range:
o.contentRange = 'bytes ' + ub + '-' +
(ub + o.chunkSize - 1) + '/' + fs;
+ // Trigger chunkbeforesend to allow form data to be updated for this chunk
+ that._trigger('chunkbeforesend', null, o);
// Process the upload data (the blob and potential form data):
that._initXHRData(o);
// Add progress listeners for this chunk upload:
@@ -808,6 +824,9 @@
o.context,
[jqXHR, textStatus, errorThrown]
);
+ })
+ .always(function () {
+ that._deinitProgressListener(o);
});
};
this._enhancePromise(promise);
@@ -909,6 +928,7 @@
}).fail(function (jqXHR, textStatus, errorThrown) {
that._onFail(jqXHR, textStatus, errorThrown, options);
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
+ that._deinitProgressListener(options);
that._onAlways(
jqXHRorResult,
textStatus,
@@ -1126,7 +1146,7 @@
dirReader = entry.createReader();
readEntries();
} else {
- // Return an empy list for file system items
+ // Return an empty list for file system items
// other than files or directories:
dfd.resolve([]);
}
diff --git a/library/blueimp_upload/js/vendor/jquery.ui.widget.js b/library/blueimp_upload/js/vendor/jquery.ui.widget.js
index e08df3fd0..914b8ffb8 100644
--- a/library/blueimp_upload/js/vendor/jquery.ui.widget.js
+++ b/library/blueimp_upload/js/vendor/jquery.ui.widget.js
@@ -1,571 +1,751 @@
-/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28
-* http://jqueryui.com
-* Includes: widget.js
-* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+/*! jQuery UI - v1.12.1+CommonJS - 2018-02-10
+ * http://jqueryui.com
+ * Includes: widget.js
+ * Copyright jQuery Foundation and other contributors; Licensed MIT */
(function( factory ) {
- if ( typeof define === "function" && define.amd ) {
+ if ( typeof define === "function" && define.amd ) {
- // AMD. Register as an anonymous module.
- define([ "jquery" ], factory );
+ // AMD. Register as an anonymous module.
+ define([ "jquery" ], factory );
+ } else if ( typeof exports === "object" ) {
- } else if ( typeof exports === "object" ) {
+ // Node/CommonJS
+ factory( require( "jquery" ) );
+ } else {
- // Node/CommonJS
- factory( require( "jquery" ) );
+ // Browser globals
+ factory( jQuery );
+ }
+}(function( $ ) {
- } else {
+ $.ui = $.ui || {};
+
+ var version = $.ui.version = "1.12.1";
+
+
+ /*!
+ * jQuery UI Widget 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+ //>>label: Widget
+ //>>group: Core
+ //>>description: Provides a factory for creating stateful widgets with a common API.
+ //>>docs: http://api.jqueryui.com/jQuery.widget/
+ //>>demos: http://jqueryui.com/widget/
+
+
+
+ var widgetUuid = 0;
+ var widgetSlice = Array.prototype.slice;
+
+ $.cleanData = ( function( orig ) {
+ return function( elems ) {
+ var events, elem, i;
+ for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
+ try {
+
+ // Only trigger remove when necessary to save time
+ events = $._data( elem, "events" );
+ if ( events && events.remove ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+
+ // Http://bugs.jquery.com/ticket/8235
+ } catch ( e ) {}
+ }
+ orig( elems );
+ };
+ } )( $.cleanData );
+
+ $.widget = function( name, base, prototype ) {
+ var existingConstructor, constructor, basePrototype;
+
+ // ProxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ var proxiedPrototype = {};
+
+ var namespace = name.split( "." )[ 0 ];
+ name = name.split( "." )[ 1 ];
+ var fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ if ( $.isArray( prototype ) ) {
+ prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
+ }
+
+ // Create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+
+ // Allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // Allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ // Extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+
+ // Copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+
+ // Track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ } );
+
+ basePrototype = new base();
+
+ // We need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = ( function() {
+ function _super() {
+ return base.prototype[ prop ].apply( this, arguments );
+ }
+
+ function _superApply( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ }
+
+ return function() {
+ var __super = this._super;
+ var __superApply = this._superApply;
+ var returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ } )();
+ } );
+ constructor.prototype = $.widget.extend( basePrototype, {
+
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ } );
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // Redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
+ child._proto );
+ } );
+
+ // Remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+
+ return constructor;
+ };
+
+ $.widget.extend = function( target ) {
+ var input = widgetSlice.call( arguments, 1 );
+ var inputIndex = 0;
+ var inputLength = input.length;
+ var key;
+ var value;
+
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+ };
+
+ $.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string";
+ var args = widgetSlice.call( arguments, 1 );
+ var returnValue = this;
+
+ if ( isMethodCall ) {
+
+ // If this is an empty collection, we need to have the instance method
+ // return undefined instead of the jQuery instance
+ if ( !this.length && options === "instance" ) {
+ returnValue = undefined;
+ } else {
+ this.each( function() {
+ var methodValue;
+ var instance = $.data( this, fullName );
+
+ if ( options === "instance" ) {
+ returnValue = instance;
+ return false;
+ }
+
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name +
+ " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+
+ if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name +
+ " widget instance" );
+ }
+
+ methodValue = instance[ options ].apply( instance, args );
+
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ } );
+ }
+ } else {
+
+ // Allow multiple hashes to be passed on init
+ if ( args.length ) {
+ options = $.widget.extend.apply( null, [ options ].concat( args ) );
+ }
+
+ this.each( function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} );
+ if ( instance._init ) {
+ instance._init();
+ }
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ } );
+ }
+
+ return returnValue;
+ };
+ };
+
+ $.Widget = function( /* options, element */ ) {};
+ $.Widget._childConstructors = [];
+
+ $.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+
+ options: {
+ classes: {},
+ disabled: false,
+
+ // Callbacks
+ create: null
+ },
+
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widgetUuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+ this.classesElementLookup = {};
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ } );
+ this.document = $( element.style ?
+
+ // Element within the document
+ element.ownerDocument :
+
+ // Element is window or document
+ element.document || element );
+ this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+
+ if ( this.options.disabled ) {
+ this._setOptionDisabled( this.options.disabled );
+ }
+
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+
+ _getCreateOptions: function() {
+ return {};
+ },
+
+ _getCreateEventData: $.noop,
+
+ _create: $.noop,
+
+ _init: $.noop,
+
+ destroy: function() {
+ var that = this;
+
+ this._destroy();
+ $.each( this.classesElementLookup, function( key, value ) {
+ that._removeClass( value, key );
+ } );
+
+ // We can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .off( this.eventNamespace )
+ .removeData( this.widgetFullName );
+ this.widget()
+ .off( this.eventNamespace )
+ .removeAttr( "aria-disabled" );
+
+ // Clean up events and states
+ this.bindings.off( this.eventNamespace );
+ },
+
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+ var parts;
+ var curOption;
+ var i;
+
+ if ( arguments.length === 0 ) {
+
+ // Don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+
+ // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "classes" ) {
+ this._setOptionClasses( value );
+ }
+
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this._setOptionDisabled( value );
+ }
+
+ return this;
+ },
+
+ _setOptionClasses: function( value ) {
+ var classKey, elements, currentElements;
+
+ for ( classKey in value ) {
+ currentElements = this.classesElementLookup[ classKey ];
+ if ( value[ classKey ] === this.options.classes[ classKey ] ||
+ !currentElements ||
+ !currentElements.length ) {
+ continue;
+ }
+
+ // We are doing this to create a new jQuery object because the _removeClass() call
+ // on the next line is going to destroy the reference to the current elements being
+ // tracked. We need to save a copy of this collection so that we can add the new classes
+ // below.
+ elements = $( currentElements.get() );
+ this._removeClass( currentElements, classKey );
+
+ // We don't use _addClass() here, because that uses this.options.classes
+ // for generating the string of classes. We want to use the value passed in from
+ // _setOption(), this is the new value of the classes option which was passed to
+ // _setOption(). We pass this value directly to _classes().
+ elements.addClass( this._classes( {
+ element: elements,
+ keys: classKey,
+ classes: value,
+ add: true
+ } ) );
+ }
+ },
+
+ _setOptionDisabled: function( value ) {
+ this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this._removeClass( this.hoverable, null, "ui-state-hover" );
+ this._removeClass( this.focusable, null, "ui-state-focus" );
+ }
+ },
+
+ enable: function() {
+ return this._setOptions( { disabled: false } );
+ },
+
+ disable: function() {
+ return this._setOptions( { disabled: true } );
+ },
+
+ _classes: function( options ) {
+ var full = [];
+ var that = this;
+
+ options = $.extend( {
+ element: this.element,
+ classes: this.options.classes || {}
+ }, options );
+
+ function processClassString( classes, checkOption ) {
+ var current, i;
+ for ( i = 0; i < classes.length; i++ ) {
+ current = that.classesElementLookup[ classes[ i ] ] || $();
+ if ( options.add ) {
+ current = $( $.unique( current.get().concat( options.element.get() ) ) );
+ } else {
+ current = $( current.not( options.element ).get() );
+ }
+ that.classesElementLookup[ classes[ i ] ] = current;
+ full.push( classes[ i ] );
+ if ( checkOption && options.classes[ classes[ i ] ] ) {
+ full.push( options.classes[ classes[ i ] ] );
+ }
+ }
+ }
+
+ this._on( options.element, {
+ "remove": "_untrackClassesElement"
+ } );
+
+ if ( options.keys ) {
+ processClassString( options.keys.match( /\S+/g ) || [], true );
+ }
+ if ( options.extra ) {
+ processClassString( options.extra.match( /\S+/g ) || [] );
+ }
+
+ return full.join( " " );
+ },
+
+ _untrackClassesElement: function( event ) {
+ var that = this;
+ $.each( that.classesElementLookup, function( key, value ) {
+ if ( $.inArray( event.target, value ) !== -1 ) {
+ that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
+ }
+ } );
+ },
+
+ _removeClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, false );
+ },
+
+ _addClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, true );
+ },
+
+ _toggleClass: function( element, keys, extra, add ) {
+ add = ( typeof add === "boolean" ) ? add : extra;
+ var shift = ( typeof element === "string" || element === null ),
+ options = {
+ extra: shift ? keys : extra,
+ keys: shift ? element : keys,
+ element: shift ? this.element : element,
+ add: add
+ };
+ options.element.toggleClass( this._classes( options ), add );
+ return this;
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement;
+ var instance = this;
+
+ // No suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // No element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+
+ // Allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // Copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ );
+ var eventName = match[ 1 ] + instance.eventNamespace;
+ var selector = match[ 2 ];
+
+ if ( selector ) {
+ delegateElement.on( eventName, selector, handlerProxy );
+ } else {
+ element.on( eventName, handlerProxy );
+ }
+ } );
+ },
+
+ _off: function( element, eventName ) {
+ eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.off( eventName ).off( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
+ }
+ } );
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
+ }
+ } );
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig;
+ var callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+
+ // The original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // Copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+ };
+
+ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+
+ var hasOptions;
+ var effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue( function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ } );
+ }
+ };
+ } );
+
+ var widget = $.widget;
- // Browser globals
- factory( jQuery );
- }
-}(function( $ ) {
-/*!
- * jQuery UI Widget 1.11.4
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/jQuery.widget/
- */
-
-
-var widget_uuid = 0,
- widget_slice = Array.prototype.slice;
-
-$.cleanData = (function( orig ) {
- return function( elems ) {
- var events, elem, i;
- for ( i = 0; (elem = elems[i]) != null; i++ ) {
- try {
-
- // Only trigger remove when necessary to save time
- events = $._data( elem, "events" );
- if ( events && events.remove ) {
- $( elem ).triggerHandler( "remove" );
- }
-
- // http://bugs.jquery.com/ticket/8235
- } catch ( e ) {}
- }
- orig( elems );
- };
-})( $.cleanData );
-
-$.widget = function( name, base, prototype ) {
- var fullName, existingConstructor, constructor, basePrototype,
- // proxiedPrototype allows the provided prototype to remain unmodified
- // so that it can be used as a mixin for multiple widgets (#8876)
- proxiedPrototype = {},
- namespace = name.split( "." )[ 0 ];
-
- name = name.split( "." )[ 1 ];
- fullName = namespace + "-" + name;
-
- if ( !prototype ) {
- prototype = base;
- base = $.Widget;
- }
-
- // create selector for plugin
- $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
- return !!$.data( elem, fullName );
- };
-
- $[ namespace ] = $[ namespace ] || {};
- existingConstructor = $[ namespace ][ name ];
- constructor = $[ namespace ][ name ] = function( options, element ) {
- // allow instantiation without "new" keyword
- if ( !this._createWidget ) {
- return new constructor( options, element );
- }
-
- // allow instantiation without initializing for simple inheritance
- // must use "new" keyword (the code above always passes args)
- if ( arguments.length ) {
- this._createWidget( options, element );
- }
- };
- // extend with the existing constructor to carry over any static properties
- $.extend( constructor, existingConstructor, {
- version: prototype.version,
- // copy the object used to create the prototype in case we need to
- // redefine the widget later
- _proto: $.extend( {}, prototype ),
- // track widgets that inherit from this widget in case this widget is
- // redefined after a widget inherits from it
- _childConstructors: []
- });
-
- basePrototype = new base();
- // we need to make the options hash a property directly on the new instance
- // otherwise we'll modify the options hash on the prototype that we're
- // inheriting from
- basePrototype.options = $.widget.extend( {}, basePrototype.options );
- $.each( prototype, function( prop, value ) {
- if ( !$.isFunction( value ) ) {
- proxiedPrototype[ prop ] = value;
- return;
- }
- proxiedPrototype[ prop ] = (function() {
- var _super = function() {
- return base.prototype[ prop ].apply( this, arguments );
- },
- _superApply = function( args ) {
- return base.prototype[ prop ].apply( this, args );
- };
- return function() {
- var __super = this._super,
- __superApply = this._superApply,
- returnValue;
-
- this._super = _super;
- this._superApply = _superApply;
-
- returnValue = value.apply( this, arguments );
-
- this._super = __super;
- this._superApply = __superApply;
-
- return returnValue;
- };
- })();
- });
- constructor.prototype = $.widget.extend( basePrototype, {
- // TODO: remove support for widgetEventPrefix
- // always use the name + a colon as the prefix, e.g., draggable:start
- // don't prefix for widgets that aren't DOM-based
- widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
- }, proxiedPrototype, {
- constructor: constructor,
- namespace: namespace,
- widgetName: name,
- widgetFullName: fullName
- });
-
- // If this widget is being redefined then we need to find all widgets that
- // are inheriting from it and redefine all of them so that they inherit from
- // the new version of this widget. We're essentially trying to replace one
- // level in the prototype chain.
- if ( existingConstructor ) {
- $.each( existingConstructor._childConstructors, function( i, child ) {
- var childPrototype = child.prototype;
-
- // redefine the child widget using the same prototype that was
- // originally used, but inherit from the new version of the base
- $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
- });
- // remove the list of existing child constructors from the old constructor
- // so the old child constructors can be garbage collected
- delete existingConstructor._childConstructors;
- } else {
- base._childConstructors.push( constructor );
- }
-
- $.widget.bridge( name, constructor );
-
- return constructor;
-};
-
-$.widget.extend = function( target ) {
- var input = widget_slice.call( arguments, 1 ),
- inputIndex = 0,
- inputLength = input.length,
- key,
- value;
- for ( ; inputIndex < inputLength; inputIndex++ ) {
- for ( key in input[ inputIndex ] ) {
- value = input[ inputIndex ][ key ];
- if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
- // Clone objects
- if ( $.isPlainObject( value ) ) {
- target[ key ] = $.isPlainObject( target[ key ] ) ?
- $.widget.extend( {}, target[ key ], value ) :
- // Don't extend strings, arrays, etc. with objects
- $.widget.extend( {}, value );
- // Copy everything else by reference
- } else {
- target[ key ] = value;
- }
- }
- }
- }
- return target;
-};
-
-$.widget.bridge = function( name, object ) {
- var fullName = object.prototype.widgetFullName || name;
- $.fn[ name ] = function( options ) {
- var isMethodCall = typeof options === "string",
- args = widget_slice.call( arguments, 1 ),
- returnValue = this;
-
- if ( isMethodCall ) {
- this.each(function() {
- var methodValue,
- instance = $.data( this, fullName );
- if ( options === "instance" ) {
- returnValue = instance;
- return false;
- }
- if ( !instance ) {
- return $.error( "cannot call methods on " + name + " prior to initialization; " +
- "attempted to call method '" + options + "'" );
- }
- if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
- return $.error( "no such method '" + options + "' for " + name + " widget instance" );
- }
- methodValue = instance[ options ].apply( instance, args );
- if ( methodValue !== instance && methodValue !== undefined ) {
- returnValue = methodValue && methodValue.jquery ?
- returnValue.pushStack( methodValue.get() ) :
- methodValue;
- return false;
- }
- });
- } else {
-
- // Allow multiple hashes to be passed on init
- if ( args.length ) {
- options = $.widget.extend.apply( null, [ options ].concat(args) );
- }
-
- this.each(function() {
- var instance = $.data( this, fullName );
- if ( instance ) {
- instance.option( options || {} );
- if ( instance._init ) {
- instance._init();
- }
- } else {
- $.data( this, fullName, new object( options, this ) );
- }
- });
- }
-
- return returnValue;
- };
-};
-
-$.Widget = function( /* options, element */ ) {};
-$.Widget._childConstructors = [];
-
-$.Widget.prototype = {
- widgetName: "widget",
- widgetEventPrefix: "",
- defaultElement: "<div>",
- options: {
- disabled: false,
-
- // callbacks
- create: null
- },
- _createWidget: function( options, element ) {
- element = $( element || this.defaultElement || this )[ 0 ];
- this.element = $( element );
- this.uuid = widget_uuid++;
- this.eventNamespace = "." + this.widgetName + this.uuid;
-
- this.bindings = $();
- this.hoverable = $();
- this.focusable = $();
-
- if ( element !== this ) {
- $.data( element, this.widgetFullName, this );
- this._on( true, this.element, {
- remove: function( event ) {
- if ( event.target === element ) {
- this.destroy();
- }
- }
- });
- this.document = $( element.style ?
- // element within the document
- element.ownerDocument :
- // element is window or document
- element.document || element );
- this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
- }
-
- this.options = $.widget.extend( {},
- this.options,
- this._getCreateOptions(),
- options );
-
- this._create();
- this._trigger( "create", null, this._getCreateEventData() );
- this._init();
- },
- _getCreateOptions: $.noop,
- _getCreateEventData: $.noop,
- _create: $.noop,
- _init: $.noop,
-
- destroy: function() {
- this._destroy();
- // we can probably remove the unbind calls in 2.0
- // all event bindings should go through this._on()
- this.element
- .unbind( this.eventNamespace )
- .removeData( this.widgetFullName )
- // support: jquery <1.6.3
- // http://bugs.jquery.com/ticket/9413
- .removeData( $.camelCase( this.widgetFullName ) );
- this.widget()
- .unbind( this.eventNamespace )
- .removeAttr( "aria-disabled" )
- .removeClass(
- this.widgetFullName + "-disabled " +
- "ui-state-disabled" );
-
- // clean up events and states
- this.bindings.unbind( this.eventNamespace );
- this.hoverable.removeClass( "ui-state-hover" );
- this.focusable.removeClass( "ui-state-focus" );
- },
- _destroy: $.noop,
-
- widget: function() {
- return this.element;
- },
-
- option: function( key, value ) {
- var options = key,
- parts,
- curOption,
- i;
-
- if ( arguments.length === 0 ) {
- // don't return a reference to the internal hash
- return $.widget.extend( {}, this.options );
- }
-
- if ( typeof key === "string" ) {
- // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
- options = {};
- parts = key.split( "." );
- key = parts.shift();
- if ( parts.length ) {
- curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
- for ( i = 0; i < parts.length - 1; i++ ) {
- curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
- curOption = curOption[ parts[ i ] ];
- }
- key = parts.pop();
- if ( arguments.length === 1 ) {
- return curOption[ key ] === undefined ? null : curOption[ key ];
- }
- curOption[ key ] = value;
- } else {
- if ( arguments.length === 1 ) {
- return this.options[ key ] === undefined ? null : this.options[ key ];
- }
- options[ key ] = value;
- }
- }
-
- this._setOptions( options );
-
- return this;
- },
- _setOptions: function( options ) {
- var key;
-
- for ( key in options ) {
- this._setOption( key, options[ key ] );
- }
-
- return this;
- },
- _setOption: function( key, value ) {
- this.options[ key ] = value;
-
- if ( key === "disabled" ) {
- this.widget()
- .toggleClass( this.widgetFullName + "-disabled", !!value );
-
- // If the widget is becoming disabled, then nothing is interactive
- if ( value ) {
- this.hoverable.removeClass( "ui-state-hover" );
- this.focusable.removeClass( "ui-state-focus" );
- }
- }
-
- return this;
- },
-
- enable: function() {
- return this._setOptions({ disabled: false });
- },
- disable: function() {
- return this._setOptions({ disabled: true });
- },
-
- _on: function( suppressDisabledCheck, element, handlers ) {
- var delegateElement,
- instance = this;
-
- // no suppressDisabledCheck flag, shuffle arguments
- if ( typeof suppressDisabledCheck !== "boolean" ) {
- handlers = element;
- element = suppressDisabledCheck;
- suppressDisabledCheck = false;
- }
-
- // no element argument, shuffle and use this.element
- if ( !handlers ) {
- handlers = element;
- element = this.element;
- delegateElement = this.widget();
- } else {
- element = delegateElement = $( element );
- this.bindings = this.bindings.add( element );
- }
-
- $.each( handlers, function( event, handler ) {
- function handlerProxy() {
- // allow widgets to customize the disabled handling
- // - disabled as an array instead of boolean
- // - disabled class as method for disabling individual parts
- if ( !suppressDisabledCheck &&
- ( instance.options.disabled === true ||
- $( this ).hasClass( "ui-state-disabled" ) ) ) {
- return;
- }
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
-
- // copy the guid so direct unbinding works
- if ( typeof handler !== "string" ) {
- handlerProxy.guid = handler.guid =
- handler.guid || handlerProxy.guid || $.guid++;
- }
-
- var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
- eventName = match[1] + instance.eventNamespace,
- selector = match[2];
- if ( selector ) {
- delegateElement.delegate( selector, eventName, handlerProxy );
- } else {
- element.bind( eventName, handlerProxy );
- }
- });
- },
-
- _off: function( element, eventName ) {
- eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
- this.eventNamespace;
- element.unbind( eventName ).undelegate( eventName );
-
- // Clear the stack to avoid memory leaks (#10056)
- this.bindings = $( this.bindings.not( element ).get() );
- this.focusable = $( this.focusable.not( element ).get() );
- this.hoverable = $( this.hoverable.not( element ).get() );
- },
-
- _delay: function( handler, delay ) {
- function handlerProxy() {
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
- var instance = this;
- return setTimeout( handlerProxy, delay || 0 );
- },
-
- _hoverable: function( element ) {
- this.hoverable = this.hoverable.add( element );
- this._on( element, {
- mouseenter: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-hover" );
- },
- mouseleave: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-hover" );
- }
- });
- },
-
- _focusable: function( element ) {
- this.focusable = this.focusable.add( element );
- this._on( element, {
- focusin: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-focus" );
- },
- focusout: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-focus" );
- }
- });
- },
-
- _trigger: function( type, event, data ) {
- var prop, orig,
- callback = this.options[ type ];
-
- data = data || {};
- event = $.Event( event );
- event.type = ( type === this.widgetEventPrefix ?
- type :
- this.widgetEventPrefix + type ).toLowerCase();
- // the original event may come from any element
- // so we need to reset the target on the new event
- event.target = this.element[ 0 ];
-
- // copy original event properties over to the new event
- orig = event.originalEvent;
- if ( orig ) {
- for ( prop in orig ) {
- if ( !( prop in event ) ) {
- event[ prop ] = orig[ prop ];
- }
- }
- }
-
- this.element.trigger( event, data );
- return !( $.isFunction( callback ) &&
- callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
- event.isDefaultPrevented() );
- }
-};
-
-$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
- $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
- if ( typeof options === "string" ) {
- options = { effect: options };
- }
- var hasOptions,
- effectName = !options ?
- method :
- options === true || typeof options === "number" ?
- defaultEffect :
- options.effect || defaultEffect;
- options = options || {};
- if ( typeof options === "number" ) {
- options = { duration: options };
- }
- hasOptions = !$.isEmptyObject( options );
- options.complete = callback;
- if ( options.delay ) {
- element.delay( options.delay );
- }
- if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
- element[ method ]( options );
- } else if ( effectName !== method && element[ effectName ] ) {
- element[ effectName ]( options.duration, options.easing, callback );
- } else {
- element.queue(function( next ) {
- $( this )[ method ]();
- if ( callback ) {
- callback.call( element[ 0 ] );
- }
- next();
- });
- }
- };
-});
-
-var widget = $.widget;
diff --git a/library/blueimp_upload/package.json b/library/blueimp_upload/package.json
index ed4d33681..4801d7913 100644
--- a/library/blueimp_upload/package.json
+++ b/library/blueimp_upload/package.json
@@ -1,6 +1,6 @@
{
"name": "blueimp-file-upload",
- "version": "9.18.0",
+ "version": "9.23.0",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
"keywords": [
diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile
index ca88d3d0d..8633fee74 100644
--- a/library/blueimp_upload/server/php/Dockerfile
+++ b/library/blueimp_upload/server/php/Dockerfile
@@ -1,4 +1,4 @@
-FROM php:7.0-apache
+FROM php:7-apache
# Enable the Apache Headers module:
RUN ln -s /etc/apache2/mods-available/headers.load \
diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php
index 1380d4739..285d046aa 100755
--- a/library/blueimp_upload/server/php/UploadHandler.php
+++ b/library/blueimp_upload/server/php/UploadHandler.php
@@ -131,18 +131,22 @@ class UploadHandler
// Command or path for to the ImageMagick identify binary:
'identify_bin' => 'identify',
'image_versions' => array(
- // The empty image version key defines options for the original image:
+ // The empty image version key defines options for the original image.
+ // Keep in mind: these image manipulations are inherited by all other image versions from this point onwards.
+ // Also note that the property 'no_cache' is not inherited, since it's not a manipulation.
'' => array(
// Automatically rotate images based on EXIF meta data:
'auto_orient' => true
),
- // Uncomment the following to create medium sized images:
+ // You can add arrays to generate different versions.
+ // The name of the key is the name of the version (example: 'medium').
+ // the array contains the options to apply.
/*
'medium' => array(
'max_width' => 800,
'max_height' => 600
),
- */
+ */
'thumbnail' => array(
// Uncomment the following to use a defined directory for the thumbnails
// instead of a subdirectory based on the version identifier.
@@ -153,9 +157,13 @@ class UploadHandler
//'upload_url' => $this->get_full_url().'/thumb/',
// Uncomment the following to force the max
// dimensions and e.g. create square thumbnails:
- //'crop' => true,
- 'max_width' => 80,
- 'max_height' => 80
+ // 'auto_orient' => true,
+ // 'crop' => true,
+ // 'jpeg_quality' => 70,
+ // 'no_cache' => true, (there's a caching option, but this remembers thumbnail sizes from a previous action!)
+ // 'strip' => true, (this strips EXIF tags, such as geolocation)
+ 'max_width' => 80, // either specify width, or set to 0. Then width is automatically adjusted - keeping aspect ratio to a specified max_height.
+ 'max_height' => 80 // either specify height, or set to 0. Then height is automatically adjusted - keeping aspect ratio to a specified max_width.
)
),
'print_response' => true
@@ -862,22 +870,32 @@ class UploadHandler
$image_oriented = false;
if (!empty($options['auto_orient'])) {
$image_oriented = $this->imagick_orient_image($image);
- }
+ }
+
+ $image_resize = false;
$new_width = $max_width = $img_width = $image->getImageWidth();
- $new_height = $max_height = $img_height = $image->getImageHeight();
- if (!empty($options['max_width'])) {
- $new_width = $max_width = $options['max_width'];
- }
- if (!empty($options['max_height'])) {
+ $new_height = $max_height = $img_height = $image->getImageHeight();
+
+ // use isset(). User might be setting max_width = 0 (auto in regular resizing). Value 0 would be considered empty when you use empty()
+ if (isset($options['max_width'])) {
+ $image_resize = true;
+ $new_width = $max_width = $options['max_width'];
+ }
+ if (isset($options['max_height'])) {
+ $image_resize = true;
$new_height = $max_height = $options['max_height'];
}
- if (!($image_oriented || $max_width < $img_width || $max_height < $img_height)) {
+
+ $image_strip = (isset($options['strip']) ? $options['strip'] : false);
+
+ if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) {
if ($file_path !== $new_file_path) {
return copy($file_path, $new_file_path);
}
return true;
}
- $crop = !empty($options['crop']);
+ $crop = (isset($options['crop']) ? $options['crop'] : false);
+
if ($crop) {
$x = 0;
$y = 0;
@@ -917,7 +935,7 @@ class UploadHandler
}
break;
}
- if (!empty($options['strip'])) {
+ if ( $image_strip ) {
$image->stripImage();
}
return $success && $image->writeImage($new_file_path);
diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml
index 691ea9caa..74eabf7dc 100644
--- a/library/blueimp_upload/server/php/docker-compose.yml
+++ b/library/blueimp_upload/server/php/docker-compose.yml
@@ -1,6 +1,9 @@
-apache:
- build: ./
- ports:
- - "80:80"
- volumes:
- - "../../:/var/www/html"
+version: '2.3'
+services:
+ apache:
+ build: ./
+ network_mode: bridge
+ ports:
+ - "80:80"
+ volumes:
+ - "../../:/var/www/html"
diff --git a/library/blueimp_upload/test/index.html b/library/blueimp_upload/test/index.html
index 4a9a6f328..0b5cf57b7 100644
--- a/library/blueimp_upload/test/index.html
+++ b/library/blueimp_upload/test/index.html
@@ -20,7 +20,7 @@
<meta charset="utf-8">
<title>jQuery File Upload Plugin Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css">
+<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-1.23.1.css">
</head>
<body>
<h1 id="qunit-header">jQuery File Upload Plugin Test</h1>
@@ -145,11 +145,11 @@
</tr>
{% } %}
</script>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="../js/vendor/jquery.ui.widget.js"></script>
-<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
-<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
-<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<script src="../js/jquery.iframe-transport.js"></script>
<script src="../js/jquery.fileupload.js"></script>
<script>
@@ -166,7 +166,7 @@ window.testBasicWidget = $.blueimp.fileupload;
/* global window, $ */
window.testUIWidget = $.blueimp.fileupload;
</script>
-<script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script>
+<script src="https://code.jquery.com/qunit/qunit-1.23.1.js"></script>
<script src="test.js"></script>
</body>
</html>
diff --git a/view/js/autocomplete.js b/view/js/autocomplete.js
index 54eb03e13..6b77f0631 100644
--- a/view/js/autocomplete.js
+++ b/view/js/autocomplete.js
@@ -163,7 +163,7 @@ function string2bb(element) {
// Autocomplete contacts
contacts = {
- match: /(^|\s)(@\!*)([^ \n]{2,})$/,
+ match: /(^|\s)(@\!*)([^ \n]{3,})$/,
index: 3,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, 'c', extra_channels, spinelement=false); },
@@ -195,12 +195,12 @@ function string2bb(element) {
smilies = {
- match: /(^|\s)(:[a-z_:]{2,})$/,
+ match: /(^|\s)(:[a-z0-9_:]{2,})$/,
index: 2,
cache: true,
- search: function(term, callback) { $.getJSON('/smilies/json').done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term) === 0 ? entry : null; })); }); },
- //template: function(item) { return item.icon + item.text; },
+ search: function(term, callback) { $.getJSON('/smilies/json').done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term.substr(1)) !== -1 ? entry : null; })); }); },
replace: function(item) { return "$1" + item.text + ' '; },
+ context: function(text) { return text.toLowerCase(); },
template: smiley_format
};
this.attr('autocomplete','off');
@@ -209,8 +209,12 @@ function string2bb(element) {
$(this).each(function() {
var editor = new Textarea(this);
- var textcomplete = new Textcomplete(editor);
- textcomplete.register([contacts,forums,smilies,tags], {className:'acpopup', zIndex:1020});
+ var textcomplete = new Textcomplete(editor, {
+ dropdown: {
+ maxCount: 100
+ }
+ });
+ textcomplete.register([contacts,forums,smilies,tags]);
});
@@ -264,8 +268,12 @@ function string2bb(element) {
$(this).each(function() {
var editor = new Textarea(this);
- textcomplete = new Textcomplete(editor);
- textcomplete.register([contacts,forums,tags], {className:'acpopup', maxCount:100, zIndex: 1020, appendTo:'nav'});
+ textcomplete = new Textcomplete(editor, {
+ dropdown: {
+ maxCount: 100
+ }
+ });
+ textcomplete.register([contacts,forums,tags]);
});
textcomplete.on('selected', function() { this.editor.el.form.submit(); });
@@ -299,8 +307,12 @@ function string2bb(element) {
$(this).each(function() {
var editor = new Textarea(this);
- textcomplete = new Textcomplete(editor);
- textcomplete.register([contacts], {className:'acpopup', zIndex:1020});
+ textcomplete = new Textcomplete(editor, {
+ dropdown: {
+ maxCount: 100
+ }
+ });
+ textcomplete.register([contacts]);
});
if(autosubmit)
@@ -338,8 +350,12 @@ function string2bb(element) {
$(this).each(function() {
var editor = new Textarea(this);
- textcomplete = new Textcomplete(editor);
- textcomplete.register([names], {className:'acpopup', zIndex:1020});
+ textcomplete = new Textcomplete(editor, {
+ dropdown: {
+ maxCount: 100
+ }
+ });
+ textcomplete.register([names]);
});
if(autosubmit)
@@ -358,8 +374,8 @@ function string2bb(element) {
return;
if(type=='bbcode') {
- var open_close_elements = ['bold', 'italic', 'underline', 'overline', 'strike', 'superscript', 'subscript', 'quote', 'code', 'open', 'spoiler', 'map', 'nobb', 'list', 'checklist', 'ul', 'ol', 'dl', 'li', 'table', 'tr', 'th', 'td', 'center', 'color', 'font', 'size', 'zrl', 'zmg', 'rpost', 'qr', 'observer', 'observer.language','embed', 'highlight', 'url', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
- var open_elements = ['observer.baseurl', 'observer.address', 'observer.photo', 'observer.name', 'observer.webname', 'observer.url', '*', 'hr', ];
+ var open_close_elements = ['bold', 'italic', 'underline', 'overline', 'strike', 'superscript', 'subscript', 'quote', 'code', 'open', 'spoiler', 'summary', 'map', 'nobb', 'list', 'checklist', 'ul', 'ol', 'dl', 'li', 'table', 'tr', 'th', 'td', 'center', 'color', 'font', 'size', 'zrl', 'zmg', 'rpost', 'qr', 'observer', 'observer.language','embed', 'highlight', 'url', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+ var open_elements = ['observer.baseurl', 'observer.address', 'observer.photo', 'observer.name', 'observer.webname', 'observer.url', '*', 'hr' ];
var elements = open_close_elements.concat(open_elements);
}
@@ -420,7 +436,7 @@ function string2bb(element) {
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
- textcomplete.register([bbco], {className:'acpopup', zIndex:1020});
+ textcomplete.register([bbco]);
});
this.keypress(function(e){
diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css
index 4f0658477..489d71735 100644
--- a/view/theme/redbasic/css/style.css
+++ b/view/theme/redbasic/css/style.css
@@ -1474,6 +1474,12 @@ blockquote {
background-color: $item_colour;
}
+.textcomplete-dropdown {
+ max-height: 300px;
+ max-width: 250px;
+ overflow: auto;
+}
+
.dropdown-item.active {
color: #fff;
background-color: #007bff;
diff --git a/view/tpl/build_query.tpl b/view/tpl/build_query.tpl
index 2c55a8140..fcb22b605 100755
--- a/view/tpl/build_query.tpl
+++ b/view/tpl/build_query.tpl
@@ -31,6 +31,7 @@
var bParam_verb = "{{$verb}}";
var bParam_net = "{{$net}}";
var bParam_pf = "{{$pf}}";
+ var bParam_unseen = "{{$unseen}}";
function buildCmd() {
var udargs = ((page_load) ? "/load" : "");
@@ -62,6 +63,7 @@
if(bParam_net != "") bCmd = bCmd + "&net=" + bParam_net;
if(bParam_page != 1) bCmd = bCmd + "&page=" + bParam_page;
if(bParam_pf != 0) bCmd = bCmd + "&pf=" + bParam_pf;
+ if(bParam_unseen != 0) bCmd = bCmd + "&unseen=" + bParam_unseen;
return(bCmd);
}
diff --git a/view/tpl/notifications_widget.tpl b/view/tpl/notifications_widget.tpl
index 9b3d7487e..f43d82301 100644
--- a/view/tpl/notifications_widget.tpl
+++ b/view/tpl/notifications_widget.tpl
@@ -143,7 +143,7 @@
<div id="nav-notifications-forums-template" rel="template">
<a class="list-group-item clearfix notification notification-forum" href="{0}" title="{3}" data-b64mid="{6}" data-notify_id="{7}" data-thread_top="{8}" data-contact_name="{2}">
<span class="float-right badge badge-{{$notification.severity}}">{9}</span>
- <img class="menu-img-1" src="{1}">
+ <img class="menu-img-1" data-src="{1}">
<span class="">{2}</span>
<i class="fa fa-{10} text-muted"></i>
</a>