diff options
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'; } @@ -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&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&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&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&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&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&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> |