file_operation.html 39 KB

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