Menu="Buttons:3a"
Title="File Manager"
Icon="icon-u-duplicate"
Code="e963"
---
<?PHP
/* Copyright 2005-2025, Lime Technology
 * Copyright 2012-2025, Bergware International.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */
?>
<?
$dfm = [
  'browser' => $myPage['name'] == 'Browse',
  'running' => file_exists('/var/tmp/file.manager.active'),
  'jobs'    => file_exists('/var/tmp/file.manager.jobs'),
  'zfs'     => is_executable('/usr/sbin/zfs')
];
if ($dfm['running'] || $dfm['browser']) eval('?>'.parse_file("$docroot/webGui/include/Templates.php"));
?>
<script>
function BrowseButton() {
  location.replace('/<?=$task?>/Browse?dir=/mnt');
}

// Prototypes
String.prototype.dfm_patch = function(){return this.replace('rw','x+rw').replace('r-','wx+r').replace('--','rwx');}
String.prototype.dfm_proxy = function(){return this.replace('name','row');}
String.prototype.dfm_fetch = function(tag){return this.replace('check',tag);}
String.prototype.dfm_bring = function(tag){return this.replace('row',tag);}
String.prototype.dfm_strip = function(){return this.replace(/\/$/,'');}
String.prototype.dfm_quote = function(){return this.replace(/&#34;/g,'"');}
String.prototype.dfm_alter = function(...a){var t=this;for(var i=0;i<a.length;i+=2){t=t.replace(a[i],a[i+1]);} return t;}
String.prototype.dfm_build = function(){return this.replace(/\n(<!--!|!-->)\n/g,'');}
String.prototype.dfm_wedge = function(len){len=len||70;return this.length<=len ? this : this.slice(0,Math.round(len/2)-2)+'...'+this.slice(-1-Math.round(len/2));}

// General variables
const dfm = {
  window: null,
  dialog: false,
  running: false,
  draggable:  false,
  previous: '',
  height: 0,
  tsize: {0: 0, 1: 6, 2: 3, 3: 3, 4: 3, 11: 2, 12: 2, 14: 0, 15: 3},
};
var dfm_read = {};

function dfm_footer(action, text) {
  switch (action) {
  case 'show':
    $('#user-notice').show();
    break;
  case 'hide':
    $('#user-notice').hide();
    break;
  case 'write':
    let icon = '<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>';
    $('#user-notice').html(icon + text);
    break;
  case 'clear':
    $('#user-notice').html('');
    break;
  }
}

function dfm_done() {
  dfm_footer('write', "<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
}

function dfm_minimize() {
  dfm.window.dialog('close');
  dfm_footer('show');
}

function dfm_close_button() {
  $('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-window-minimize"></i>').prop({'title':"_(Minimize)_"}).prop('onclick',null).off('click').click(function(){dfm_minimize();}).show();
}

function dfm_htmlspecialchars(text) {
  var map = {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'};
  return text.replace(/[&<>"']/g, function(m){return map[m];});
}

function dfm_escapeHTML(name) {
  const data = document.createElement('div');
  const text = document.createTextNode(name);
  data.appendChild(text);
  return data.innerHTML;
}

function dfm_createSource(source) {
  var select = dfm.window.find('#dfm_source');
  if (Array.isArray(source)) {
    for (var i=0,object; object=source[i]; i++) {
      if (i < 10) {
        select.html(select.html()+'<option'+(i==0?' selected':'')+'>'+object+'</option>');
      } else {
        select.html(select.html()+'<option>&lt;_(more)_&gt; ...</option>');
        break;
      }
    }
  } else {
    select.html('<option selected>'+source+'</option>');
  }
}

function dfm_showProgress(data) {
  if (!data) return 0;
  let file = null;
  let text = data.split('\n');
  let line = text[0].split('... ');
  let strict = /^mnt|^boot/;
  let footer = false;
  if (text[0] == '#cat#') {
    let loc = [], cat = [];
    for (let i=1,row; row=text[i]; i++) {
      if (!row) continue;
      row = row.split('\0');
      loc.push(row[0]);
      cat.push(row[1].dfm_wedge(80));
    }
    if (cat.length > 0) {
      dfm.window.find('.dfm_loc').html(loc.join('<br>'));
      dfm.window.find('.dfm_text').html(cat.join('<br>'));
      dfm.window.find('#dfm_files').html(loc.length+" "+"_(files)_");
    }
    return cat.length;
  } else if (text.length == 1) {
    text = text[0].dfm_wedge(80);
    footer = text.indexOf("_(Searching)_") != -1;
  } else {
    if (strict.test(text[1])) {
      file = text[1];
      text = dfm.previous;
    } else {
      file = line[1];
      text = text[1].split(/\s+/);
      text = "<i class='fa fa-circle-o-notch fa-spin dfm'></i>_(Completed)_: "+text[1]+",&nbsp;&nbsp;_(Speed)_: "+text[2]+",&nbsp;&nbsp;_(ETA)_: "+text[3];
      dfm.previous = text;
      footer = true;
    }
  }
  if (file == null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
  if (footer) dfm_footer('write',text);
  return 0;
}

function dfm_fileManager(action) {
  switch (action) {
  case 'start':
    $('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
<?if ($dfm['browser']):?>
    $('.dfm_control').prop('disabled',true);
    $('.dfm_control.jobs').prop('disabled',$.cookie('dfm_control.jobs')?false:true);
<?endif;?>
    if (!dfm.running) nchan_filemanager.start();
    dfm.running = true;
    break;
  case 'stop':
    if (dfm.running) nchan_filemanager.stop();
<?if ($dfm['browser']):?>
    dfm.window.find('.dfm_text').removeClass('orange-text').html('');
    $('.dfm_control.basic').prop('disabled',false);
    $('.dfm_control.common').prop('disabled',$.cookie('dfm_control.common')?true:false);
<?endif;?>
    dfm_footer('clear');
    dfm.running = false;
    break;
  }
}

function dfm_makeDialog(open) {
  if (open && dfm_read.action == 15) {
    dfm.window.dialog('open');
    dfm_footer('hide');
    return;
  }
  dfm.window = $('#dfm_dialogWindow');
  if (dfm.window.dialog('instance') !==  undefined) dfm.dialog = dfm.window.dialog('isOpen');
  var dfm_source = dfm_read.source.split('\r').slice(0,9);
  switch (dfm_read.action) {
  case 0: // create folder/object
    dfm.window.html($('#dfm_templateCreateFolder').html());
    dfm.height = 330;
    break;
  case 1: // delete folder/object
    dfm.window.html($('#dfm_templateDeleteFolder').html());
    dfm.height = 330;
    break;
  case 2: // rename folder/object
    dfm.window.html($('#dfm_templateRenameFolder').html());
    dfm.window.find('#dfm_target').val(dfm_read.target.strip().split('/').pop());
    dfm.height = 330;
    break;
  case 3: // copy folder/object
    dfm.window.html($('#dfm_templateCopyFolder').html());
    dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
    dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
    dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
    dfm.height = 630;
    break;
  case 4: // move folder/object (rsync)
  case 5: // move folder/object (mv)
    dfm.window.html($('#dfm_templateMoveFolder').html());
    dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
    dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
    dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
    dfm.height = 630;
    break;
  case 6: // delete file
    dfm.window.html($('#dfm_templateDeleteFile').html());
    dfm.height = 330;
    break;
  case 8: // copy file
    dfm.window.html($('#dfm_templateCopyFile').html());
    dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
    dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
    dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
    dfm.height = 630;
    break;
  case 9: // move file (rsync)
  case 10: // move file (mv)
    dfm.window.html($('#dfm_templateMoveFile').html());
    dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
    dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true :false);
    dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
    dfm.height = 630;
    break;
  case 11: // change owner
    dfm.window.html($('#dfm_templateChangeOwner').html());
    dfm.window.find('#dfm_target').prop('disabled',true);
    dfm.height = 330;
    break;
  case 12: // change permission
    dfm.window.html($('#dfm_templateChangePermission').html());
    dfm.window.find('#dfm_owner').prop('disabled',true);
    dfm.window.find('#dfm_group').prop('disabled',true);
    dfm.window.find('#dfm_other').prop('disabled',true);
    dfm.height = 330;
    break;
  case 15: // search
    dfm.window.html($('#dfm_templateSearch').html());
    dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
    dfm.window.find('.dfm_loc').html('&nbsp;').css({'line-height':'normal'});
    dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
    dfm.height = 630;
    break;
  }
  dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[dfm_read.action],dfm_source.length));
  dfm_createSource(dfm_source);
  dfm.window.find('#dfm_sparse').prop('disabled',true);
  dfm.window.find('#dfm_exist').prop('disabled',true);
  dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
  dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
  dfm.window.dialog({
    classes: {'ui-dialog': 'ui-dfm'},
    autoOpen: open || dfm.dialog,
    title: dfm_read.title,
    height: dfm.height,
    width: 'auto',
    resizable: false,
    draggable: false,
    modal: true,
    buttons: {
      "_(Start)_": function(){
        if (dfm_read.action == 15) {
          var dfm_target = dfm.window.find('#dfm_target').val();
          dfm.window.find('.dfm_loc').html('&nbsp;');
          dfm.window.find('.dfm_text').html("_(Running)_...");
          dfm_footer('hide');
          dfm_fileManager('start');
          $.post('/webGui/include/Control.php',{mode:'file',action:15,title:encodeURIComponent(dfm_read.title),source:encodeURIComponent(dfm_read.source),target:encodeURIComponent(dfm_target),hdlink:'',sparse:'',exist:'',zfs:''});
        } else {
          return;
        }
      },
      "_(Queue)_": function(){
        return;
      },
      "_(Cancel)_": function(){
        dfm_fileManager('stop');
        dfm.window.dialog('destroy');
        $.post('/webGui/include/Control.php',{mode:'file',action:99},function(){<?if ($dfm['browser']):?>setTimeout(loadList,500);<?endif;?>});
      }
    }
  });
  dfm_close_button();
  $('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
  setTimeout(function(){$('.ui-dfm .ui-dialog-buttonset button:eq(2)').focus();});
  if (open||dfm.dialog) dfm_footer('hide'); else dfm_footer('show');
}

function dfm_openDialog(open) {
  $.post('/webGui/include/Control.php',{mode:'read'},function(data){
    if (data) {
      dfm_read = JSON.parse(data);
      dfm_read.action = parseInt(dfm_read.action);
    }
    dfm_makeDialog(open);
  });
}

var nchan_filemanager = new NchanSubscriber('/sub/filemanager',{subscriber:'websocket'});
nchan_filemanager.on('message', function(msg) {
  let data = $.parseJSON(msg);
  if (data.error) {
    dfm_fileManager('stop');
    dfm.window.find('.dfm_text').addClass('orange-text').html(data.error);
    dfm.window.find('#dfm_target').prop('disabled',false);
    dfm.window.find('#dfm_sparse').prop('disabled',false);
    dfm.window.find('#dfm_exist').prop('disabled',false);
    dfm.window.find('#dfm_owner').prop('disabled',false);
    dfm.window.find('#dfm_group').prop('disabled',false);
    dfm.window.find('#dfm_other').prop('disabled',false);
    $('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',false);
  } else {
    let cat = dfm_showProgress(data.status);
    if (data.done == 1) {
      setTimeout(function(){$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
        switch (parseInt(queue)) {
        case 0:
          dfm_fileManager('stop');
          dfm.window.dialog('destroy');
<?if ($dfm['browser']):?>
          setTimeout(loadList);
<?endif;?>
          break;
        case 1:
<?if ($dfm['browser']):?>
          $('.dfm_control.jobs').prop('disabled',true);
<?endif;?>
          $.removeCookie('dfm_control.jobs');
        case 2:
          dfm_openDialog();
          break;
        }
      })});
    } else if (data.done == 2) {
      nchan_filemanager.stop();
      dfm.running = false;
      dfm.window.find('#dfm_target').prop('disabled',false).focus();
      $('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',false);
      if (cat == 0) dfm.window.find('.dfm_text').html("_(No results found)_");
      if ($('#user-notice:visible')) dfm_done();
    }
  }
});

<?if ($dfm['running']):?>
$(function(){
  dfm_openDialog();
  dfm_fileManager('start');
});
<?endif;?>
</script>
