file_operation.html 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. <html>
  2. <head>
  3. <title locale="title">File Operation</title>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
  6. <link rel="stylesheet" href="../../script/semantic/semantic.min.css">
  7. <script type="text/javascript" src="../../script/jquery.min.js"></script>
  8. <script type="text/javascript" src="../../script/semantic/semantic.min.js"></script>
  9. <script type="text/javascript" src="../../script/ao_module.js"></script>
  10. <script type="text/javascript" src="../../script/applocale.js"></script>
  11. <style>
  12. body{
  13. overflow: hidden;
  14. }
  15. .banner{
  16. /*background-color:#2b4871;*/
  17. background: rgb(43,72,113);
  18. background: linear-gradient(153deg, rgba(43,72,113,1) 43%, rgba(141,146,147,1) 100%);
  19. height:50px;
  20. padding:12px;
  21. padding-left:20px;
  22. padding-top:16px;
  23. }
  24. #opricon{
  25. position:absolute;
  26. top:0px;
  27. right:0px;
  28. width:80px;
  29. height:80px;
  30. }
  31. .title{
  32. color:white;
  33. font-size:130%;
  34. }
  35. .content{
  36. padding:12px;
  37. }
  38. .info{
  39. margin-top:3px;
  40. white-space: nowrap;
  41. overflow: hidden;
  42. text-overflow: ellipsis;
  43. }
  44. </style>
  45. </head>
  46. <body>
  47. <div class="banner">
  48. <div class="title" locale="banner/title">Calculating Operation</div>
  49. <img id="opricon" src="img/loading.png" class="ui image"></img>
  50. </div>
  51. <div class="content">
  52. <div class="info"><span locale="info/from">From:</span> <span id="src"></span></div>
  53. <div class="info"><span locale="info/to">To:</span> <span id="dest"></span></div>
  54. <div class="info"><span locale="info/progress">Progress:</span> <span id="progress"> <i class="loading spinner icon"></i> <span>Calculating</span></div>
  55. <div class="ui active small progress" style="margin-top:18px;">
  56. <div id="progressbar" class="bar" style="width:100%; background-color:#4287f5;"></div>
  57. </div>
  58. <div id="advanceControlbtns" class="ui right floated small buttons" style="margin-top: -2em; display: none;">
  59. <div id="pauseButton" locale="button/pause" class="ui basic grey button" onclick="togglePauseTask();">Pause</div>
  60. <div id="cancelButton" class="ui basic red button" locale="button/cancel" onclick="cancelTask();">Cancel</div>
  61. </div>
  62. </div>
  63. <div class="ui modal" id="duplicateAction">
  64. <div class="content">
  65. <div class="description" style="padding: 0px !important;">
  66. <p><i class="big exclamation triangle icon"></i> <span locale="dup/question">File with same name already exists. <b>Which action should be taken?</b></span></p><br>
  67. </div>
  68. </div>
  69. <div class="actions">
  70. <div locale="dup/overwrite" class="ui labeled button" onclick="continueProcess('overwrite');">
  71. Overwrite
  72. </div>
  73. <div locale="dup/skip" class="ui labeled button" onclick="continueProcess('skip');">
  74. Skip
  75. </div>
  76. <div locale="dup/renameAndKeep" class="ui labeled button" style="color: #2fb55c;" onclick="continueProcess('keep');">
  77. Rename & Keep
  78. </div>
  79. </div>
  80. </div>
  81. <script>
  82. /*
  83. ArOZ Online File Operation Listener
  84. Usage: Pass in the following JSON object as hash with encodeURIComponent after JSON stringify
  85. {
  86. opr: {move / copy / zip / unzip / download / zipAndDown / unzipAndOpen},
  87. src: {filelist, allow multiple files},
  88. dest: {filepath},
  89. //Optional paramters
  90. overwriteMode: {skip / overwrite / keep},
  91. callbackWindowID: {floatWindow ID},
  92. callbackFunction: {target Window Function Name as String}
  93. }
  94. **For download opr, it will first buffer into the browser memory.
  95. It is not recommended for files > 2GB (Firefox Limit)
  96. Example callbackFunction: "refreshList()" (string)
  97. */
  98. var operationConfig = null;
  99. var opr = "";
  100. var oprId = "";
  101. var originalIcon = "";
  102. var paused = false;
  103. var maxPathDisplayLength = 40;
  104. var legacyMode = !('WebSocket' in window || 'MozWebSocket' in window); //Use AJAX instead of WebSocket if legacy mode is activated
  105. var enterErrorMode = false;
  106. //Initalized floatWindow events
  107. ao_module_setFixedWindowSize();
  108. ao_module_setWindowSize(400,220);
  109. if (applocale){
  110. //Applocale found. Do localization
  111. applocale.init("../locale/file_operation.json", function(){
  112. applocale.translate();
  113. init();
  114. });
  115. }else{
  116. //Applocale not found. Is this a trim down version of ArozOS?
  117. applocale = {
  118. getString: function(key, original){
  119. return original;
  120. }
  121. }
  122. init();
  123. }
  124. function init(){
  125. console.log("Checking launch parameters...");
  126. if (window.location.hash.length > 0){
  127. //OK to proceed
  128. try{
  129. operationConfig = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
  130. //Check if there are any missing paratmers
  131. configValid = true;
  132. if (typeof operationConfig.opr == "undefined"){ configValid = false; }
  133. if (typeof operationConfig.src == "undefined"){ configValid = false; }
  134. if (typeof operationConfig.dest == "undefined"){ configValid = false; }
  135. if (!configValid){
  136. console.log("Invalid file operation config. Please see the file_operation.html source code for the correct config json object.")
  137. ao_module_close();
  138. return;
  139. }
  140. //Parse the missing argument if there are any
  141. if (typeof operationConfig.overwriteMode == "undefined"){
  142. operationConfig.overwriteMode = "skip";
  143. }
  144. //Update 17-12-2020, ask the user for overwrite mode if file duplicate exists
  145. if (operationConfig.overwriteMode == "ask"){
  146. //Check if any file duplication before proceeding
  147. console.log(operationConfig.src);
  148. $.ajax({
  149. url: "../../system/file_system/listDir",
  150. data: {dir: operationConfig.dest},
  151. success: function(filelist){
  152. //Check for duplication
  153. var srcFilenameList = [];
  154. operationConfig.src.forEach(srcpath => {
  155. var filename = srcpath.split("/").pop();
  156. srcFilenameList.push(filename);
  157. })
  158. var duplicateFound = filelist.some(function(file){
  159. return srcFilenameList.includes(file.Filename);
  160. });
  161. console.log(filelist);
  162. console.log(operationConfig.src);
  163. if (duplicateFound){
  164. //Duplication found.
  165. $("#duplicateAction").modal({
  166. closable: false
  167. }).modal("show");
  168. }else{
  169. //Duplication not found. Start the operation with default mode
  170. operationConfig.overwriteMode = "skip";
  171. processOperations(operationConfig);
  172. }
  173. }
  174. })
  175. }else{
  176. //All information are defined. Process it now.
  177. processOperations(operationConfig)
  178. }
  179. }catch(ex){
  180. //Failed.
  181. console.log("Argument parse error", ex);
  182. }
  183. }else{
  184. alert("Invalid use of File Operation Listener.")
  185. ao_module_close();
  186. }
  187. }
  188. function continueProcess(duplicateMode){
  189. operationConfig.overwriteMode = duplicateMode;
  190. $("#duplicateAction").modal("hide");
  191. processOperations(operationConfig)
  192. }
  193. function processOperations(operationConfig){
  194. //Update the display information
  195. $("#src").text(operationConfig.src);
  196. $("#dest").text(operationConfig.dest);
  197. opr = operationConfig.opr;
  198. updateTitle(operationConfig.src.length, operationConfig.opr);
  199. //Check which type of the oprs is about. And assign the related functions to start
  200. if (operationConfig.opr == "move"){
  201. $("#opricon").attr("src","img/move.gif");
  202. originalIcon = "img/move.gif";
  203. cut(operationConfig.src, operationConfig.dest, operationConfig.overwriteMode);
  204. }else if (operationConfig.opr == "copy"){
  205. $("#opricon").attr("src","img/copy.gif");
  206. originalIcon = "img/copy.gif"
  207. copyopr(operationConfig.src, operationConfig.dest, operationConfig.overwriteMode);
  208. }else if (operationConfig.opr == "zip"){
  209. $("#opricon").attr("src","img/zip.gif");
  210. originalIcon = "img/zip.gif"
  211. zip(operationConfig.src, operationConfig.dest, operationConfig.overwriteMode);
  212. }else if (operationConfig.opr == "unzip"){
  213. $("#opricon").attr("src","img/unzip.gif");
  214. originalIcon = "img/unzip.gif"
  215. unzip(operationConfig.src, operationConfig.dest, operationConfig.overwriteMode);
  216. }else if (operationConfig.opr == "unzipAndOpen"){
  217. $("#opricon").attr("src","img/unzip.gif");
  218. originalIcon = "img/unzip.gif"
  219. unzip(operationConfig.src, operationConfig.dest, operationConfig.overwriteMode, function(){
  220. //Open the target directory
  221. });
  222. }
  223. }
  224. //Unzip zip
  225. function unzip(srcList, dest, overwriteMode, callback=undefined){
  226. if (legacyMode){
  227. //Run in legacy mode
  228. requestCSRFToken(function(token){
  229. $.ajax({
  230. type: 'POST',
  231. url: `../../system/file_system/fileOpr`,
  232. data: {opr: "unzip" ,src: JSON.stringify(srcList), dest: dest, csrft: token},
  233. success: function(data){
  234. handleFinish(data);
  235. }
  236. });
  237. });
  238. }else{
  239. //Filter all + sign in the list
  240. var filteredSrcList = [];
  241. srcList.forEach(src => {
  242. filteredSrcList.push(src.split("+").join("{{plug_sign}}"));
  243. });
  244. //Open WebSocket
  245. var endpoint = getWSEndpoint() + `?opr=unzip&src=${encodeURIComponent(JSON.stringify(filteredSrcList))}&dest=${encodeURIComponent(dest)}&existsresp=${overwriteMode}`
  246. console.log(endpoint);
  247. var ws = new WebSocket(endpoint);
  248. ws.onopen = function(){
  249. //Do nothing. Just listen to the progress update
  250. };
  251. ws.onmessage = function (evt) {
  252. var data = evt.data;
  253. var progress = JSON.parse(data);
  254. console.log(progress);
  255. if (progress.oprid != undefined){
  256. //This operation is assigned an ongoing task id. Show pause and cancel
  257. showPauseCancelButton();
  258. oprId = progress.oprid;
  259. }else if (progress.Error != ""){
  260. //Something went wrong
  261. $("#progressbar").css("background-color", "#eb3f28");
  262. enterErrorMode = true;
  263. handleFinish({error: progress.Error});
  264. }else{
  265. //Update the progress display
  266. var currentSrc = truncate(progress.LatestFile, maxPathDisplayLength);
  267. var filteredDest = operationConfig.dest.trim();
  268. if (filteredDest.substr(filteredDest.length -1, 1) != "/"){
  269. filteredDest += "/"
  270. }
  271. var currentDest = truncate(filteredDest + progress.LatestFile, maxPathDisplayLength);
  272. $("#src").text(currentSrc);
  273. $("#dest").text(currentDest);
  274. handleProgressUpdate(progress);
  275. }
  276. };
  277. ws.onclose = function() {
  278. if (!enterErrorMode){
  279. $("#progressbar").css("background-color", "#2bba35");
  280. $("#progressbar").css("width", "100%");
  281. $("#progress").text("100%");
  282. $("#opricon").attr("src", "img/done.png")
  283. setTimeout(function(){
  284. if (operationConfig.opr == "unzipAndOpen"){
  285. //If open after unzip is required
  286. ao_module_openPath(operationConfig.dest);
  287. }
  288. ao_module_close();
  289. }, 100);
  290. }
  291. };
  292. ws.onerror = function(event){
  293. console.error("WebSocket error observed:", event);
  294. legacyMode = true;
  295. console.log("Falling back to Legacy Mode");
  296. unzip(srcList, dest, overwriteMode, callback);
  297. }
  298. }
  299. }
  300. //Create zip
  301. function zip(srcList, dest, overwriteMode){
  302. if (legacyMode){
  303. //Run in legacy mode
  304. requestCSRFToken(function(token){
  305. $.ajax({
  306. type: 'POST',
  307. url: `../../system/file_system/fileOpr`,
  308. data: {opr: "zip" ,src: JSON.stringify(srcList), dest: dest, csrft: token},
  309. success: function(data){
  310. handleFinish(data);
  311. }
  312. });
  313. });
  314. }else{
  315. //Replace all + sign with tag
  316. var filteredSrcList = [];
  317. srcList.forEach(src => {
  318. filteredSrcList.push(src.split("+").join("{{plug_sign}}"));
  319. })
  320. //Start WebSocket connection
  321. var endpoint = getWSEndpoint() + `?opr=zip&src=${encodeURIComponent(JSON.stringify(filteredSrcList))}&dest=${encodeURIComponent(dest)}&existsresp=${overwriteMode}`
  322. console.log(endpoint);
  323. var ws = new WebSocket(endpoint);
  324. var srcZipRoot = "";
  325. ws.onopen = function() {
  326. console.log("File Operation WebSocket opened")
  327. //Emulate the src folder
  328. var srcDir = srcList[0].split("/");
  329. srcDir.pop();
  330. srcDir = srcDir.join("/");
  331. srcZipRoot = srcDir;
  332. var currentSrc = truncate(srcDir, maxPathDisplayLength);
  333. $("#src").text(currentSrc);
  334. //Emulate the dest folder
  335. var destFolderName = dest.substr(0, dest.length - 1).split('/').pop();
  336. destFolderName += ".zip";
  337. var currentDest = truncate(dest + destFolderName, maxPathDisplayLength);
  338. $("#dest").text(currentDest);
  339. };
  340. ws.onmessage = function (evt) {
  341. var data = evt.data;
  342. var progress = JSON.parse(data);
  343. if (progress.oprid != undefined){
  344. //This operation is assigned an ongoing task id. Show pause and cancel
  345. showPauseCancelButton();
  346. oprId = progress.oprid;
  347. }else if (progress.Error != ""){
  348. //Something went wrong
  349. $("#progressbar").css("background-color", "#eb3f28");
  350. enterErrorMode = true;
  351. handleFinish({error: progress.Error});
  352. }else{
  353. //Update the progress display
  354. var currentSrc = truncate(srcZipRoot + "/" + progress.LatestFile, maxPathDisplayLength);
  355. var filteredDest = operationConfig.dest.trim();
  356. if (filteredDest.substr(filteredDest.length -1, 1) != "/"){
  357. filteredDest += "/"
  358. }
  359. var currentDest = truncate(filteredDest + progress.LatestFile, maxPathDisplayLength);
  360. $("#src").text(currentSrc);
  361. $("#dest").text(currentDest);
  362. handleProgressUpdate(progress);
  363. }
  364. };
  365. ws.onclose = function() {
  366. //Transfer finished! Set OK and close in 1 second
  367. if (!enterErrorMode){
  368. $("#progressbar").css("background-color", "#2bba35");
  369. $("#progressbar").css("width", "100%");
  370. $("#progress").text("100%")
  371. handleFinish({});
  372. }
  373. };
  374. ws.onerror = function(event){
  375. console.error("WebSocket error observed:", event);
  376. legacyMode = true;
  377. console.log("Falling back to Legacy Mode");
  378. zip(srcList, dest, overwriteMode);
  379. }
  380. }
  381. }
  382. function cut(srcList, dest, overwriteMode){
  383. if (legacyMode){
  384. console.log("WebSocket not found, Running in legacy mode");
  385. requestCSRFToken(function(token){
  386. $.ajax({
  387. type: 'POST',
  388. url: `../../system/file_system/fileOpr`,
  389. data: {opr: "move" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode, csrft: token},
  390. success: function(data){
  391. handleFinish(data);
  392. }
  393. });
  394. });
  395. }else{
  396. //Replace all + sign in srclist with {{plus_sign}}
  397. var filteredSrcList = [];
  398. srcList.forEach(src => {
  399. filteredSrcList.push(src.split("+").join("{{plug_sign}}"));
  400. })
  401. //Use Websocket for operation updates
  402. var endpoint = getWSEndpoint() + `?opr=move&src=${encodeURIComponent(JSON.stringify(filteredSrcList))}&dest=${encodeURIComponent(dest)}&existsresp=${overwriteMode}`
  403. console.log(endpoint);
  404. var ws = new WebSocket(endpoint);
  405. ws.onopen = function() {
  406. console.log("File Operation WebSocket opened")
  407. };
  408. ws.onmessage = function (evt) {
  409. var data = evt.data;
  410. var progress = JSON.parse(data);
  411. if (progress.oprid != undefined){
  412. //This operation is assigned an ongoing task id. Show pause and cancel
  413. showPauseCancelButton();
  414. oprId = progress.oprid;
  415. }else if (progress.Error != ""){
  416. $("#progressbar").css("background-color", "#eb3f28");
  417. enterErrorMode = true;
  418. handleFinish({error: progress.Error});
  419. }else{
  420. var currentSrc = truncate(operationConfig.src + "/" + progress.LatestFile, maxPathDisplayLength);
  421. var filteredDest = operationConfig.dest.trim();
  422. if (filteredDest.substr(filteredDest.length -1, 1) != "/"){
  423. filteredDest += "/"
  424. }
  425. var currentDest = truncate(filteredDest + progress.LatestFile, maxPathDisplayLength);
  426. $("#src").text(currentSrc);
  427. $("#dest").text(currentDest);
  428. handleProgressUpdate(progress);
  429. }
  430. };
  431. ws.onclose = function() {
  432. //Transfer finished! Set OK and close in 1 second
  433. if (!enterErrorMode){
  434. $("#progressbar").css("background-color", "#2bba35");
  435. $("#progressbar").css("width", "100%");
  436. $("#progress").text("100%")
  437. handleFinish({});
  438. }
  439. };
  440. ws.onerror = function(event){
  441. console.error("WebSocket error observed:", event);
  442. console.log("Falling back to Legacy Mode")
  443. legacyMode = true;
  444. cut(srcList, dest, overwriteMode)
  445. }
  446. }
  447. }
  448. function copyopr(srcList, dest, overwriteMode){
  449. if (legacyMode){
  450. //Open operation in legacy mode
  451. console.log("WebSocket not found, Running in legacy mode");
  452. requestCSRFToken(function(token){
  453. $.ajax({
  454. type: 'POST',
  455. url: `../../system/file_system/fileOpr`,
  456. data: {opr: "copy" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode , csrft: token},
  457. success: function(data){
  458. handleFinish(data);
  459. }
  460. });
  461. });
  462. }else{
  463. var filteredSrcList = [];
  464. srcList.forEach(src => {
  465. filteredSrcList.push(src.split("+").join("{{plug_sign}}"));
  466. })
  467. //Use Websocket for operation updates
  468. var endpoint = getWSEndpoint() + `?opr=copy&src=${encodeURIComponent(JSON.stringify(filteredSrcList))}&dest=${encodeURIComponent(dest)}&existsresp=${overwriteMode}`
  469. var ws = new WebSocket(endpoint);
  470. ws.onopen = function() {
  471. console.log("File Operation WebSocket opened")
  472. };
  473. ws.onmessage = function (evt) {
  474. var data = evt.data;
  475. var progress = JSON.parse(data);
  476. if (progress.oprid != undefined){
  477. //This operation is assigned an ongoing task id. Show pause and cancel
  478. showPauseCancelButton();
  479. oprId = progress.oprid;
  480. }else if (progress.Error != ""){
  481. $("#progressbar").css("background-color", "#eb3f28");
  482. enterErrorMode = true;
  483. handleFinish({error: progress.Error});
  484. }else{
  485. var currentSrc = truncate(operationConfig.src + "/" + progress.LatestFile, maxPathDisplayLength);
  486. var filteredDest = operationConfig.dest.trim();
  487. if (filteredDest.substr(filteredDest.length -1, 1) != "/"){
  488. filteredDest += "/"
  489. }
  490. var currentDest = truncate(filteredDest + progress.LatestFile, maxPathDisplayLength);
  491. $("#src").text(currentSrc);
  492. $("#dest").text(currentDest);
  493. handleProgressUpdate(progress);
  494. }
  495. };
  496. ws.onclose = function() {
  497. //Transfer finished! Set OK and close in 1 second
  498. if (!enterErrorMode){
  499. $("#progressbar").css("background-color", "#2bba35");
  500. $("#progressbar").css("width", "100%");
  501. $("#progress").text("100%");
  502. handleFinish({});
  503. }
  504. };
  505. ws.onerror = function(event){
  506. console.error("WebSocket error observed:", event);
  507. console.log("Falling back to Legacy Mode")
  508. legacyMode = true;
  509. copyopr(srcList, dest, overwriteMode)
  510. }
  511. }
  512. }
  513. var truncate = function (fullStr, strLen, separator) {
  514. if (fullStr.length <= strLen) return fullStr;
  515. separator = separator || '...';
  516. var sepLen = separator.length,
  517. charsToShow = strLen - sepLen,
  518. frontChars = Math.ceil(charsToShow/2),
  519. backChars = Math.floor(charsToShow/2);
  520. return fullStr.substr(0, frontChars) +
  521. separator +
  522. fullStr.substr(fullStr.length - backChars);
  523. };
  524. function getWSEndpoint(){
  525. //Open opeartion in websocket
  526. let protocol = "wss://";
  527. if (location.protocol !== 'https:') {
  528. protocol = "ws://";
  529. }
  530. var port = window.location.port;
  531. if (window.location.port == ""){
  532. if (location.protocol !== 'https:') {
  533. port = "80";
  534. }else{
  535. port = "443";
  536. }
  537. }
  538. wsControlEndpoint = (protocol + window.location.hostname + ":" + port + "/system/file_system/ws/fileOpr");
  539. return wsControlEndpoint;
  540. }
  541. function updateTitle(fileNumber, opr){
  542. var title = "";
  543. if (opr == "move"){
  544. title = applocale.getString("title/moving","Moving ");
  545. }else if (opr == "copy"){
  546. title = applocale.getString("title/copying","Copying ");
  547. }else if (opr == "zip" || opr == "zipAndDownload"){
  548. title = applocale.getString("title/zipping","Zipping ");
  549. }else if (opr == "download"){
  550. title = applocale.getString("title/downloading","Downloading ");
  551. }else if (opr == "unzip" || opr == "unzipAndOpen"){
  552. title = applocale.getString("title/unzipping","Unzipping ");
  553. }
  554. title += fileNumber + " ";
  555. if (fileNumber == 1){
  556. title += applocale.getString("title/file"," File");
  557. }else{
  558. title += applocale.getString("title/files"," Files");
  559. }
  560. $(".title").text(title);
  561. }
  562. function handleProgressUpdate(progress){
  563. if (progress.StatusFlag != undefined){
  564. switch (progress.StatusFlag) {
  565. case 1:
  566. if ($("#opricon").attr("src") != "img/paused.png"){
  567. //Show paused UI state
  568. $("#opricon").attr("src", "img/paused.png");
  569. $("#pauseButton").text(applocale.getString("button/resume","Resume"));
  570. }
  571. break;
  572. case 2:
  573. if ($("#opricon").attr("src") != "img/error.png"){
  574. $("#opricon").attr("src", "img/error.png");
  575. }
  576. break;
  577. default:
  578. if ($("#opricon").attr("src") != originalIcon){
  579. //Show
  580. $("#opricon").attr("src",originalIcon);
  581. $("#pauseButton").text(applocale.getString("button/pause","Pause"));
  582. }
  583. }
  584. }
  585. $("#progressbar").css("width", progress.Progress + "%");
  586. $("#progress").text(progress.Progress + "%")
  587. if (progress.Progress >= 100){
  588. //Set progress bar to green
  589. $("#progressbar").css("background-color", "#2bba35");
  590. $("#progress").text("100%");
  591. }
  592. }
  593. function handleFinish(data){
  594. $("#advanceControlbtns").find(".button").addClass("disabled");
  595. if (data.error !== undefined){
  596. $("#progressbar").css("background-color","#db2828");
  597. $("#progressbar").parent().removeClass('active');
  598. $(".title").html(applocale.getString("error/" + data.error,data.error));
  599. $("#opricon").attr("src", "img/error.png");
  600. enterErrorMode = true;
  601. $("#cancelButton").html(applocale.getString("button/cancel", "Cancel"));
  602. return
  603. }else{
  604. $("#progressbar").css("background-color","#21ba45");
  605. $("#progressbar").parent().removeClass('active');
  606. $("#opricon").attr("src", "img/done.png");
  607. if (opr == "move" || opr == "copy" || opr == "zip" || opr == "unzip"){
  608. //Action completed. close window.
  609. setTimeout(function(){
  610. //Do callback if exists
  611. if (operationConfig.callbackWindowID == "desktop"){
  612. //Special call from desktop
  613. parent.eval(operationConfig.callbackFunction);
  614. }else if (ao_module_virtualDesktop && operationConfig.callbackWindowID !== undefined && operationConfig.callbackFunction !== undefined){
  615. var callbackWindowObject = parent.getFloatWindowByID(operationConfig.callbackWindowID)
  616. var windowObject = $(callbackWindowObject).find("iframe")[0];
  617. if (windowObject == undefined || windowObject == null){
  618. //Caller no longer exists.
  619. }else{
  620. //Caller still exists. Do callback events
  621. //console.log(windowObject.contentWindow, operationConfig.callbackFunction);
  622. windowObject.contentWindow.eval(operationConfig.callbackFunction);
  623. }
  624. }
  625. //If the target or src is desktop, refresh desktop as well
  626. if(pathIsOnDesktop(operationConfig.dest) || pathIsOnDesktop(operationConfig.src[0])){
  627. if (ao_module_virtualDesktop){
  628. parent.refresh(undefined, true);
  629. }
  630. }
  631. if (!enterErrorMode){
  632. ao_module_close();
  633. setTimeout(function(){
  634. //If ao_module_close is not working for some reason
  635. open(location, '_self').close();
  636. }, 500);
  637. }
  638. }, 1000);
  639. }else if (opr == "download"){
  640. //Create download from buffer
  641. }else if (opr == "zipAndDown"){
  642. //Download
  643. }else if (opr == "unzipAndOpen"){
  644. //Unzip and open the target directory
  645. setTimeout(function(){
  646. //Open the target directory
  647. ao_module_openPath(operationConfig.dest);
  648. //Close the window
  649. ao_module_close();
  650. }, 1000);
  651. }
  652. }
  653. console.log(data);
  654. }
  655. function pathIsOnDesktop(path){
  656. var filteredDest = path;
  657. if (filteredDest.substr(filteredDest.length - 1) == "/"){
  658. filteredDest = filteredDest.substr(0, filteredDest.length - 1);
  659. }
  660. var dirChunk = filteredDest.split("/");
  661. console.log(dirChunk);
  662. if (dirChunk.length == 2 || dirChunk.length == 3){
  663. if (dirChunk[0].toLowerCase() == "user:" && dirChunk[1].toLowerCase() == "desktop"){
  664. //This is a direct access desktop file
  665. return true;
  666. }
  667. }
  668. return false;
  669. }
  670. function requestCSRFToken(callback){
  671. $.ajax({
  672. url: "../../system/csrf/new",
  673. success: function(token){
  674. callback(token);
  675. }
  676. })
  677. }
  678. /*
  679. Functions related to pause and cancel of the file operations
  680. */
  681. function togglePauseTask(){
  682. if (paused){
  683. //Resume
  684. $.ajax({
  685. url: "../../system/file_system/ongoing",
  686. method: "POST",
  687. data: {"oprid": oprId, "flag": "continue"},
  688. success: function(data){
  689. if (data.error != undefined){
  690. console.log(data.error);
  691. }else{
  692. paused = false;
  693. $("#pauseButton").text(applocale.getString("button/pause","Pause"));
  694. $("#opricon").attr("src",originalIcon);
  695. }
  696. }
  697. });
  698. }else{
  699. //Pause
  700. $.ajax({
  701. url: "../../system/file_system/ongoing",
  702. method: "POST",
  703. data: {"oprid": oprId, "flag": "pause"},
  704. success: function(data){
  705. if (data.error != undefined){
  706. console.log(data.error);
  707. }else{
  708. paused = true;
  709. $("#opricon").attr("src","img/paused.png");
  710. $("#pauseButton").text(applocale.getString("button/resume","Resume"));
  711. }
  712. }
  713. });
  714. }
  715. }
  716. //Cancel the current ongoing task
  717. function cancelTask(){
  718. $.ajax({
  719. url: "../../system/file_system/ongoing",
  720. method: "POST",
  721. data: {"oprid": oprId, "flag": "cancel"},
  722. success: function(data){
  723. if (data.error != undefined){
  724. console.log(data.error);
  725. }else{
  726. //Disable further operation untill task cancelled
  727. $("#advanceControlbtns").find(".button").addClass("disabled");
  728. $("#cancelButton").html(`<i class="ui loading spinner icon"></i>`);
  729. }
  730. }
  731. });
  732. }
  733. function showPauseCancelButton(){
  734. ao_module_setWindowSize(400,254);
  735. $("#progressbar").parent().css({
  736. "margin-bottom":"1em"
  737. });
  738. $("#advanceControlbtns").show();
  739. }
  740. function hidePauseCancelButton(){
  741. ao_module_setWindowSize(400,220);
  742. $("#progressbar").parent().css("margin-bottom", "2.5em");
  743. $("#advanceControlbtns").hide();
  744. }
  745. </script>
  746. </body>
  747. </html>