Rebuild File Manager's non-Bootstrap interface on the core widgets
@@ -11,7 +11,7 @@ eval "use File::MimeInfo";
|
||||
|
||||
our ($path, $quote_escaped_path, $urlized_path, $base, $cwd, $upload_max,
|
||||
$confdir, $template_name, $bookmarks, $page, $pagelimit, $edit_icon,
|
||||
$rename_icon, $extract_icon, $goto_icon, $root_icon, $head);
|
||||
$rename_icon, $extract_icon, $goto_icon, $root_icon);
|
||||
our (%access, %userconfig, %allowed_for_edit);
|
||||
our (@allowed_paths, @allowed_for_edit, @remote_user_info);
|
||||
|
||||
@@ -413,124 +413,9 @@ if ($tinfo{'bootstrap'}) {
|
||||
"unauthenticated/templates/dialogs.html");
|
||||
}
|
||||
|
||||
# Interface for legacy themes
|
||||
# Interface for other themes, built from the core widgets
|
||||
else {
|
||||
|
||||
# Set icons variables
|
||||
$edit_icon =
|
||||
"<img src='images/icons/quick/edit.png'" .
|
||||
" alt='$text{'edit'}' />";
|
||||
$rename_icon =
|
||||
"<img src='images/icons/quick/" .
|
||||
"rename.png' " .
|
||||
"alt='$text{'rename'}' />";
|
||||
$extract_icon =
|
||||
"<img src='images/icons/quick/" .
|
||||
"extract.png' " .
|
||||
"alt='$text{'extract_archive'}' />";
|
||||
$goto_icon =
|
||||
"<img src='images/icons/quick/" .
|
||||
"go-next.png' " .
|
||||
"alt='$text{'goto_folder'}'";
|
||||
|
||||
# Add static files
|
||||
$head = "<link rel=\"stylesheet\" " .
|
||||
"type=\"text/css\" " .
|
||||
"href=\"unauthenticated/css/" .
|
||||
"style.css\" />";
|
||||
$head .= "<script type=\"text/javascript\"" .
|
||||
" src=\"unauthenticated/jquery/" .
|
||||
"jquery.min.js\"></script>";
|
||||
$head .= "<script type=\"text/javascript\"" .
|
||||
" src=\"unauthenticated/jquery/" .
|
||||
"jquery-ui.min.js\"></script>";
|
||||
$head .= "<script type=\"text/javascript\"" .
|
||||
" src=\"unauthenticated/js/" .
|
||||
"legacy.js\"></script>";
|
||||
$head .= "<link rel=\"stylesheet\" " .
|
||||
"type=\"text/css\" " .
|
||||
"href=\"unauthenticated/jquery/" .
|
||||
"jquery-ui.min.css\" />";
|
||||
$head .= "<script type=\"text/javascript\"" .
|
||||
" src=\"unauthenticated/js/" .
|
||||
"chmod-calculator.js\"></script>";
|
||||
$head .= "<link rel=\"stylesheet\" " .
|
||||
"type=\"text/css\" " .
|
||||
"href=\"unauthenticated/dropdown/" .
|
||||
"fg.menu.css\" />";
|
||||
$head .= "<script type=\"text/javascript\"" .
|
||||
" src=\"unauthenticated/dropdown/" .
|
||||
"fg.menu.js\"></script>";
|
||||
print $head;
|
||||
|
||||
# Set "root" icon
|
||||
if ($base eq '/') {
|
||||
$root_icon =
|
||||
"<img src=\"images/icons/quick/" .
|
||||
"drive-harddisk.png\" " .
|
||||
"class=\"hdd-icon\" />";
|
||||
}
|
||||
else {
|
||||
$root_icon = "~";
|
||||
}
|
||||
# Legacy breadcrumbs
|
||||
print "<div id='bread' style='float: left;" .
|
||||
" padding-bottom: 2px;'>" .
|
||||
"<a href='index.cgi?path='>" .
|
||||
"$root_icon</a> / ";
|
||||
my @breadcr = split('/', $path);
|
||||
my $cp = '';
|
||||
for (my $i = 1;
|
||||
$i <= scalar(@breadcr)-1; $i++) {
|
||||
chomp($breadcr[$i]);
|
||||
$cp = $cp.'/'.$breadcr[$i];
|
||||
print "<a href='index.cgi?path=" .
|
||||
&urlize($cp) . "'>" .
|
||||
&html_escape($breadcr[$i]) .
|
||||
"</a> / ";
|
||||
}
|
||||
print "<br />";
|
||||
# And pagination
|
||||
$page = $in{'page'};
|
||||
$pagelimit = $userconfig{'per_page'};
|
||||
$pages = ceil((scalar(@list))/$pagelimit);
|
||||
if (not defined $page or $page > $pages) {
|
||||
$page = 1;
|
||||
}
|
||||
print "Pages: ";
|
||||
for (my $i = 1; $i <= $pages; $i++) {
|
||||
if ($page eq $i) {
|
||||
print "<a class='pages active' " .
|
||||
"href='?path=" .
|
||||
&urlize($path) .
|
||||
"&page=$i" .
|
||||
"&query=" .
|
||||
&urlize($query) .
|
||||
"'>" .
|
||||
&html_escape($i) .
|
||||
"</a>";
|
||||
}
|
||||
else {
|
||||
print "<a class='pages' " .
|
||||
"href='?path=" .
|
||||
&urlize($path) .
|
||||
"&page=$i" .
|
||||
"&query=" .
|
||||
&urlize($query) .
|
||||
"'>" .
|
||||
&html_escape($i) .
|
||||
"</a>";
|
||||
}
|
||||
}
|
||||
print "</div>";
|
||||
|
||||
# And toolbar
|
||||
print_template(
|
||||
"unauthenticated/templates/" .
|
||||
"legacy_quicks.html");
|
||||
print_template(
|
||||
"unauthenticated/templates/" .
|
||||
"legacy_dialogs.html");
|
||||
print &plain_interface_head();
|
||||
}
|
||||
my $info_total;
|
||||
my $info_files = scalar @files;
|
||||
@@ -801,6 +686,18 @@ for (my $count = 1 + $pagelimit * ($page - 1);
|
||||
print ui_columns_end();
|
||||
print &ui_hidden("path", $path),"\n";
|
||||
print &ui_form_end();
|
||||
# Close the widget page area opened by the non-Bootstrap interface
|
||||
print &ui_page_end() if (!$tinfo{'bootstrap'});
|
||||
}
|
||||
|
||||
# list_bookmarks()
|
||||
# Returns the directories the user has bookmarked
|
||||
sub list_bookmarks
|
||||
{
|
||||
$confdir = "$remote_user_info[7]/.filemin";
|
||||
return () if (!-e "$confdir/.bookmarks");
|
||||
my $bookmarks = &read_file_lines($confdir.'/.bookmarks', 1);
|
||||
return grep { $_ ne '' } @$bookmarks;
|
||||
}
|
||||
|
||||
# get_bookmarks()
|
||||
@@ -811,10 +708,8 @@ $confdir = "$remote_user_info[7]/.filemin";
|
||||
if (!-e "$confdir/.bookmarks") {
|
||||
return "<li><a>$text{'no_bookmarks'}</a></li>";
|
||||
}
|
||||
my $bookmarks =
|
||||
&read_file_lines($confdir.'/.bookmarks', 1);
|
||||
$result = '';
|
||||
foreach $bookmark (@$bookmarks) {
|
||||
foreach $bookmark (&list_bookmarks()) {
|
||||
$result .=
|
||||
"<li><a href='index.cgi?path=" .
|
||||
&urlize($bookmark) . "'>" .
|
||||
@@ -824,6 +719,486 @@ foreach $bookmark (@$bookmarks) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
# plain_interface_head()
|
||||
# Returns the top of the file list for themes without Bootstrap : the
|
||||
# module assets, the breadcrumbs, the toolbar of menus and buttons, the
|
||||
# page links and the dialogs behind the toolbar, all built from the core
|
||||
# widgets. Also sets the row action icons and the pagination that the
|
||||
# shared listing code uses, and opens the widget page area that
|
||||
# print_interface closes after the listing.
|
||||
sub plain_interface_head
|
||||
{
|
||||
my $rv = "";
|
||||
|
||||
# Row action icons from the built-in icon set
|
||||
$edit_icon = &ui_svg_icon('edit', { 'title' => $text{'edit'} });
|
||||
$rename_icon = &ui_svg_icon('cursor-text', { 'title' => $text{'rename'} });
|
||||
$extract_icon = &ui_svg_icon('unarchive',
|
||||
{ 'title' => $text{'extract_archive'} });
|
||||
$goto_icon = &ui_svg_icon('arrow-right', { 'title' => $text{'goto_folder'} });
|
||||
|
||||
# Server-side pagination, with as many entries per page as the user chose
|
||||
$page = int($in{'page'} || 0) || 1;
|
||||
$pagelimit = int($userconfig{'per_page'} || 0) || 50;
|
||||
$pages = ceil(scalar(@list) / $pagelimit) || 1;
|
||||
$page = 1 if ($page > $pages);
|
||||
|
||||
# The widget page area, with the module's own stylesheet and script
|
||||
$rv .= &ui_page_start({ 'class' => 'filemin_page' });
|
||||
$rv .= &plain_asset_tags();
|
||||
|
||||
# Breadcrumbs at the left and the toolbar at the right
|
||||
$rv .= &ui_tag('div', &plain_breadcrumb().&plain_toolbar(),
|
||||
{ 'class' => 'filemin_head' });
|
||||
|
||||
# Page links, when the listing does not fit on one page. The URL is
|
||||
# relative, so a search keeps its query from page to page
|
||||
my $pager = &ui_pager({
|
||||
'page' => $page,
|
||||
'pages' => $pages,
|
||||
'href' => "?path=".&urlize($path).
|
||||
(defined($query) && $query ne '' ?
|
||||
"&query=".&urlize($query) : "").
|
||||
($in{'caseins'} ? "&caseins=1" : "").
|
||||
"&page=" });
|
||||
$rv .= &ui_tag('div', $pager, { 'class' => 'filemin_pager' }) if ($pager);
|
||||
|
||||
# The dialogs opened from the toolbar and the rows
|
||||
$rv .= &plain_dialogs();
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# plain_asset_tags()
|
||||
# Returns the tags loading the module's stylesheet and script for the
|
||||
# widget interface, each keyed by its modification time so that a changed
|
||||
# file is fetched at once, and the permissions calculator shared with the
|
||||
# Bootstrap interface
|
||||
sub plain_asset_tags
|
||||
{
|
||||
my $rv = "";
|
||||
foreach my $file ('css/plain.css', 'js/plain.js') {
|
||||
my @st = stat("$module_root_directory/unauthenticated/$file");
|
||||
my $url = "unauthenticated/$file?".(@st ? $st[9] : &get_webmin_version());
|
||||
if ($file =~ /\.css$/) {
|
||||
$rv .= &ui_tag('link', undef,
|
||||
{ 'rel' => 'stylesheet', 'href' => $url })."\n";
|
||||
}
|
||||
else {
|
||||
$rv .= &ui_tag('script', undef,
|
||||
{ 'src' => $url, 'defer' => undef })."\n";
|
||||
}
|
||||
}
|
||||
$rv .= &ui_tag('script', undef,
|
||||
{ 'src' => 'unauthenticated/js/chmod-calculator.js' })."\n";
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# plain_breadcrumb()
|
||||
# Returns the path to the current directory as breadcrumb links, starting
|
||||
# with the allowed base directory : the disk when it is the root, else
|
||||
# the home
|
||||
sub plain_breadcrumb
|
||||
{
|
||||
my @items = ( { 'icon' => $base eq '/' ? 'hard-drive' : 'home',
|
||||
'href' => 'index.cgi?path=',
|
||||
'title' => $base } );
|
||||
my $cp = '';
|
||||
foreach my $part (grep { $_ ne '' } split(/\//, $path)) {
|
||||
$cp .= '/'.$part;
|
||||
push(@items, { 'label' => $part,
|
||||
'href' => 'index.cgi?path='.&urlize($cp) });
|
||||
}
|
||||
return &ui_breadcrumb(\@items, { 'class' => 'filemin_crumbs' });
|
||||
}
|
||||
|
||||
# plain_toolbar()
|
||||
# Returns the toolbar : the File, Edit, Tools and Bookmarks menus, and the
|
||||
# refresh and delete buttons. Entries acting on the selected entries are
|
||||
# marked, so that plain.js asks for a selection first. Tools whose
|
||||
# command is missing are left out.
|
||||
sub plain_toolbar
|
||||
{
|
||||
my $urlpath = &urlize($path);
|
||||
my $sel = { 'data-filemin-selection' => '1' };
|
||||
my @file = (
|
||||
{ 'label' => $text{'create_file'}, 'icon' => 'file-plus',
|
||||
'dialog' => 'filemin_create_file' },
|
||||
{ 'label' => $text{'create_folder'}, 'icon' => 'folder-plus',
|
||||
'dialog' => 'filemin_create_folder' },
|
||||
'-',
|
||||
{ 'label' => $text{'upload_files'}, 'icon' => 'upload',
|
||||
'dialog' => 'filemin_upload' },
|
||||
{ 'label' => $text{'get_from_url'}, 'icon' => 'globe',
|
||||
'dialog' => 'filemin_download' },
|
||||
);
|
||||
my @edit = (
|
||||
{ 'label' => $text{'copy_selected'}, 'icon' => 'copy',
|
||||
'attrs' => { %$sel, 'data-filemin-submit' => 'copy.cgi' } },
|
||||
{ 'label' => $text{'cut_selected'}, 'icon' => 'scissors',
|
||||
'attrs' => { %$sel, 'data-filemin-submit' => 'cut.cgi' } },
|
||||
{ 'label' => $text{'paste'}, 'icon' => 'clipboard',
|
||||
'href' => 'paste.cgi?path='.$urlpath },
|
||||
'-',
|
||||
{ 'label' => $text{'select_all'}, 'icon' => 'check-square',
|
||||
'attrs' => { 'data-filemin-select' => 'all' } },
|
||||
{ 'label' => $text{'invert_selection'}, 'icon' => 'square-half',
|
||||
'attrs' => { 'data-filemin-select' => 'invert' } },
|
||||
);
|
||||
my @tools = (
|
||||
{ 'label' => $text{'search'}, 'icon' => 'search',
|
||||
'dialog' => 'filemin_search' },
|
||||
'-',
|
||||
{ 'label' => $text{'compress_selected'}, 'icon' => 'archive',
|
||||
'dialog' => 'filemin_compress', 'attrs' => $sel },
|
||||
{ 'label' => $text{'chmod_selected'}, 'icon' => 'lock',
|
||||
'dialog' => 'filemin_chmod', 'attrs' => $sel },
|
||||
{ 'label' => $text{'chown_selected'}, 'icon' => 'user',
|
||||
'dialog' => 'filemin_chown', 'attrs' => $sel },
|
||||
);
|
||||
push(@tools, { 'label' => $text{'chattr_selected'}, 'icon' => 'tag',
|
||||
'dialog' => 'filemin_chattr', 'attrs' => $sel })
|
||||
if (&has_command('chattr'));
|
||||
push(@tools, { 'label' => $text{'chcon_selected'}, 'icon' => 'shield',
|
||||
'dialog' => 'filemin_chcon', 'attrs' => $sel })
|
||||
if (&get_selinux_status());
|
||||
push(@tools, { 'label' => $text{'acls_selected'}, 'icon' => 'key',
|
||||
'dialog' => 'filemin_acls', 'attrs' => $sel })
|
||||
if (&has_command('setfacl'));
|
||||
my @bookmarks = (
|
||||
{ 'label' => $text{'bookmark_folder'}, 'icon' => 'bookmark',
|
||||
'href' => 'bookmark.cgi?path='.$urlpath },
|
||||
'-',
|
||||
);
|
||||
my @marks = &list_bookmarks();
|
||||
if (@marks) {
|
||||
push(@bookmarks, map { { 'label' => $_, 'icon' => 'folder',
|
||||
'href' => 'index.cgi?path='.&urlize($_) } }
|
||||
@marks);
|
||||
}
|
||||
else {
|
||||
push(@bookmarks, { 'label' => $text{'no_bookmarks'}, 'disabled' => 1 });
|
||||
}
|
||||
my @buttons = (
|
||||
&ui_dropdown($text{'menu_file'}, \@file, { 'icon' => 'file' }),
|
||||
&ui_dropdown($text{'menu_edit'}, \@edit, { 'icon' => 'clipboard' }),
|
||||
&ui_dropdown($text{'menu_tools'}, \@tools, { 'icon' => 'gear' }),
|
||||
&ui_dropdown($text{'menu_bookmarks'}, \@bookmarks,
|
||||
{ 'icon' => 'book', 'align' => 'end' }),
|
||||
&ui_action_button($text{'refresh'}, 'neutral',
|
||||
{ 'icon' => 'refresh', 'href' => 'index.cgi?path='.$urlpath }),
|
||||
&ui_dialog_button($text{'delete'}, 'filemin_delete', 'danger',
|
||||
{ 'icon' => 'trash', 'attrs' => $sel }),
|
||||
);
|
||||
return &ui_tag('div', join("\n", @buttons),
|
||||
{ 'class' => 'filemin_toolbar', 'role' => 'toolbar' });
|
||||
}
|
||||
|
||||
# plain_dialog_table(&rows)
|
||||
# Returns a two-column table of label and input rows for a dialog body.
|
||||
# A row with an empty label spans the table.
|
||||
sub plain_dialog_table
|
||||
{
|
||||
my ($rows) = @_;
|
||||
my $rv = &ui_table_start(undef, "width=100%", 2);
|
||||
foreach my $row (@$rows) {
|
||||
$rv .= defined($row->[0]) && $row->[0] ne '' ?
|
||||
&ui_table_row($row->[0], $row->[1]) :
|
||||
&ui_table_row(undef, $row->[1], 2);
|
||||
}
|
||||
$rv .= &ui_table_end();
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# plain_dialogs()
|
||||
# Returns the dialogs behind the toolbar and the row actions. A dialog
|
||||
# acting on the selected entries carries the script to run in a
|
||||
# data-filemin-apply attribute : plain.js sends the selection form to that
|
||||
# script with the dialog's fields as URL parameters, as the action
|
||||
# scripts expect them. The other dialogs are ordinary forms posting to
|
||||
# their script.
|
||||
sub plain_dialogs
|
||||
{
|
||||
my $rv = "";
|
||||
my $hidden_path = &ui_hidden('path', $path);
|
||||
my $cancel = $text{'dialog_cancel'};
|
||||
my $recursive = &ui_checkbox('recursive', 'true', $text{'dialog_recursive'}, 0);
|
||||
my $apply = sub {
|
||||
# A form sent to the selection, closed natively if the script fails
|
||||
my ($script, $name) = @_;
|
||||
return { 'method' => 'dialog',
|
||||
'name' => $name,
|
||||
'attrs' => { 'data-filemin-apply' => $script } };
|
||||
};
|
||||
my $change = [ { 'label' => $text{'dialog_change'}, 'state' => 'success',
|
||||
'icon' => 'check' } ];
|
||||
|
||||
# Shown when an action needs a selection and nothing is checked
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_nothing',
|
||||
'title' => $text{'warning_title'},
|
||||
'state' => 'warning',
|
||||
'size' => 'small',
|
||||
'text' => $text{'nothing_selected'},
|
||||
'close' => $text{'dialog_ok'} });
|
||||
|
||||
# New file and directory
|
||||
foreach my $kind ([ 'file', 'create_file', 'new_file_name', 'file-plus' ],
|
||||
[ 'folder', 'create_folder', 'new_folder_name', 'folder-plus' ]) {
|
||||
my ($what, $title, $label, $icon) = @$kind;
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_create_'.$what,
|
||||
'title' => $text{$title},
|
||||
'icon' => $icon,
|
||||
'size' => 'small',
|
||||
'form' => 'create_'.$what.'.cgi',
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{$label},
|
||||
&ui_textbox('name', '', 30, 0, undef, 'required') ],
|
||||
]).$hidden_path,
|
||||
'buttons' => [ { 'label' => $text{'create'}, 'state' => 'success',
|
||||
'icon' => 'check' } ],
|
||||
'close' => $cancel });
|
||||
}
|
||||
|
||||
# Rename, filled in by the row link
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_rename',
|
||||
'title' => $text{'rename'},
|
||||
'icon' => 'cursor-text',
|
||||
'size' => 'small',
|
||||
'form' => 'rename.cgi',
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'new_name'},
|
||||
&ui_textbox('name', '', 30, 0, undef, 'required') ],
|
||||
]).&ui_hidden('file', '').$hidden_path,
|
||||
'buttons' => [ { 'label' => $text{'rename'}, 'state' => 'success',
|
||||
'icon' => 'check' } ],
|
||||
'close' => $cancel });
|
||||
|
||||
# Upload. The options travel in the URL, which upload.cgi reads before
|
||||
# the files arrive, so plain.js adds them to the action on submit
|
||||
my $upload_url = "upload.cgi?path=".&urlize($path)."&id=".$upid;
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_upload',
|
||||
'title' => $text{'upload_files'},
|
||||
'icon' => 'upload',
|
||||
'form' => { 'action' => $upload_url,
|
||||
'method' => 'form-data',
|
||||
'attrs' => {
|
||||
'data-filemin-upload' => $upload_url,
|
||||
'data-filemin-tracker' =>
|
||||
&get_webprefix()."/uptracker.cgi?id=".$upid } },
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'upload_files'},
|
||||
&ui_upload('upfiles', 40, 0, 'multiple required') ],
|
||||
[ undef,
|
||||
&ui_checkbox('opt_dirs', 1, $text{'upload_dirs'}, 0,
|
||||
'data-filemin-upload-dirs')."<br>".
|
||||
&ui_checkbox('opt_extract', 1, $text{'extract_uploaded'}, 0,
|
||||
"data-filemin-upload-option='extract_uploaded'").
|
||||
"<br>".
|
||||
&ui_checkbox('opt_overwrite', 1, $text{'overwrite_existing'}, 0,
|
||||
"data-filemin-upload-option='overwrite_existing'") ],
|
||||
]),
|
||||
'buttons' => [ { 'label' => $text{'upload_files'}, 'state' => 'success',
|
||||
'icon' => 'upload' } ],
|
||||
'close' => $cancel });
|
||||
|
||||
# Download from a URL
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_download',
|
||||
'title' => $text{'get_from_url'},
|
||||
'icon' => 'globe',
|
||||
'form' => 'http_download.cgi',
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'dialog_file_url'},
|
||||
&ui_tag('input', undef, { 'type' => 'url', 'name' => 'link',
|
||||
'class' => 'ui_textbox', 'size' => 40,
|
||||
'autocomplete' => 'url',
|
||||
'required' => undef }) ],
|
||||
[ $text{'dialog_user_name'},
|
||||
&ui_textbox('username', '', 25, 0, undef, "autocomplete='off'") ],
|
||||
[ $text{'dialog_user_pass'},
|
||||
&ui_password('password', '', 25, 0, undef,
|
||||
"autocomplete='new-password' data-password-meter-skip") ],
|
||||
]).$hidden_path,
|
||||
'buttons' => [ { 'label' => $text{'dialog_download'}, 'state' => 'success',
|
||||
'icon' => 'download' } ],
|
||||
'close' => $cancel });
|
||||
|
||||
# Search under the current directory
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_search',
|
||||
'title' => $text{'search'},
|
||||
'icon' => 'search',
|
||||
'size' => 'small',
|
||||
'form' => 'search.cgi',
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'search_label'},
|
||||
&ui_textbox('query', '', 30, 0, undef, 'required') ],
|
||||
[ undef, &ui_checkbox('caseins', 1, $text{'search_insensitive'}, 1) ],
|
||||
]).$hidden_path,
|
||||
'buttons' => [ { 'label' => $text{'search_go'}, 'state' => 'success',
|
||||
'icon' => 'search' } ],
|
||||
'close' => $cancel });
|
||||
|
||||
# Compress the selection into an archive
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_compress',
|
||||
'title' => $text{'compress_selected'},
|
||||
'icon' => 'archive',
|
||||
'size' => 'small',
|
||||
'form' => &$apply('compress.cgi'),
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'archive_name'},
|
||||
&ui_textbox('arch', '', 30, 0, undef, 'required') ],
|
||||
[ $text{'type'},
|
||||
&ui_select('method', 'tar', [ [ 'plain-tar', '.tar' ],
|
||||
[ 'xz-tar', '.tar.xz' ],
|
||||
[ 'tar', '.tar.gz' ],
|
||||
[ 'zstd-tar', '.zstd' ],
|
||||
[ 'zip', '.zip' ] ]) ],
|
||||
]),
|
||||
'buttons' => [ { 'label' => $text{'dialog_compress'}, 'state' => 'success',
|
||||
'icon' => 'archive' } ],
|
||||
'close' => $cancel });
|
||||
|
||||
# Permissions. The form is named for the calculator, whose fields are
|
||||
# kept out of the parameters; the perms parameter the script reads is a
|
||||
# hidden field that plain.js keeps equal to the octal field
|
||||
my $matrix = &ui_tag_start('table', { 'class' => 'filemin_chmod_matrix' }).
|
||||
&ui_tag('tr', &ui_tag('th', '').
|
||||
join('', map { &ui_tag('th', &html_escape($text{$_})) }
|
||||
('chmod_owner', 'chmod_group', 'chmod_others')));
|
||||
foreach my $bit ([ 'chmod_read', 4 ], [ 'chmod_write', 2 ],
|
||||
[ 'chmod_execute', 1 ]) {
|
||||
$matrix .= &ui_tag('tr', &ui_tag('td', &html_escape($text{$bit->[0]})).
|
||||
join('', map { &ui_tag('td', &ui_checkbox($_.$bit->[1], $bit->[1],
|
||||
undef, 0, 'data-filemin-chmod data-filemin-skip')) }
|
||||
('owner', 'group', 'other')));
|
||||
}
|
||||
foreach my $extra ([ 'chmod_sticky', 'sticky', 1 ], [ 'chmod_setgid', 'setgid', 2 ]) {
|
||||
$matrix .= &ui_tag('tr', &ui_tag('td', &html_escape($text{$extra->[0]})).
|
||||
&ui_tag('td', &ui_checkbox($extra->[1], $extra->[2], undef, 0,
|
||||
'data-filemin-chmod data-filemin-skip')).
|
||||
&ui_tag('td', '').&ui_tag('td', ''));
|
||||
}
|
||||
$matrix .= &ui_tag_end('table');
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_chmod',
|
||||
'title' => $text{'chmod_selected'},
|
||||
'icon' => 'lock',
|
||||
'form' => &$apply('chmod.cgi', 'chmod'),
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'permissions'},
|
||||
&ui_textbox('t_total', '0644', 4, 0, 4,
|
||||
"data-filemin-chmod-octal data-filemin-skip ".
|
||||
"pattern='[0-7]{3,4}' required")." ".
|
||||
&ui_textbox('sym_total', '', 12, 0, undef,
|
||||
'readonly data-filemin-skip').
|
||||
&ui_hidden('perms', '0644') ],
|
||||
[ undef, $matrix ],
|
||||
[ $text{'chmod_apply_to'},
|
||||
&ui_select('applyto', 1,
|
||||
[ map { [ $_->[0], $text{$_->[1]} ] }
|
||||
( [ 1, 'chmod_dir_only' ],
|
||||
[ 2, 'chmod_dir_and_its_files' ],
|
||||
[ 3, 'chmod_all' ],
|
||||
[ 4, 'chmod_dir_files_and_subs_files' ],
|
||||
[ 5, 'chmod_dir_and_subs' ] ) ]) ],
|
||||
]),
|
||||
'buttons' => $change,
|
||||
'close' => $cancel });
|
||||
|
||||
# Ownership
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_chown',
|
||||
'title' => $text{'chown_selected'},
|
||||
'icon' => 'user',
|
||||
'size' => 'small',
|
||||
'form' => &$apply('chown.cgi'),
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'user_name'},
|
||||
&ui_textbox('owner', '', 20, 0, undef, 'required') ],
|
||||
[ $text{'group_name'},
|
||||
&ui_textbox('group', '', 20, 0, undef, 'required') ],
|
||||
[ undef, $recursive ],
|
||||
]),
|
||||
'buttons' => $change,
|
||||
'close' => $cancel });
|
||||
|
||||
# File attributes and SELinux context, which take one label each
|
||||
foreach my $tool ([ 'chattr', 'tag', 'attr_label' ],
|
||||
[ 'chcon', 'shield', 'context_label' ]) {
|
||||
my ($what, $icon, $label) = @$tool;
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_'.$what,
|
||||
'title' => $text{$what.'_selected'},
|
||||
'icon' => $icon,
|
||||
'size' => 'small',
|
||||
'form' => &$apply($what.'.cgi'),
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{$label},
|
||||
&ui_textbox('label', '', 25, 0, undef, 'required') ],
|
||||
[ undef, $recursive ],
|
||||
]),
|
||||
'buttons' => $change,
|
||||
'close' => $cancel });
|
||||
}
|
||||
|
||||
# Access control lists, when setfacl exists
|
||||
if (&has_command('setfacl')) {
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_acls',
|
||||
'title' => $text{'acls_selected'},
|
||||
'icon' => 'key',
|
||||
'form' => &$apply('setfacl.cgi'),
|
||||
'body' => &plain_dialog_table([
|
||||
[ $text{'acls_action'},
|
||||
&ui_select('action', '-m',
|
||||
[ [ '', '' ], [ '-m', 'Modify (-m)' ],
|
||||
[ '-x', 'Remove (-x)' ],
|
||||
[ '-b', 'Remove all extended (-b)' ],
|
||||
[ '-k', 'Remove default (-k)' ] ]) ],
|
||||
[ $text{'acls_applyto'},
|
||||
&ui_select('apply_to', [ ],
|
||||
[ map { [ $_->[0], $text{$_->[1]} ] }
|
||||
( [ 'u', 'acls_user' ], [ 'g', 'acls_group' ],
|
||||
[ 'm', 'acls_mask' ], [ 'o', 'acls_other' ] ) ],
|
||||
4, 1) ],
|
||||
[ $text{'acls_perms'},
|
||||
&ui_select('perms', '',
|
||||
[ map { [ $_, $_ ] }
|
||||
( '', '---', 'r--', '-w-', '--x',
|
||||
'r-x', 'rw-', '-wx', 'rwx' ) ]) ],
|
||||
[ $text{'acls_user'}, $acl_user_select ],
|
||||
[ $text{'acls_group'}, $acl_group_select ],
|
||||
[ undef, &ui_checkbox('recursive', 1, $text{'dialog_recursive'}, 0) ],
|
||||
[ undef, $acl_manual ],
|
||||
]),
|
||||
'buttons' => $change,
|
||||
'close' => $cancel });
|
||||
}
|
||||
|
||||
# Delete, after listing what is selected. Cancel takes the focus, so
|
||||
# Enter does not delete by accident
|
||||
$rv .= &ui_dialog({
|
||||
'id' => 'filemin_delete',
|
||||
'title' => $text{'remove_selected'},
|
||||
'state' => 'danger',
|
||||
'icon' => 'trash',
|
||||
'form' => &$apply('delete.cgi'),
|
||||
'body' => &ui_tag('p', &html_escape($text{'about_to_delete'})).
|
||||
&ui_tag('pre', '', { 'id' => 'filemin_delete_items',
|
||||
'class' => 'filemin_delete_items' }).
|
||||
&ui_tag('p', &html_escape($text{'are_you_sure'})),
|
||||
'buttons' => [ { 'label' => $text{'delete'}, 'state' => 'danger',
|
||||
'icon' => 'trash' } ],
|
||||
'close' => $cancel,
|
||||
'focus' => 'close' });
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# get_paste_buffer_file()
|
||||
# Returns the location of the file for temporary copy/paste state
|
||||
sub get_paste_buffer_file
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 466 B |
|
Before Width: | Height: | Size: 944 B |
|
Before Width: | Height: | Size: 734 B |
|
Before Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 956 B |
|
Before Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 738 B |
|
Before Width: | Height: | Size: 529 B |
|
Before Width: | Height: | Size: 864 B |
|
Before Width: | Height: | Size: 589 B |
|
Before Width: | Height: | Size: 981 B |
|
Before Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 608 B |
|
Before Width: | Height: | Size: 702 B |
|
Before Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 557 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 838 B |
|
Before Width: | Height: | Size: 736 B |
|
Before Width: | Height: | Size: 294 B |
|
Before Width: | Height: | Size: 754 B |
@@ -13,7 +13,6 @@ $query = $in{'query'};
|
||||
$text{'search_results'} . " '" .
|
||||
&html_escape($query) . "'", "");
|
||||
|
||||
print $head;
|
||||
if ($in{'caseins'}) {
|
||||
$criteria = '-iname';
|
||||
}
|
||||
|
||||
85
filemin/unauthenticated/css/plain.css
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* plain.css
|
||||
* Layout of the File Manager for themes without Bootstrap. The toolbar,
|
||||
* its menus, the dialogs and the page links are core widgets styled by
|
||||
* ui-lib.css; this file only arranges them around the listing and
|
||||
* styles the row action links and the permissions matrix.
|
||||
*/
|
||||
|
||||
/* Breadcrumbs at the left, toolbar at the right, wrapping on a narrow
|
||||
* frame */
|
||||
.filemin_head {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px 16px;
|
||||
}
|
||||
.filemin_head .ui_breadcrumb {
|
||||
min-width: 0;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
.filemin_toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.filemin_pager { display: flex; }
|
||||
.filemin_page .total { color: var(--ui-fg-muted); }
|
||||
|
||||
/* Row action links hold icons and sit side by side */
|
||||
.filemin_page .action-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
color: var(--ui-fg-muted);
|
||||
vertical-align: middle;
|
||||
}
|
||||
.filemin_page .action-link:hover { color: var(--ui-accent); }
|
||||
.filemin_page td > a > img { vertical-align: middle; }
|
||||
|
||||
/* Dialog forms sit flush inside the dialog body, and stay within it :
|
||||
* both the theme's wrapper table and the form table take the dialog
|
||||
* width with fixed columns, the label column has a set width, and the
|
||||
* inputs fit the value column instead of widening the dialog */
|
||||
.filemin_page .ui_dialog_body > table.wrapper { margin: 0; }
|
||||
.filemin_page .ui_dialog_body table.wrapper,
|
||||
.filemin_page .ui_dialog_body table.ui_table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
.filemin_page .ui_dialog_body td.ui_form_label {
|
||||
width: 8.5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.filemin_page .ui_dialog_body td.ui_form_value select { width: 100%; }
|
||||
.filemin_page .ui_dialog_body td.ui_form_value
|
||||
input:not([type="checkbox"]):not([type="radio"]) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* The permissions matrix */
|
||||
.filemin_chmod_matrix { border-collapse: collapse; }
|
||||
.filemin_chmod_matrix th, .filemin_chmod_matrix td {
|
||||
padding: 2px 12px 2px 0;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
}
|
||||
.filemin_chmod_matrix th { font-weight: 600; }
|
||||
.filemin_chmod_matrix input[type="checkbox"] { margin: 0; }
|
||||
|
||||
/* The entries about to be deleted */
|
||||
.filemin_delete_items {
|
||||
max-height: 180px;
|
||||
margin: 8px 0;
|
||||
padding: 8px 10px;
|
||||
overflow: auto;
|
||||
border: 1px solid var(--ui-border-soft);
|
||||
background: var(--ui-surface-2);
|
||||
font-family: var(--ui-font-mono);
|
||||
font-size: 0.92em;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/* Styles for jQuery menu widget
|
||||
Author: Maggie Wachs, maggie@filamentgroup.com
|
||||
Date: September 2008
|
||||
*/
|
||||
|
||||
|
||||
/* REQUIRED STYLES - the menus will only render correctly with these rules */
|
||||
|
||||
.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
|
||||
.fg-menu-container.fg-menu-flyout { overflow: visible; }
|
||||
|
||||
.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
|
||||
|
||||
.fg-menu { position:relative; }
|
||||
.fg-menu-flyout .fg-menu { position:static; }
|
||||
|
||||
.fg-menu ul { position:absolute; top:0; }
|
||||
.fg-menu ul ul { top:-1px; }
|
||||
|
||||
.fg-menu-container.fg-menu-ipod .fg-menu-content,
|
||||
.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
|
||||
|
||||
.fg-menu.fg-menu-scroll,
|
||||
.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
|
||||
|
||||
.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
|
||||
.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
|
||||
|
||||
.fg-menu-flyout ul ul { padding: .4em; }
|
||||
.fg-menu-flyout li { position:relative; }
|
||||
|
||||
.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
|
||||
|
||||
.fg-menu-breadcrumb { margin: 0; padding: 0; }
|
||||
|
||||
.fg-menu-footer { margin-top: .4em; padding: .4em; }
|
||||
.fg-menu-header { margin-bottom: .4em; padding: .4em; }
|
||||
|
||||
.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
|
||||
.fg-menu-breadcrumb li.fg-menu-prev-list,
|
||||
.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
|
||||
.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
|
||||
|
||||
.fg-menu-breadcrumb a,
|
||||
.fg-menu-breadcrumb span { float: left; }
|
||||
|
||||
.fg-menu-footer a:link,
|
||||
.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
|
||||
.fg-menu-footer a:hover,
|
||||
.fg-menu-footer a:active { }
|
||||
|
||||
.fg-menu-footer a span { float:left; cursor: pointer; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:link,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
|
||||
|
||||
|
||||
|
||||
/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
|
||||
selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
|
||||
|
||||
.fg-menu a:link,
|
||||
.fg-menu a:visited,
|
||||
.fg-menu a:hover,
|
||||
.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
|
||||
|
||||
.fg-menu a { border: 1px dashed transparent; }
|
||||
|
||||
.fg-menu a.ui-state-default:link,
|
||||
.fg-menu a.ui-state-default:visited,
|
||||
.fg-menu a.ui-state-default:hover,
|
||||
.fg-menu a.ui-state-default:active,
|
||||
.fg-menu a.ui-state-hover:link,
|
||||
.fg-menu a.ui-state-hover:visited,
|
||||
.fg-menu a.ui-state-hover:hover,
|
||||
.fg-menu a.ui-state-hover:active,
|
||||
.fg-menu a.ui-state-active:link,
|
||||
.fg-menu a.ui-state-active:visited,
|
||||
.fg-menu a.ui-state-active:hover,
|
||||
.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
|
||||
|
||||
.fg-menu a span { display:block; cursor:pointer; }
|
||||
|
||||
|
||||
/* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
|
||||
|
||||
.fg-menu-indicator span { float:left; }
|
||||
.fg-menu-indicator span.ui-icon { float:right; }
|
||||
|
||||
.fg-menu-content.ui-widget-content,
|
||||
.fg-menu-content ul.ui-widget-content { border:0; }
|
||||
|
||||
|
||||
/* ICONS AND DIVIDERS */
|
||||
|
||||
.fg-menu.fg-menu-has-icons a:link,
|
||||
.fg-menu.fg-menu-has-icons a:visited,
|
||||
.fg-menu.fg-menu-has-icons a:hover,
|
||||
.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
|
||||
|
||||
.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
|
||||
.fg-menu .horizontal-divider hr { border:0; height:1px; }
|
||||
.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
|
||||
|
||||
@@ -1,648 +0,0 @@
|
||||
/*--------------------------------------------------------------------
|
||||
Scripts for creating and manipulating custom menus based on standard <ul> markup
|
||||
Version: 3.0, 03.31.2009
|
||||
|
||||
By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
|
||||
http://www.filamentgroup.com
|
||||
* reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_menu/
|
||||
|
||||
Copyright (c) 2009 Filament Group
|
||||
Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
var allUIMenus = [];
|
||||
|
||||
$.fn.menu = function(options){
|
||||
var caller = this;
|
||||
var options = options;
|
||||
var m = new Menu(caller, options);
|
||||
allUIMenus.push(m);
|
||||
|
||||
$(this)
|
||||
.mousedown(function(){
|
||||
if (!m.menuOpen) { m.showLoading(); };
|
||||
})
|
||||
.click(function(){
|
||||
if (m.menuOpen == false) { m.showMenu(); }
|
||||
else { m.kill(); };
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
function Menu(caller, options){
|
||||
var menu = this;
|
||||
var caller = $(caller);
|
||||
var container = $('<div class="fg-menu-container ui-widget ui-widget-content ui-corner-all">'+options.content+'</div>');
|
||||
|
||||
this.menuOpen = false;
|
||||
this.menuExists = false;
|
||||
|
||||
var options = jQuery.extend({
|
||||
content: null,
|
||||
width: 180, // width of menu container, must be set or passed in to calculate widths of child menus
|
||||
maxHeight: 180, // max height of menu (if a drilldown: height does not include breadcrumb)
|
||||
positionOpts: {
|
||||
posX: 'left',
|
||||
posY: 'bottom',
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
directionH: 'right',
|
||||
directionV: 'down',
|
||||
detectH: true, // do horizontal collision detection
|
||||
detectV: true, // do vertical collision detection
|
||||
linkToFront: false
|
||||
},
|
||||
showSpeed: 200, // show/hide speed in milliseconds
|
||||
callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the menu is showing
|
||||
loadingState: 'ui-state-loading', // class added to the link/button while the menu is created
|
||||
linkHover: 'ui-state-hover', // class for menu option hover state
|
||||
linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level menus
|
||||
// ----- multi-level menu defaults -----
|
||||
crossSpeed: 200, // cross-fade speed for multi-level menus
|
||||
crumbDefaultText: 'Choose an option:',
|
||||
backLink: true, // in the ipod-style menu: instead of breadcrumbs, show only a 'back' link
|
||||
backLinkText: 'Back',
|
||||
flyOut: false, // multi-level menus are ipod-style by default; this parameter overrides to make a flyout instead
|
||||
flyOutOnState: 'ui-state-default',
|
||||
nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
|
||||
topLinkText: 'All',
|
||||
nextCrumbLink: 'ui-icon-carat-1-e'
|
||||
}, options);
|
||||
|
||||
var killAllMenus = function(){
|
||||
$.each(allUIMenus, function(i){
|
||||
if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
|
||||
});
|
||||
};
|
||||
|
||||
this.kill = function(){
|
||||
caller
|
||||
.removeClass(options.loadingState)
|
||||
.removeClass('fg-menu-open')
|
||||
.removeClass(options.callerOnState);
|
||||
container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);
|
||||
if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };
|
||||
if (options.callerOnState) { caller.removeClass(options.callerOnState); };
|
||||
if (container.is('.fg-menu-ipod')) { menu.resetDrilldownMenu(); };
|
||||
if (container.is('.fg-menu-flyout')) { menu.resetFlyoutMenu(); };
|
||||
container.parent().hide();
|
||||
menu.menuOpen = false;
|
||||
$(document).unbind('click', killAllMenus);
|
||||
$(document).unbind('keydown');
|
||||
};
|
||||
|
||||
this.showLoading = function(){
|
||||
caller.addClass(options.loadingState);
|
||||
};
|
||||
|
||||
this.showMenu = function(){
|
||||
killAllMenus();
|
||||
if (!menu.menuExists) { menu.create() };
|
||||
caller
|
||||
.addClass('fg-menu-open')
|
||||
.addClass(options.callerOnState);
|
||||
container.parent().show().click(function(){ menu.kill(); return false; });
|
||||
container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
|
||||
menu.menuOpen = true;
|
||||
caller.removeClass(options.loadingState);
|
||||
$(document).click(killAllMenus);
|
||||
|
||||
// assign key events
|
||||
$(document).keydown(function(event){
|
||||
var e;
|
||||
if (event.which !="") { e = event.which; }
|
||||
else if (event.charCode != "") { e = event.charCode; }
|
||||
else if (event.keyCode != "") { e = event.keyCode; }
|
||||
|
||||
var menuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
|
||||
|
||||
switch(e) {
|
||||
case 37: // left arrow
|
||||
if (menuType == 'flyout') {
|
||||
$(event.target).trigger('mouseout');
|
||||
if ($('.'+options.flyOutOnState).length > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
|
||||
};
|
||||
|
||||
if (menuType == 'ipod') {
|
||||
$(event.target).trigger('mouseout');
|
||||
if ($('.fg-menu-footer').find('a').length > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
|
||||
if ($('.fg-menu-header').find('a').length > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
|
||||
if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
|
||||
$('.fg-menu-current').prev().trigger('mouseover');
|
||||
};
|
||||
};
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 38: // up arrow
|
||||
if ($(event.target).is('.' + options.linkHover)) {
|
||||
var prevLink = $(event.target).parent().prev().find('a:eq(0)');
|
||||
if (prevLink.length > 0) {
|
||||
$(event.target).trigger('mouseout');
|
||||
prevLink.trigger('mouseover');
|
||||
};
|
||||
}
|
||||
else { container.find('a:eq(0)').trigger('mouseover'); }
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 39: // right arrow
|
||||
if ($(event.target).is('.fg-menu-indicator')) {
|
||||
if (menuType == 'flyout') {
|
||||
$(event.target).next().find('a:eq(0)').trigger('mouseover');
|
||||
}
|
||||
else if (menuType == 'ipod') {
|
||||
$(event.target).trigger('click');
|
||||
setTimeout(function(){
|
||||
$(event.target).next().find('a:eq(0)').trigger('mouseover');
|
||||
}, options.crossSpeed);
|
||||
};
|
||||
};
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 40: // down arrow
|
||||
if ($(event.target).is('.' + options.linkHover)) {
|
||||
var nextLink = $(event.target).parent().next().find('a:eq(0)');
|
||||
if (nextLink.length > 0) {
|
||||
$(event.target).trigger('mouseout');
|
||||
nextLink.trigger('mouseover');
|
||||
};
|
||||
}
|
||||
else { container.find('a:eq(0)').trigger('mouseover'); }
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 27: // escape
|
||||
killAllMenus();
|
||||
break;
|
||||
|
||||
case 13: // enter
|
||||
if ($(event.target).is('.fg-menu-indicator') && menuType == 'ipod') {
|
||||
$(event.target).trigger('click');
|
||||
setTimeout(function(){
|
||||
$(event.target).next().find('a:eq(0)').trigger('mouseover');
|
||||
}, options.crossSpeed);
|
||||
};
|
||||
break;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
this.create = function() {
|
||||
container.css({ width: options.width }).appendTo('body').find('ul:first').not('.fg-menu-breadcrumb').addClass('fg-menu');
|
||||
container.find('ul, li a').addClass('ui-corner-all');
|
||||
|
||||
// aria roles & attributes
|
||||
container.find('ul').attr('role', 'menu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
|
||||
container.find('li').attr('role', 'menuitem');
|
||||
container.find('li:has(ul)').attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
|
||||
container.find('a').attr('tabindex', '-1');
|
||||
|
||||
// when there are multiple levels of hierarchy, create flyout or drilldown menu
|
||||
if (container.find('ul').length > 1) {
|
||||
if (options.flyOut) { menu.flyout(container, options); }
|
||||
else { menu.drilldown(container, options); }
|
||||
}
|
||||
else {
|
||||
container.find('a').click(function(){
|
||||
menu.chooseItem(this);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
if (options.linkHover) {
|
||||
var allLinks = container.find('.fg-menu li a');
|
||||
allLinks.hover(
|
||||
function(){
|
||||
var menuitem = $(this);
|
||||
$('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
|
||||
$(this).addClass(options.linkHover).focus().parent().attr('id','active-menuitem');
|
||||
},
|
||||
function(){
|
||||
$(this).removeClass(options.linkHover).blur().parent().removeAttr('id');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
if (options.linkHoverSecondary) {
|
||||
container.find('.fg-menu li').hover(
|
||||
function(){
|
||||
$(this).siblings('li').removeClass(options.linkHoverSecondary);
|
||||
if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
|
||||
$(this).addClass(options.linkHoverSecondary);
|
||||
},
|
||||
function(){ $(this).removeClass(options.linkHoverSecondary); }
|
||||
);
|
||||
};
|
||||
|
||||
menu.setPosition(container, caller, options);
|
||||
menu.menuExists = true;
|
||||
|
||||
// Hide empty
|
||||
container.find('a:empty').parent('li').hide()
|
||||
};
|
||||
|
||||
this.chooseItem = function(item){
|
||||
menu.kill();
|
||||
// edit this for your own custom function/callback:
|
||||
$('#menuSelection').text($(item).text());
|
||||
location.href = $(item).attr('href');
|
||||
};
|
||||
};
|
||||
|
||||
Menu.prototype.flyout = function(container, options) {
|
||||
var menu = this;
|
||||
|
||||
this.resetFlyoutMenu = function(){
|
||||
var allLists = container.find('ul ul');
|
||||
allLists.removeClass('ui-widget-content').hide();
|
||||
};
|
||||
|
||||
container.addClass('fg-menu-flyout').find('li:has(ul)').each(function(){
|
||||
var linkWidth = container.width();
|
||||
var showTimer, hideTimer;
|
||||
var allSubLists = $(this).find('ul');
|
||||
|
||||
allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
|
||||
|
||||
$(this).find('a:eq(0)').addClass('fg-menu-indicator').html('<span>' + $(this).find('a:eq(0)').text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>').hover(
|
||||
function(){
|
||||
clearTimeout(hideTimer);
|
||||
var subList = $(this).next();
|
||||
if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
|
||||
if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 999 }); };
|
||||
showTimer = setTimeout(function(){
|
||||
subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');
|
||||
}, 300);
|
||||
},
|
||||
function(){
|
||||
clearTimeout(showTimer);
|
||||
var subList = $(this).next();
|
||||
hideTimer = setTimeout(function(){
|
||||
subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
|
||||
}, 400);
|
||||
}
|
||||
);
|
||||
|
||||
$(this).find('ul a').hover(
|
||||
function(){
|
||||
clearTimeout(hideTimer);
|
||||
if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
|
||||
$(this).parents('ul').prev().addClass(options.flyOutOnState);
|
||||
}
|
||||
},
|
||||
function(){
|
||||
hideTimer = setTimeout(function(){
|
||||
allSubLists.hide(options.showSpeed);
|
||||
container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
|
||||
}, 500);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
container.find('a').click(function(){
|
||||
menu.chooseItem(this);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Menu.prototype.drilldown = function(container, options) {
|
||||
var menu = this;
|
||||
var topList = container.find('.fg-menu');
|
||||
var breadcrumb = $('<ul class="fg-menu-breadcrumb ui-widget-header ui-corner-all ui-helper-clearfix"></ul>');
|
||||
var crumbDefaultHeader = $('<li class="fg-menu-breadcrumb-text">'+options.crumbDefaultText+'</li>');
|
||||
var firstCrumbText = (options.backLink) ? options.backLinkText : options.topLinkText;
|
||||
var firstCrumbClass = (options.backLink) ? 'fg-menu-prev-list' : 'fg-menu-all-lists';
|
||||
var firstCrumbLinkClass = (options.backLink) ? 'ui-state-default ui-corner-all' : '';
|
||||
var firstCrumbIcon = (options.backLink) ? '<span class="ui-icon ui-icon-triangle-1-w"></span>' : '';
|
||||
var firstCrumb = $('<li class="'+firstCrumbClass+'"><a href="#" class="'+firstCrumbLinkClass+'">'+firstCrumbIcon+firstCrumbText+'</a></li>');
|
||||
|
||||
container.addClass('fg-menu-ipod');
|
||||
|
||||
if (options.backLink) { breadcrumb.addClass('fg-menu-footer').appendTo(container).hide(); }
|
||||
else { breadcrumb.addClass('fg-menu-header').prependTo(container); };
|
||||
breadcrumb.append(crumbDefaultHeader);
|
||||
|
||||
var checkMenuHeight = function(el){
|
||||
if (el.height() > options.maxHeight) { el.addClass('fg-menu-scroll') };
|
||||
el.css({ height: options.maxHeight });
|
||||
};
|
||||
|
||||
var resetChildMenu = function(el){ el.removeClass('fg-menu-scroll').removeClass('fg-menu-current').height('auto'); };
|
||||
|
||||
this.resetDrilldownMenu = function(){
|
||||
$('.fg-menu-current').removeClass('fg-menu-current');
|
||||
topList.animate({ left: 0 }, options.crossSpeed, function(){
|
||||
$(this).find('ul').each(function(){
|
||||
$(this).hide();
|
||||
resetChildMenu($(this));
|
||||
});
|
||||
topList.addClass('fg-menu-current');
|
||||
});
|
||||
$('.fg-menu-all-lists').find('span').remove();
|
||||
breadcrumb.empty().append(crumbDefaultHeader);
|
||||
$('.fg-menu-footer').empty().hide();
|
||||
checkMenuHeight(topList);
|
||||
};
|
||||
|
||||
topList
|
||||
.addClass('fg-menu-content fg-menu-current ui-widget-content ui-helper-clearfix')
|
||||
.css({ width: container.width() })
|
||||
.find('ul')
|
||||
.css({ width: container.width(), left: container.width() })
|
||||
.addClass('ui-widget-content')
|
||||
.hide();
|
||||
checkMenuHeight(topList);
|
||||
|
||||
topList.find('a').each(function(){
|
||||
// if the link opens a child menu:
|
||||
if ($(this).next().is('ul')) {
|
||||
$(this)
|
||||
.addClass('fg-menu-indicator')
|
||||
.each(function(){ $(this).html('<span>' + $(this).text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>'); })
|
||||
.click(function(){ // ----- show the next menu
|
||||
var nextList = $(this).next();
|
||||
var parentUl = $(this).parents('ul:eq(0)');
|
||||
var parentLeft = (parentUl.is('.fg-menu-content')) ? 0 : parseFloat(topList.css('left'));
|
||||
var nextLeftVal = Math.round(parentLeft - parseFloat(container.width()));
|
||||
var footer = $('.fg-menu-footer');
|
||||
|
||||
// show next menu
|
||||
resetChildMenu(parentUl);
|
||||
checkMenuHeight(nextList);
|
||||
topList.animate({ left: nextLeftVal }, options.crossSpeed);
|
||||
nextList.show().addClass('fg-menu-current').attr('aria-expanded', 'true');
|
||||
|
||||
var setPrevMenu = function(backlink){
|
||||
var b = backlink;
|
||||
var c = $('.fg-menu-current');
|
||||
var prevList = c.parents('ul:eq(0)');
|
||||
c.hide().attr('aria-expanded', 'false');
|
||||
resetChildMenu(c);
|
||||
checkMenuHeight(prevList);
|
||||
prevList.addClass('fg-menu-current').attr('aria-expanded', 'true');
|
||||
if (prevList.hasClass('fg-menu-content')) { b.remove(); footer.hide(); };
|
||||
};
|
||||
|
||||
// initialize "back" link
|
||||
if (options.backLink) {
|
||||
if (footer.find('a').length == 0) {
|
||||
footer.show();
|
||||
$('<a href="#"><span class="ui-icon ui-icon-triangle-1-w"></span> <span>Back</span></a>')
|
||||
.appendTo(footer)
|
||||
.click(function(){ // ----- show the previous menu
|
||||
var b = $(this);
|
||||
var prevLeftVal = parseFloat(topList.css('left')) + container.width();
|
||||
topList.animate({ left: prevLeftVal }, options.crossSpeed, function(){
|
||||
setPrevMenu(b);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
// or initialize top breadcrumb
|
||||
else {
|
||||
if (breadcrumb.find('li').length == 1){
|
||||
breadcrumb.empty().append(firstCrumb);
|
||||
firstCrumb.find('a').click(function(){
|
||||
menu.resetDrilldownMenu();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
$('.fg-menu-current-crumb').removeClass('fg-menu-current-crumb');
|
||||
var crumbText = $(this).find('span:eq(0)').text();
|
||||
var newCrumb = $('<li class="fg-menu-current-crumb"><a href="javascript://" class="fg-menu-crumb">'+crumbText+'</a></li>');
|
||||
newCrumb
|
||||
.appendTo(breadcrumb)
|
||||
.find('a').click(function(){
|
||||
if ($(this).parent().is('.fg-menu-current-crumb')){
|
||||
menu.chooseItem(this);
|
||||
}
|
||||
else {
|
||||
var newLeftVal = - ($('.fg-menu-current').parents('ul').length - 1) * 180;
|
||||
topList.animate({ left: newLeftVal }, options.crossSpeed, function(){
|
||||
setPrevMenu();
|
||||
});
|
||||
|
||||
// make this the current crumb, delete all breadcrumbs after this one, and navigate to the relevant menu
|
||||
$(this).parent().addClass('fg-menu-current-crumb').find('span').remove();
|
||||
$(this).parent().nextAll().remove();
|
||||
};
|
||||
return false;
|
||||
});
|
||||
newCrumb.prev().append(' <span class="ui-icon '+options.nextCrumbLink+'"></span>');
|
||||
};
|
||||
return false;
|
||||
});
|
||||
}
|
||||
// if the link is a leaf node (doesn't open a child menu)
|
||||
else {
|
||||
$(this).click(function(){
|
||||
menu.chooseItem(this);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/* Menu.prototype.setPosition parameters (defaults noted with *):
|
||||
referrer = the link (or other element) used to show the overlaid object
|
||||
settings = can override the defaults:
|
||||
- posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
|
||||
X: left*, center, right
|
||||
Y: top, center, bottom*
|
||||
- offsetX/Y: the number of pixels to be offset from the x or y position. Can be a positive or negative number.
|
||||
- directionH/V: where the entire menu should appear in relation to its referrer.
|
||||
Horizontal: left*, right
|
||||
Vertical: up, down*
|
||||
- detectH/V: detect the viewport horizontally / vertically
|
||||
- linkToFront: copy the menu link and place it on top of the menu (visual effect to make it look like it overlaps the object) */
|
||||
|
||||
Menu.prototype.setPosition = function(widget, caller, options) {
|
||||
var el = widget;
|
||||
var referrer = caller;
|
||||
var dims = {
|
||||
refX: referrer.offset().left,
|
||||
refY: referrer.offset().top,
|
||||
refW: referrer.getTotalWidth(),
|
||||
refH: referrer.getTotalHeight()
|
||||
};
|
||||
var options = options;
|
||||
var xVal, yVal;
|
||||
|
||||
var helper = $('<div class="positionHelper"></div>');
|
||||
helper.css({ position: 'absolute', left: dims.refX, top: dims.refY, width: dims.refW, height: dims.refH });
|
||||
el.wrap(helper);
|
||||
|
||||
// get X pos
|
||||
switch(options.positionOpts.posX) {
|
||||
case 'left': xVal = 0;
|
||||
break;
|
||||
case 'center': xVal = dims.refW / 2;
|
||||
break;
|
||||
case 'right': xVal = dims.refW;
|
||||
break;
|
||||
};
|
||||
|
||||
// get Y pos
|
||||
switch(options.positionOpts.posY) {
|
||||
case 'top': yVal = 0;
|
||||
break;
|
||||
case 'center': yVal = dims.refH / 2;
|
||||
break;
|
||||
case 'bottom': yVal = dims.refH;
|
||||
break;
|
||||
};
|
||||
|
||||
// add the offsets (zero by default)
|
||||
xVal += options.positionOpts.offsetX;
|
||||
yVal += options.positionOpts.offsetY;
|
||||
|
||||
// position the object vertically
|
||||
if (options.positionOpts.directionV == 'up') {
|
||||
el.css({ top: 'auto', bottom: yVal });
|
||||
if (options.positionOpts.detectV && !fitVertical(el)) {
|
||||
el.css({ bottom: 'auto', top: yVal });
|
||||
}
|
||||
}
|
||||
else {
|
||||
el.css({ bottom: 'auto', top: yVal });
|
||||
if (options.positionOpts.detectV && !fitVertical(el)) {
|
||||
el.css({ top: 'auto', bottom: yVal });
|
||||
}
|
||||
};
|
||||
|
||||
// and horizontally
|
||||
if (options.positionOpts.directionH == 'left') {
|
||||
el.css({ left: 'auto', right: xVal });
|
||||
if (options.positionOpts.detectH && !fitHorizontal(el)) {
|
||||
el.css({ right: 'auto', left: xVal });
|
||||
}
|
||||
}
|
||||
else {
|
||||
el.css({ right: 'auto', left: xVal });
|
||||
if (options.positionOpts.detectH && !fitHorizontal(el)) {
|
||||
el.css({ left: 'auto', right: xVal });
|
||||
}
|
||||
};
|
||||
|
||||
// if specified, clone the referring element and position it so that it appears on top of the menu
|
||||
if (options.positionOpts.linkToFront) {
|
||||
referrer.clone().addClass('linkClone').css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 'auto',
|
||||
bottom: 'auto',
|
||||
left: 0,
|
||||
width: referrer.width(),
|
||||
height: referrer.height()
|
||||
}).insertAfter(el);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Utilities to sort and find viewport dimensions */
|
||||
|
||||
function sortBigToSmall(a, b) { return b - a; };
|
||||
|
||||
jQuery.fn.getTotalWidth = function(){
|
||||
return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
|
||||
};
|
||||
|
||||
jQuery.fn.getTotalHeight = function(){
|
||||
return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
|
||||
};
|
||||
|
||||
function getScrollTop(){
|
||||
return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
|
||||
};
|
||||
|
||||
function getScrollLeft(){
|
||||
return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
};
|
||||
|
||||
function getWindowHeight(){
|
||||
var de = document.documentElement;
|
||||
return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
|
||||
};
|
||||
|
||||
function getWindowWidth(){
|
||||
var de = document.documentElement;
|
||||
return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
|
||||
};
|
||||
|
||||
/* Utilities to test whether an element will fit in the viewport
|
||||
Parameters:
|
||||
el = element to position, required
|
||||
leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
|
||||
|
||||
function fitHorizontal(el, leftOffset){
|
||||
var leftVal = parseInt(leftOffset) || $(el).offset().left;
|
||||
return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
|
||||
};
|
||||
|
||||
function fitVertical(el, topOffset){
|
||||
var topVal = parseInt(topOffset) || $(el).offset().top;
|
||||
return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* javascript method: "pxToEm"
|
||||
* by:
|
||||
Scott Jehl (scott@filamentgroup.com)
|
||||
Maggie Wachs (maggie@filamentgroup.com)
|
||||
http://www.filamentgroup.com
|
||||
*
|
||||
* Copyright (c) 2008 Filament Group
|
||||
* Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
|
||||
*
|
||||
* Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.
|
||||
* Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
|
||||
* Demo: http://www.filamentgroup.com/examples/pxToEm/
|
||||
*
|
||||
* Options:
|
||||
scope: string or jQuery selector for font-size scoping
|
||||
reverse: Boolean, true reverses the conversion to em-px
|
||||
* Dependencies: jQuery library
|
||||
* Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
|
||||
*
|
||||
* Version: 2.0, 08.01.2008
|
||||
* Changelog:
|
||||
* 08.02.2007 initial Version 1.0
|
||||
* 08.01.2008 - fixed font-size calculation for IE
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
Number.prototype.pxToEm = String.prototype.pxToEm = function(settings){
|
||||
//set defaults
|
||||
settings = jQuery.extend({
|
||||
scope: 'body',
|
||||
reverse: false
|
||||
}, settings);
|
||||
|
||||
var pxVal = (this == '') ? 0 : parseFloat(this);
|
||||
var scopeVal;
|
||||
var getWindowWidth = function(){
|
||||
var de = document.documentElement;
|
||||
return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
|
||||
};
|
||||
|
||||
/* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size.
|
||||
For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size.
|
||||
When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size)
|
||||
to get an accurate em value. */
|
||||
|
||||
if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
|
||||
var calcFontSize = function(){
|
||||
return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
|
||||
};
|
||||
scopeVal = calcFontSize();
|
||||
}
|
||||
else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
|
||||
|
||||
var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
|
||||
return result;
|
||||
};
|
||||
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
2
filemin/unauthenticated/jquery/jquery.min.js
vendored
@@ -1,475 +0,0 @@
|
||||
$( document ).ready(function() {
|
||||
/*
|
||||
$( "input[title]" ).tooltip({
|
||||
position: {
|
||||
my: "left top",
|
||||
at: "right+5 top-5"
|
||||
}
|
||||
});
|
||||
/*
|
||||
$( "a[title]" ).tooltip({
|
||||
position: {
|
||||
my: "bottom center",
|
||||
at: "bottom+30"
|
||||
}
|
||||
});*/
|
||||
$('tr').removeAttr('onmouseover');
|
||||
$('tr').removeAttr('onmouseout');
|
||||
$('input').removeAttr('onclick');
|
||||
$('._select-unselect_').change(function() { selectUnselect($(this)); });
|
||||
|
||||
// BUTTONS
|
||||
$('.fg-button').hover(
|
||||
function(){ $(this).removeClass('ui-state-default').addClass('ui-state-focus'); },
|
||||
function(){ $(this).removeClass('ui-state-focus').addClass('ui-state-default'); }
|
||||
);
|
||||
|
||||
// MENUS
|
||||
$('#flat').menu({
|
||||
content: $('#flat').next().html(), // grab content from this page
|
||||
showSpeed: 100
|
||||
});
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var checkboxes = document.getElementsByClassName('ui_checkbox');
|
||||
for(var i = 0; i < checkboxes.length; i++) {
|
||||
checkboxes[i].onclick = function() {
|
||||
var row = this.parentNode.parentNode;
|
||||
if (this.checked) {
|
||||
row.className = row.className + ' checked';
|
||||
}
|
||||
else {
|
||||
row.className = row.className.replace(' checked', '');
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function countUploads(files) {
|
||||
if(files.files.length = 0) return;
|
||||
var info = '';
|
||||
for (i = 0; i < files.files.length; i++) {
|
||||
info += files.files[i].name + '<br>';
|
||||
}
|
||||
$('#readyForUploadList').html(info);
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
var rows = document.getElementsByClassName('ui_checked_columns');
|
||||
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
var input = rows[i].getElementsByTagName('input')[0];
|
||||
if (!input.checked) {
|
||||
rowClick(rows[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function invertSelection() {
|
||||
var rows = document.getElementsByClassName('ui_checked_columns');
|
||||
|
||||
for (i = 0; i < rows.length; i++)
|
||||
rowClick(rows[i]);
|
||||
}
|
||||
|
||||
function compressDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#compressDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Compress": function() {
|
||||
compressSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function compressSelected() {
|
||||
var filename = $('#compressSelectedForm input[name=filename]').val();
|
||||
if (filename != null && filename != "") {
|
||||
var method = $('#compressSelectedForm select[name=method] option:selected').val();
|
||||
$('#list_form').attr('action', "compress.cgi?arch=" + filename + "&method=" + method);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelected() {
|
||||
if(checkSelected()) {
|
||||
$('#items-to-remove').html('');
|
||||
|
||||
$(".ui_checked_checkbox input[type='checkbox']:checked").each(function() {
|
||||
$('#items-to-remove').append($(this).val() + '<br>');
|
||||
});
|
||||
|
||||
$( "#removeDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"YES": function() {
|
||||
document.forms['list_form'].action = "delete.cgi";
|
||||
document.forms['list_form'].submit();
|
||||
},
|
||||
"NO": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chmodDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#chmodDialog" ).dialog({
|
||||
modal: true,
|
||||
minWidth: 550,
|
||||
buttons: {
|
||||
"Change": function() {
|
||||
chmodSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chmodSelected() {
|
||||
var perms = $('#perms').val();
|
||||
if (perms != null && perms != "") {
|
||||
var applyto = $('#chmodForm select[name=applyto] option:selected').val();
|
||||
$('#list_form').attr('action', "chmod.cgi?perms=" + perms + "&applyto=" + applyto);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
}
|
||||
|
||||
function chownDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#chownDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Change": function() {
|
||||
chownSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function chownSelected() {
|
||||
var owner = $('#chownForm input[name=owner]').val();
|
||||
var group = $('#chownForm input[name=group]').val();
|
||||
var recursive = $('#chown-recursive').prop('checked');
|
||||
|
||||
if (owner != null && owner != "" && group != null && group != "") {
|
||||
$('#list_form').attr('action', "chown.cgi?owner=" + owner + "&group=" + group + "&recursive=" + recursive);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
}
|
||||
|
||||
function chattrDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#chattrDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Change": function() {
|
||||
chattrSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chattrSelected() {
|
||||
var label = $('#chattrForm input[name=label]').val(),
|
||||
recursive = $('#chattr-recursive').prop('checked');
|
||||
|
||||
if (label != null && label != "") {
|
||||
$('#list_form').attr('action', "chattr.cgi?label=" + encodeURIComponent(label) + "&recursive=" + recursive);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function chconDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#chconDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Change": function() {
|
||||
chconSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chconSelected() {
|
||||
var label = $('#chconForm input[name=label]').val(),
|
||||
recursive = $('#chcon-recursive').prop('checked');
|
||||
|
||||
if (label != null && label != "") {
|
||||
$('#list_form').attr('action', "chcon.cgi?label=" + label + "&recursive=" + recursive);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
}
|
||||
|
||||
function aclsDialog() {
|
||||
if(checkSelected()) {
|
||||
$( "#aclsDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Change": function() {
|
||||
aclsSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function aclsSelected() {
|
||||
var aclsForm = $('#aclsForm').serialize();
|
||||
$('#list_form').attr('action', "setfacl.cgi?" + aclsForm);
|
||||
$('#list_form').submit();
|
||||
}
|
||||
|
||||
function renameDialog(file) {
|
||||
$("#renameForm input[name=name]").val(file);
|
||||
$("#renameForm input[name=file]").val(file);
|
||||
$( "#renameDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Rename": function() {
|
||||
renameSelected();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renameSelected() {
|
||||
var name = $('#renameForm input[name=name]').val();
|
||||
var file = $('#renameForm input[name=file]').val();
|
||||
if (name != null && name != "" && name != file) {
|
||||
$('#renameForm').submit();
|
||||
}
|
||||
}
|
||||
|
||||
function copySelected() {
|
||||
if(checkSelected()) {
|
||||
document.forms['list_form'].action = "copy.cgi";
|
||||
document.forms['list_form'].submit();
|
||||
}
|
||||
}
|
||||
|
||||
function cutSelected() {
|
||||
if(checkSelected()) {
|
||||
document.forms['list_form'].action = "cut.cgi";
|
||||
document.forms['list_form'].submit();
|
||||
}
|
||||
}
|
||||
|
||||
function viewReadyForUpload() {
|
||||
$( "#readyForUploadDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"OK": function() {
|
||||
uploadFiles();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function browseForUpload() {
|
||||
var files = document.getElementById('upfiles');
|
||||
files.click();
|
||||
return true;
|
||||
}
|
||||
|
||||
function uploadFiles() {
|
||||
var files = document.getElementById('upfiles');
|
||||
if (files.files.length > 0)
|
||||
$('#upload-form').submit();
|
||||
else
|
||||
files.click();
|
||||
}
|
||||
|
||||
function createFolderDialog() {
|
||||
$( "#createFolderDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Create": function() {
|
||||
createFolder();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
var name = $('#createFolderForm input[name=name]').val();
|
||||
if (name != null && name != "")
|
||||
$("#createFolderForm").submit();
|
||||
else {
|
||||
/* var tooltip = $('#createFolderForm input[name=name]').tooltip({
|
||||
position: {
|
||||
my: "left top",
|
||||
at: "right+5 top-5"
|
||||
}
|
||||
});
|
||||
tooltip.tooltip('open');*/
|
||||
$('#createFolderForm input[name=name]').tooltip('open');
|
||||
}
|
||||
}
|
||||
|
||||
function createFileDialog() {
|
||||
$( "#createFileDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Create": function() {
|
||||
createFile();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFile() {
|
||||
var name = $('#createFileForm input[name=name]').val();
|
||||
if (name != null && name != "") {
|
||||
$("#createFileForm").submit();
|
||||
}
|
||||
}
|
||||
|
||||
function downFromUrlDialog() {
|
||||
$( "#downFromUrlDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Download": function() {
|
||||
downFromUrl();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function downFromUrl() {
|
||||
var link = $('#downFromUrlForm input[name=link]').val();
|
||||
if (link != null && link != "")
|
||||
$('#downFromUrlForm').submit();
|
||||
}
|
||||
|
||||
function selectUnselect(cb) {
|
||||
var rows = $('.ui_checked_columns');
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
switch(cb.is(":checked")) {
|
||||
case true:
|
||||
selectRow(rows[i]);
|
||||
break;
|
||||
case false:
|
||||
unselectRow(rows[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rowClick(row) {
|
||||
var input = row.getElementsByTagName('input')[0];
|
||||
input.checked = !input.checked;
|
||||
if (input.checked) {
|
||||
row.className = row.className + ' checked';
|
||||
}
|
||||
else {
|
||||
row.className = row.className.replace(' checked', '');
|
||||
}
|
||||
}
|
||||
|
||||
function selectRow(row) {
|
||||
var input = row.getElementsByTagName('input')[0];
|
||||
if(!input.checked) {
|
||||
input.checked = true;
|
||||
row.className = row.className + ' checked';
|
||||
}
|
||||
}
|
||||
|
||||
function unselectRow(row) {
|
||||
var input = row.getElementsByTagName('input')[0];
|
||||
if(input.checked) {
|
||||
input.checked = false;
|
||||
row.className = row.className.replace(' checked', '');
|
||||
}
|
||||
}
|
||||
function checkSelected() {
|
||||
var checkboxes = $('.ui_checkbox');
|
||||
for(var i = 0; i < checkboxes.length; i++) {
|
||||
if(checkboxes[i].checked) return true;
|
||||
}
|
||||
$( "#nothingSelected" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"OK": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function searchDialog() {
|
||||
$( "#searchDialog" ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
"Search": function() {
|
||||
search();
|
||||
},
|
||||
"Cancel": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function search() {
|
||||
var query = $('#searchForm input[name=query]').val();
|
||||
if (query != null && query != "")
|
||||
$("#searchForm").submit();
|
||||
}
|
||||
|
||||
/*
|
||||
function checkSelected() {
|
||||
var checkboxes = document.getElementsByClassName('ui_checkbox');
|
||||
for(var i = 0; i < checkboxes.length; i++) {
|
||||
if(checkboxes[i].checked) return true;
|
||||
}
|
||||
alert('Nothing selected');
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
183
filemin/unauthenticated/js/plain.js
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* plain.js
|
||||
* Behavior of the File Manager for themes without Bootstrap, on top of
|
||||
* the core widget script : row selection, the selection check before an
|
||||
* action on the selected entries, sending the selection form to an
|
||||
* action script with a dialog's fields as parameters, the rename and
|
||||
* delete dialogs, the permissions calculator and the upload options.
|
||||
* Everything is delegated from the document, keyed off data-filemin-*
|
||||
* attributes, so no handlers are generated in the markup.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var widgets = window.webminUiWidgets;
|
||||
|
||||
// The selection form and its row checkboxes
|
||||
function listForm() {
|
||||
return document.getElementById('list_form');
|
||||
}
|
||||
function rowBoxes() {
|
||||
var form = listForm();
|
||||
return form ? Array.prototype.slice.call(
|
||||
form.querySelectorAll('input[type="checkbox"][name="name"]')) : [];
|
||||
}
|
||||
function selectedBoxes() {
|
||||
return rowBoxes().filter(function (box) { return box.checked; });
|
||||
}
|
||||
function selectRows(mode) {
|
||||
rowBoxes().forEach(function (box) {
|
||||
box.checked = mode === 'all' ? true :
|
||||
mode === 'none' ? false : !box.checked;
|
||||
});
|
||||
}
|
||||
|
||||
// Called by the checkbox in the table heading
|
||||
window.selectUnselect = function (master) {
|
||||
selectRows(master.checked ? 'all' : 'none');
|
||||
};
|
||||
// Called by the rename link of a row, with the entry's name
|
||||
window.renameDialog = function (file) {
|
||||
widgets.openDialog('filemin_rename', { name: file, file: file });
|
||||
};
|
||||
|
||||
// Send the selection form to a script, with parameters in its URL
|
||||
function submitSelection(script, params) {
|
||||
var form = listForm();
|
||||
if (!form) return;
|
||||
var url = script;
|
||||
var query = params ? params.toString() : '';
|
||||
if (query) url += (url.indexOf('?') >= 0 ? '&' : '?') + query;
|
||||
form.setAttribute('action', url);
|
||||
form.submit();
|
||||
}
|
||||
// The named, enabled fields of a dialog form as URL parameters,
|
||||
// leaving out the calculator's own fields
|
||||
function formParams(form) {
|
||||
var params = new URLSearchParams();
|
||||
Array.prototype.forEach.call(form.elements, function (field) {
|
||||
if (!field.name || field.disabled ||
|
||||
field.hasAttribute('data-filemin-skip')) return;
|
||||
if (/^(?:file|submit|button|reset)$/.test(field.type)) return;
|
||||
if ((field.type === 'checkbox' || field.type === 'radio') &&
|
||||
!field.checked) return;
|
||||
if (field.tagName === 'SELECT' && field.multiple) {
|
||||
Array.prototype.forEach.call(field.options, function (option) {
|
||||
if (option.selected) params.append(field.name, option.value);
|
||||
});
|
||||
return;
|
||||
}
|
||||
params.append(field.name, field.value);
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
// Toolbar entries : selecting rows, actions that need a selection,
|
||||
// and actions that send the selection straight to a script. Caught
|
||||
// before the widget script, so a dialog is not opened for an empty
|
||||
// selection.
|
||||
document.addEventListener('click', function (e) {
|
||||
var control = e.target.closest && e.target.closest(
|
||||
'[data-filemin-select], [data-filemin-selection], [data-filemin-submit]');
|
||||
if (!control) return;
|
||||
if (control.hasAttribute('data-filemin-select')) {
|
||||
e.preventDefault();
|
||||
selectRows(control.getAttribute('data-filemin-select'));
|
||||
return;
|
||||
}
|
||||
if (control.hasAttribute('data-filemin-selection') && !selectedBoxes().length) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
widgets.openDialog('filemin_nothing');
|
||||
return;
|
||||
}
|
||||
var script = control.getAttribute('data-filemin-submit');
|
||||
if (script) {
|
||||
e.preventDefault();
|
||||
submitSelection(script);
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.addEventListener('submit', function (e) {
|
||||
var form = e.target;
|
||||
if (!form.getAttribute) return;
|
||||
// A dialog acting on the selection : its fields become the
|
||||
// parameters of the action script
|
||||
var script = form.getAttribute('data-filemin-apply');
|
||||
if (script) {
|
||||
e.preventDefault();
|
||||
var dialog = form.closest('dialog');
|
||||
if (dialog && dialog.open) dialog.close();
|
||||
submitSelection(script, formParams(form));
|
||||
return;
|
||||
}
|
||||
// An upload : the options go in the URL, which the server reads
|
||||
// before the files arrive, and progress is shown in a popup
|
||||
var upload = form.getAttribute('data-filemin-upload');
|
||||
if (upload) {
|
||||
var action = upload;
|
||||
form.querySelectorAll('[data-filemin-upload-option]').forEach(function (box) {
|
||||
if (box.checked) {
|
||||
action += '&' + box.getAttribute('data-filemin-upload-option') + '=1';
|
||||
}
|
||||
});
|
||||
form.setAttribute('action', action);
|
||||
var tracker = form.getAttribute('data-filemin-tracker');
|
||||
if (tracker) {
|
||||
window.open(tracker, 'uptracker',
|
||||
'toolbar=no,menubar=no,scrollbars=no,location=no,resizable=no,' +
|
||||
'width=' + window.screen.width + ',height=' + window.screen.height);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Directory upload : the file input picks directories instead
|
||||
document.addEventListener('change', function (e) {
|
||||
var box = e.target;
|
||||
if (box.matches && box.matches('[data-filemin-upload-dirs]')) {
|
||||
var input = box.form && box.form.querySelector('input[type="file"]');
|
||||
if (input) input.toggleAttribute('webkitdirectory', box.checked);
|
||||
}
|
||||
});
|
||||
|
||||
// The delete dialog lists the selected entries as it opens
|
||||
document.addEventListener('ui-dialog-open', function (e) {
|
||||
if (e.target.id !== 'filemin_delete') return;
|
||||
var list = e.target.querySelector('#filemin_delete_items');
|
||||
if (list) {
|
||||
list.textContent = selectedBoxes().map(function (box) {
|
||||
return box.value;
|
||||
}).join('\n');
|
||||
}
|
||||
});
|
||||
|
||||
// Permissions : the octal field, the checkbox matrix and the hidden
|
||||
// perms parameter stay in step through the shared calculator
|
||||
function syncPerms(fromMatrix) {
|
||||
var form = document.forms['chmod'];
|
||||
if (!form || typeof window.calc_chmod !== 'function') return;
|
||||
if (fromMatrix) {
|
||||
window.calc_chmod();
|
||||
}
|
||||
else if (/^[0-7]{4}$/.test(form.t_total.value) &&
|
||||
typeof window.octalchange === 'function') {
|
||||
window.octalchange();
|
||||
}
|
||||
var perms = form.querySelector('input[name="perms"]');
|
||||
if (perms) perms.value = form.t_total.value;
|
||||
}
|
||||
document.addEventListener('input', function (e) {
|
||||
if (e.target.matches && e.target.matches('[data-filemin-chmod-octal]')) {
|
||||
syncPerms(false);
|
||||
}
|
||||
});
|
||||
document.addEventListener('change', function (e) {
|
||||
if (e.target.matches && e.target.matches('[data-filemin-chmod]')) {
|
||||
syncPerms(true);
|
||||
}
|
||||
});
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function () { syncPerms(false); });
|
||||
} else {
|
||||
syncPerms(false);
|
||||
}
|
||||
})();
|
||||
@@ -1,246 +0,0 @@
|
||||
<div id="nothingSelected" class="modal">
|
||||
<h3>$text{'nothing_selected'}</h3>
|
||||
</div>
|
||||
|
||||
<div id="createFolderDialog" class="modal">
|
||||
<form id="createFolderForm" action="create_folder.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label>$text{'new_folder_name'}</label>
|
||||
<input id="name" name="name" type="text" title="$text{'provide_folder_name'}">
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="createFileDialog" class="modal">
|
||||
<form id="createFileForm" action="create_file.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label>$text{'new_file_name'}</label>
|
||||
<input name="name" type="text">
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="renameDialog" class="modal">
|
||||
<form id="renameForm" action="rename.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label>$text{'new_name'}</label>
|
||||
<input name="name" type="text">
|
||||
<input type='hidden' name='file' value='' required>
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="compressDialog" class="modal">
|
||||
<form id="compressSelectedForm" action="compress.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label>$text{'archive_name'}</label>
|
||||
<input name="filename" type="text">
|
||||
<select name="method">
|
||||
<option value="plain-tar">.tar</option>
|
||||
<option value="xz-tar">.tar.xz</option>
|
||||
<option selected value="tar">.tar.gz</option>
|
||||
<option value="zstd-tar">.zstd</option>
|
||||
<option value="zip">.zip</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="removeDialog" class="modal">
|
||||
<p>$text{'about_to_delete'}</p>
|
||||
<pre id="items-to-remove">
|
||||
</pre>
|
||||
$text{'are_you_sure'}
|
||||
</div>
|
||||
|
||||
<div id="chownDialog" class="modal">
|
||||
<form id="chownForm">
|
||||
<div class="form-group">
|
||||
<label>$text{'user_name'}</label><br>
|
||||
<input name="owner" type="text"><br>
|
||||
<label>$text{'group_name'}</label><br>
|
||||
<input name="group" type="text"><br><br>
|
||||
<label>$text{'dialog_recursive'}</label>
|
||||
<input id="chown-recursive" type="checkbox" name="recursive">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="chattrDialog" class="modal">
|
||||
<form id="chattrForm">
|
||||
<div class="form-group">
|
||||
<label>$text{'attr_label'}</label><br>
|
||||
<input name="label" type="text"><br><br>
|
||||
<label>$text{'dialog_recursive'}</label>
|
||||
<input id="chattr-recursive" type="checkbox" name="recursive">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="chconDialog" class="modal">
|
||||
<form id="chconForm">
|
||||
<div class="form-group">
|
||||
<label>$text{'context_label'}</label><br>
|
||||
<input name="label" type="text"><br><br>
|
||||
<label>$text{'dialog_recursive'}</label>
|
||||
<input id="chcon-recursive" type="checkbox" name="recursive">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="aclsDialog" class="modal">
|
||||
<form id="aclsForm">
|
||||
<div class="form-group">
|
||||
<label>$text{'acls_action'}</label><br>
|
||||
<select name="action">
|
||||
<option value=""></option>
|
||||
<option selected value="-m">Modify (-m)</option>
|
||||
<option value="-x">Remove (-x)</option>
|
||||
<option value="-b">Remove all extended (-b)</option>
|
||||
<option value="-k">Remove default (-k)</option>
|
||||
</select><br><br>
|
||||
|
||||
<label>$text{'acls_applyto'}</label><br>
|
||||
<select multiple size=4 name="apply_to">
|
||||
<option value="u">$text{'acls_user'}</option>
|
||||
<option value="g">$text{'acls_group'}</option>
|
||||
<option value="m">$text{'acls_mask'}</option>
|
||||
<option value="o">$text{'acls_other'}</option>
|
||||
</select><br><br>
|
||||
|
||||
<label>$text{'acls_perms'}</label><br>
|
||||
<select name="perms">
|
||||
<option value=""></option>
|
||||
<option value="---">---</option>
|
||||
<option value="r--">r--</option>
|
||||
<option value="-w-">-w-</option>
|
||||
<option value="--x">--x</option>
|
||||
<option value="r-x">r-x</option>
|
||||
<option value="rw-">rw-</option>
|
||||
<option value="-wx">-wx</option>
|
||||
<option value="rwx">rwx</option>
|
||||
</select><br><br>
|
||||
|
||||
<label>$text{'acls_user'}</label><br>
|
||||
$acl_user_select<br><br>
|
||||
|
||||
<label>$text{'acls_group'}</label><br>
|
||||
$acl_group_select<br><br>
|
||||
|
||||
<label>$text{'dialog_recursive'}</label>
|
||||
<input id="acls-recursive" type="checkbox" name="recursive">
|
||||
|
||||
<br><br>
|
||||
$acl_manual
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="downFromUrlDialog" class="modal">
|
||||
<form id="downFromUrlForm" action="http_download.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label style="display: block;">$text{'dialog_file_url'} <sup class="text-danger"> *</sup><br>
|
||||
<input name="link" type="url" data-placement="top" data-content="$text{'provide_url'}" data-trigger="manual" autocomplete="url" style="font-weight: normal;">
|
||||
</label>
|
||||
<label style="display: block;">$text{'dialog_user_name'}<br>
|
||||
<input name="username" type="text" autocomplete="off" style="font-weight: normal;">
|
||||
</label>
|
||||
<label style="display: block;">$text{'dialog_user_pass'}<br>
|
||||
<input name="password" type="password" autocomplete="new-password" style="font-weight: normal;">
|
||||
</label>
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="readyForUploadDialog" class="modal">
|
||||
<form id='upload-form' method='post' onsubmit="this.extract_upload.checked=false" action='upload.cgi?path=$urlized_path&id=$upid' enctype='multipart/form-data' onsubmit='window.open("@{[&get_webprefix()]}/uptracker.cgi?id=$upid&uid=$uid", "uptracker", "toolbar=no, menubar=no, scrollbars=no, location=no, resizable=no, width=screen.width, height=screen.height")'>
|
||||
<input type='file' id='upfiles' name='upfiles' multiple onchange='countUploads(this)'>
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
<br>
|
||||
<br>
|
||||
<input type="checkbox" id="filetype" onchange="this.parentElement.querySelector('#upfiles').toggleAttribute('webkitdirectory')"><label for="filetype"> $text{'upload_dirs'}</label>
|
||||
<br>
|
||||
<input type="checkbox" id="extract_upload" onchange="t=document.querySelector('#upload-form'),v=t.getAttribute('action'),x='&extract_uploaded=1',this.checked?t.setAttribute('action', t.getAttribute('action') + x):t.setAttribute('action',t.getAttribute('action').replace(x,''))"><label for="extract_upload"> $text{'extract_uploaded'}</label>
|
||||
<br>
|
||||
<input type="checkbox" id="overwrite_existing" onchange="t=document.querySelector('#upload-form'),v=t.getAttribute('action'),x='&overwrite_existing=1',this.checked?t.setAttribute('action', t.getAttribute('action') + x):t.setAttribute('action',t.getAttribute('action').replace(x,''))"><label for="overwrite_existing"> $text{'overwrite_existing'}</label>
|
||||
</form>
|
||||
<div id="readyForUploadList" class="well" style="max-height: 180px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chmodDialog" class="modal fade">
|
||||
<form name="chmod" id="chmodForm">
|
||||
<div class="form-group">
|
||||
<label for="t_total">$text{'permissions'}: </label><br>
|
||||
<input id="perms" type="text" oninput="if(this.value.length>4)this.value=this.value.slice(0,4)" name="t_total" value="0644" size="4" onKeyUp="octalchange()" class="form-group-item">
|
||||
<input type="text" name="sym_total" value="" size="12" readonly="true" class="form-group-item">
|
||||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><b>$text{'chmod_owner'}</b></th>
|
||||
<th><b>$text{'chmod_group'}</b></th>
|
||||
<th><b>$text{'chmod_others'}<b></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$text{'chmod_read'}</td>
|
||||
<td><input type="checkbox" name="owner4" value="4" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="group4" value="4" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="other4" value="4" onchange="calc_chmod()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$text{'chmod_write'}</td>
|
||||
<td><input type="checkbox" name="owner2" value="2" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="group2" value="2" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="other2" value="2" onchange="calc_chmod()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$text{'chmod_execute'}</td>
|
||||
<td><input type="checkbox" name="owner1" value="1" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="group1" value="1" onchange="calc_chmod()"></td>
|
||||
<td><input type="checkbox" name="other1" value="1" onchange="calc_chmod()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>----------</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$text{'chmod_sticky'}</td>
|
||||
<td><input type="checkbox" name="sticky" value="1" onchange="calc_chmod()"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$text{'chmod_setgid'}</td>
|
||||
<td><input type="checkbox" name="setgid" value="2" onchange="calc_chmod()"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<label>$text{'chmod_apply_to'}: </label>
|
||||
<select name="applyto">
|
||||
<option value="1">$text{'chmod_dir_only'}</option>
|
||||
<option value="2">$text{'chmod_dir_and_its_files'}</option>
|
||||
<option value="3">$text{'chmod_all'}</option>
|
||||
<option value="4">$text{'chmod_dir_files_and_subs_files'}</option>
|
||||
<option value="5">$text{'chmod_dir_and_subs'}</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="searchDialog" class="modal">
|
||||
<form id="searchForm" action="search.cgi" method="post">
|
||||
<div class="form-group">
|
||||
<label>$text{'search_label'}</label>
|
||||
<input id="query" name="query" type="text" title="$text{'provide_search_query'}"><br><br>
|
||||
<input id="caseins" name="caseins" type="checkbox" checked="checked"> $text{'search_insensitive'}
|
||||
<input type='hidden' name='path' value='$quote_escaped_path'>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,29 +0,0 @@
|
||||
<div id="quicks" style="float:right">
|
||||
<a href="javascript:void(0)" onclick='searchDialog()' title="$text{'search'}"><img src='images/icons/quick/edit-find.png' alt="$text{'search'}" /></a>
|
||||
<a href="bookmark.cgi?path=$urlized_path" title="$text{'bookmark_folder'}"><img src='images/icons/quick/bookmark-new.png' alt="$text{'bookmark_folder'}" /></a>
|
||||
<a tabindex="0" class="fg-button fg-button-icon-right ui-widget ui-state-default ui-corner-all" id="flat">
|
||||
<img src="images/icons/quick/go-down.png" alt="$text{'config_bookmarks'}">
|
||||
</a>
|
||||
<div id="bookmarks" class="ui-helper-hidden">
|
||||
<ul>
|
||||
$bookmarks
|
||||
</ul>
|
||||
</div>
|
||||
<a href="javascript:void(0)" onclick='selectAll()' title="$text{'select_all'}"><img src='images/icons/quick/select-all.png' alt="$text{'select_all'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='invertSelection()' title="$text{'invert_selection'}"><img src='images/icons/quick/invert.png' alt="$text{'invert_selection'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='copySelected()' title="$text{'copy_selected'}"><img src='images/icons/quick/edit-copy.png' alt="$text{'copy_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='cutSelected()' title="$text{'cut_selected'}"><img src='images/icons/quick/edit-cut.png' alt="$text{'cut_selected'}" /></a>
|
||||
<a href='paste.cgi?path=$urlized_path' title="$text{'paste'}"><img src='images/icons/quick/edit-paste.png' alt="$text{'paste'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='createFolderDialog()' title="$text{'create_folder'}"><img src='images/icons/quick/folder-new.png' alt="$text{'create_folder'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='createFileDialog()' title="$text{'create_file'}"><img src='images/icons/quick/document-new.png' alt="$text{'create_file'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='compressDialog()' title="$text{'compress_selected'}"><img src='images/icons/quick/compress.png' alt="$text{'compress_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='chmodDialog()' title="$text{'chmod_selected'}"><img src='images/icons/quick/chmod.png' alt="$text{'chmod_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='chownDialog()' title="$text{'chown_selected'}"><img src='images/icons/quick/chown.png' alt="$text{'chown_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='chattrDialog()' title="$text{'chattr_selected'}"><img src='images/icons/quick/chattr.png' alt="$text{'chattr_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='chconDialog()' title="$text{'chcon_selected'}"><img src='images/icons/quick/chcon.png' alt="$text{'chcon_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='aclsDialog()' title="$text{'acls_selected'}"><img src='images/icons/quick/acls.png' alt="$text{'acls_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='removeSelected()' title="$text{'remove_selected'}"><img src='images/icons/quick/remove.png' alt="$text{'remove_selected'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='viewReadyForUpload()' title="$text{'upload_files'}"><img src='images/icons/quick/upload.png' alt="$text{'upload_files'}" /></a>
|
||||
<a href="javascript:void(0)" onclick='downFromUrlDialog()' title="$text{'get_from_url'}"><img src='images/icons/quick/from-url.png' alt="$text{'get_from_url'}" /></a>
|
||||
</div>
|
||||
<div id="info" style="float:right"></div>
|
||||
@@ -1,67 +0,0 @@
|
||||
<div class="btn-group pull-right" role="group">
|
||||
<button class="btn btn-inverse" onclick='searchDialog()' title="$text{'search'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-search" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick="location.href='bookmark.cgi?path=$urlized_path'" title="$text{'bookmark_folder'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-bookmark-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-inverse dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="$text{'config_bookmarks'}">
|
||||
<i class="fa fa-book" aria-hidden="true"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
$bookmarks
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn btn-inverse" onclick='window.location.href="index.cgi?path=$urlized_path"' title="$text{'refresh'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='selectAll()' title="$text{'select_all'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-check-square-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='invertSelection()' title="$text{'invert_selection'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-check-square" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='copySelected()' title="$text{'copy_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-copy" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='cutSelected()' title="$text{'cut_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-cut" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick="location.href='paste.cgi?path=$urlized_path'" title="$text{'paste'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-paste" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='createFolderDialog()' title="$text{'create_folder'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-folder-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='createFileDialog()' title="$text{'create_file'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-file-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='compressDialog()' title="$text{'compress_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-file-archive-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='chmodDialog()' title="$text{'chmod_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-gears" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='chownDialog()' title="$text{'chown_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-users" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='chattrDialog()' title="$text{'chattr_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-tags" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='chconDialog()' title="$text{'chcon_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-shield" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='aclsDialog()' title="$text{'acls_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-account-key" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='removeDialog()' title="$text{'remove_selected'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-trash-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='viewReadyForUpload()' title="$text{'upload_files'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-upload" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-inverse" onclick='downFromUrlDialog()' title="$text{'get_from_url'}" data-toggle="tooltip" data-placement="bottom" data-container="body">
|
||||
<i class="fa fa-globe" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||