file_selector.html 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. <html>
  2. <head>
  3. <title locale="title">File Selector</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/tocas/tocas.css">
  7. <link rel="stylesheet" href="../../script/ao.css">
  8. <script type="text/javascript" src="../../script/tocas/tocas.js"></script>
  9. <script type="text/javascript" src="../../script/jquery.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. background-color:white;
  15. }
  16. .navi{
  17. padding:8px;
  18. background-color:#fcfcfc;
  19. border-bottom:2px solid #34b7eb;
  20. position:fixed;
  21. left:0px;
  22. top:0px;
  23. width:100%;
  24. z-index:99;
  25. }
  26. .pusher{
  27. margin-top:46px;
  28. margin-left:200px;
  29. width: calc(100% - 200px);
  30. }
  31. .pusher .fileListWrapper{
  32. padding-left:20px;
  33. padding-right:20px;
  34. }
  35. .navi .button{
  36. box-shadow: 0 1px 1px 0px rgb(190, 190, 190) !important;
  37. }
  38. .list .item{
  39. cursor:pointer;
  40. }
  41. .list .item:hover{
  42. color:#c7c7c7 !important;
  43. }
  44. .extrapadding{
  45. padding-left:6px !important;
  46. padding-right:6px !important;
  47. }
  48. .fileObject{
  49. overflow-wrap: break-word !important;
  50. display: block !important;
  51. padding:12px !important;
  52. font-size:98%;
  53. }
  54. .fileObject .fileInfo{
  55. display:inline-block !important;
  56. word-break: break-all;
  57. text-overflow: ellipsis !important;
  58. overflow: hidden;
  59. color:black;
  60. user-select: none;
  61. }
  62. .fileObject.selected{
  63. background-color:#d2f2f7 !important;
  64. }
  65. .fileObject.item:hover{
  66. background-color:#f2f2f2;
  67. }
  68. </style>
  69. </head>
  70. <body>
  71. <div class="navi">
  72. <button id="sidebarToggleBtn" class="ts icon tiny button" onclick="ts('.sidebar').sidebar('toggle');"><i class="content icon"></i></button>
  73. <button title="Back" class="ts icon tiny button" onclick="backDir();"><i class="arrow left icon"></i></button>
  74. <button title="Parent" class="ts icon tiny button" onclick="parentDir();"><i class="arrow up icon"></i></button>
  75. <button title="Refresh" class="ts icon tiny button" onclick="refresh();"><i class="refresh icon"></i></button>
  76. <button title="New Folder" class="ts icon tiny button" onclick="newFolder();"><i class="folder icon"></i></button>
  77. <div class="ts action fluid tiny input" style="width: calc(100% - 180px); float: right;">
  78. <input id="addressbar" type="text" placeholder="" onchange="updatePath();">
  79. <button class="ts positive icon button" onclick="confirmSelection();"><i class="checkmark icon"></i></button>
  80. </div>
  81. <div id="newfilenameInput" style="width:100%; margin-top:12px;" align="right">
  82. <div class="ts fluid tiny input" style="width: calc(100% - 180px); float: right;">
  83. <input id="filename" type="text" placeholder="New Filename">
  84. </div>
  85. </div>
  86. <div id="newFolderInput" style="width:100%; margin-top:4px; display:none;" align="right">
  87. <div class="ts fluid action tiny input" style="width: calc(100% - 180px); float: right;">
  88. <input id="foldername" type="text" placeholder="New Folder" value="">
  89. <button class="ts icon button" onclick="createFolder()" title="Create Folder"><i class="add icon"></i></button>
  90. </div>
  91. </div>
  92. </div>
  93. <div id="sidebar" class="ts left static visible overlapped sidebar" style="background-color:#f5f5f5 !important;z-index:90 !important; width:200px;">
  94. <div id="sidebarPadder" style="height:46px;"></div>
  95. <details class="ts accordion" open>
  96. <summary>
  97. <i class="dropdown icon"></i> <span locale="roots/user">User</span>
  98. </summary>
  99. <div class="content" >
  100. <div class="ts list" id="userlist">
  101. </div>
  102. </div>
  103. </details>
  104. <details class="ts accordion" open>
  105. <summary>
  106. <i class="dropdown icon"></i> <span locale="roots/storage">Storage</span>
  107. </summary>
  108. <div class="content">
  109. <div class="ts list" id="storagelist">
  110. </div>
  111. </div>
  112. </details>
  113. </div>
  114. <div class="pusher">
  115. <br>
  116. <div class="fileListWrapper" style="min-height:300px; width:100%;">
  117. <div id="folderList" class="ts segmented basic fluid list whiteTheme">
  118. <div class="fileObject">
  119. <span class="fileInfo"><i class="loading spinner icon" style="margin-right:12px;"></i> <span locale="message/loading">Loading</span></span>
  120. </div>
  121. </div>
  122. <div id="fileList" class="ts segmented fluid list whiteTheme">
  123. </div>
  124. </div>
  125. <br><br>
  126. </div>
  127. <div id="waitloader" class="ts active dimmer" style="display:none; z-index:999;">
  128. <div id="waitloadertext" class="ts indeterminate text loader" locale="message/waitingResp">Waiting Response</div>
  129. </div>
  130. <script>
  131. var multiSelect = false;
  132. var type = "file";
  133. var currentDir = "user:/";
  134. var currentFileList = [];
  135. var pathHistory = [];
  136. var ctrlDown = false;
  137. var shiftDown = false;
  138. var lastClickedItemID = 0;
  139. var listenerUUID = "";
  140. var fileOptions = {};
  141. if (applocale){
  142. //Applocale found. Do localization
  143. applocale.init("../locale/file_selector.json", function(){
  144. applocale.translate();
  145. initRoots();
  146. });
  147. }else{
  148. //Applocale not found. Is this a trim down version of ArozOS?
  149. applocale = {
  150. getString: function(key, original){
  151. return original;
  152. }
  153. }
  154. initRoots();
  155. }
  156. initSelectorObject();
  157. updateWindowResize();
  158. function initSelectorObject(){
  159. var initInfo = loadSelectorInfoFromHash();
  160. //Load the initiation directory
  161. listDir(initInfo.root);
  162. //init global var
  163. type = initInfo.type;
  164. multiSelect = initInfo.allowMultiple;
  165. listenerUUID = initInfo.listenerUUID;
  166. if (initInfo.options != undefined){
  167. fileOptions = JSON.parse(JSON.stringify(initInfo.options));
  168. }
  169. //Load options and parse the UI
  170. if (type == "new"){
  171. //Resize the top bar
  172. $("#sidebarPadder").css("height", "90px");
  173. $(".fileListWrapper").css("padding-top", "50px");
  174. if (typeof(fileOptions.defaultName) != "undefined"){
  175. $("#filename").val(fileOptions.defaultName);
  176. }else{
  177. $("#filename").val("newfile.txt");
  178. }
  179. }else{
  180. $("#newfilenameInput").hide();
  181. }
  182. }
  183. function cancelSelection(){
  184. localStorage.setItem(listenerUUID, JSON.stringify("&&selection_canceled&&"));
  185. }
  186. function confirmSelection(){
  187. var files = [];
  188. $(".selected.fileObject").each(function(){
  189. var filename = decodeURIComponent($(this).attr('filename'));
  190. var filepath = decodeURIComponent($(this).attr('filepath'));
  191. files.push({
  192. filename: filename,
  193. filepath: filepath
  194. });
  195. });
  196. //Check if currentdir end with "/". If not, append it
  197. if(currentDir.substr(currentDir.length - 1, 1) != "/"){
  198. currentDir = currentDir + "/";
  199. }
  200. //Check for special cases
  201. if (files.length == 0 && type == "folder"){
  202. //Select the current path as target instead
  203. var currentPathname = currentDir.split("/");
  204. currentPathname.pop();
  205. currentPathname = currentPathname.pop();
  206. if (currentPathname == ""){
  207. currentPathname = currentDir;
  208. }
  209. files.push({
  210. filename: currentPathname,
  211. filepath: currentDir
  212. });
  213. }else if (files.length == 0 && type == "new"){
  214. //Push this new file into the return structure
  215. var newFilename = $("#filename").val();
  216. files.push({
  217. filename: newFilename,
  218. filepath: currentDir + newFilename
  219. });
  220. }
  221. if (ao_module_virtualDesktop){
  222. if (!ao_module_parentCallback(files)){
  223. //Parent callback not exists
  224. alert("Selection Failed. Is parent window alive?")
  225. }else{
  226. parent.closeFwProcess(ao_module_windowID);
  227. }
  228. }else{
  229. if (listenerUUID == ""){
  230. alert("Invalid listener UUID. Please re-open your file selector.")
  231. return;
  232. }
  233. var selectedFilesInJSON = JSON.stringify(files);
  234. localStorage.setItem(listenerUUID, selectedFilesInJSON);
  235. $("#waitloader").show();
  236. $(".pusher").css("overflow","hidden");
  237. setTimeout(function(){
  238. $("#waitloadertext").html("<i class='remove icon'></i> System is not responding. <br>Please close this window and retry.");
  239. },10000)
  240. }
  241. }
  242. //Handle on window close function, cancel current selection
  243. window.onbeforeunload = function(){
  244. cancelSelection();
  245. }
  246. //Overwrite the ao_module close function
  247. function ao_module_close(){
  248. if (!ao_module_virtualDesktop){
  249. return;
  250. }
  251. if (!ao_module_parentCallback(files)){
  252. alert("Selection Failed. Is parent window alive?")
  253. }else{
  254. parent.closeFwProcess(ao_module_windowID);
  255. }
  256. }
  257. function updatePath(){
  258. var newDir = $("#addressbar").val();
  259. listDir(newDir);
  260. }
  261. function refresh(){
  262. $("#fileList").html("");
  263. $("#folderList").html("");
  264. listDir(currentDir);
  265. }
  266. function newFolder(){
  267. $("#newFolderInput").toggle();
  268. if($("#newFolderInput").is(":visible")){
  269. $("#sidebarPadder").css("height", "90px");
  270. }else{
  271. $("#sidebarPadder").css("height", "46px");
  272. }
  273. updateFileListTopLocation();
  274. }
  275. function hideFolderNameInput(){
  276. $("#newFolderInput").hide();
  277. $("#sidebarPadder").css("height", "46px");
  278. $(".fileListWrapper").css("padding-top", "0px");
  279. }
  280. function createFolder(){
  281. var folderName = $("#foldername").val();
  282. if (folderName == ""){
  283. folderName = "New Folder"
  284. $("#foldername").val("New Folder");
  285. }
  286. folderName = folderName.replace(/[<>:"/\\|?*]/g, "_");
  287. //Check if folder exists
  288. var nameAlreadyExists = false;
  289. currentFileList.forEach(fileObject => {
  290. if (fileObject.IsDir && fileObject.Filename == folderName){
  291. nameAlreadyExists = true;
  292. }
  293. });
  294. if (nameAlreadyExists){
  295. alert("Folder already exists")
  296. return
  297. }
  298. //Create the new folder request
  299. requestCSRFToken(function(token){
  300. $.ajax({
  301. url: "../../system/file_system/newItem",
  302. data: {type: "folder", src: currentDir, filename: folderName, csrft: token},
  303. success: function(data){
  304. if (data.error !== undefined){
  305. alert(data.error);
  306. }else{
  307. refresh()
  308. }
  309. hideFolderNameInput();
  310. }
  311. });
  312. });
  313. }
  314. function loadSelectorInfoFromHash(){
  315. if (window.location.hash.length == 0){
  316. return {
  317. root: "user:/",
  318. type: "file",
  319. allowMultiple: false
  320. }
  321. }else{
  322. try{
  323. var selectInfo = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
  324. return selectInfo;
  325. }catch{
  326. //Error parsing the input. Use default settings
  327. return {
  328. root: "user:/",
  329. type: "file",
  330. allowMultiple: false
  331. }
  332. }
  333. }
  334. }
  335. function listDir(dir){
  336. currentDir = dir;
  337. pathHistory.push(currentDir);
  338. $("#addressbar").val(currentDir);
  339. ao_module_setWindowTitle(`Open`);
  340. $.get("../../system/file_system/listDir?dir=" + encodeURIComponent(dir),function(data){
  341. $("#folderList").html("");
  342. $("#fileList").html("");
  343. if (data === null){
  344. $("#folderList").hide();
  345. $("#fileList").hide();
  346. return;
  347. }else{
  348. $("#folderList").show();
  349. $("#fileList").show();
  350. }
  351. if (data.error !== undefined){
  352. //Load the index instead
  353. listDir("user:/");
  354. }else{
  355. currentFileList = data;
  356. var folders = [];
  357. var files = [];
  358. for (var i =0; i < data.length; i++){
  359. if (data[i].IsDir == true){
  360. folders.push(data[i]);
  361. }else{
  362. if (fileOptions.filter != undefined){
  363. var fileExt = data[i].Filename.split(".").pop();
  364. for (var j = 0; j < fileOptions.filter.length; j++){
  365. if (fileOptions.filter[j] == fileExt){
  366. files.push(data[i]);
  367. break;
  368. }
  369. }
  370. }else{
  371. files.push(data[i]);
  372. }
  373. }
  374. }
  375. //Append folder first then files
  376. var count = 0;
  377. for (var i =0; i < folders.length; i++){
  378. var filename = folders[i].Filename;
  379. var filepath = folders[i].Filepath;
  380. var ext = filename.split(".").pop();
  381. var icon = ao_module_utils.getIconFromExt(ext);
  382. var isDir = folders[i].IsDir;
  383. if (isDir == true){
  384. icon = "folder";
  385. }
  386. var fileSize = folders[i].Displaysize;
  387. $("#folderList").append(`<div class="fileObject item" fid="${count}" ondblclick="openFolder(event,this);" onclick="selectThis(this,event);" filepath="${encodeURIComponent(filepath)}" filename="${encodeURIComponent(filename)}" isDir="${isDir}">
  388. <span class="fileInfo"><i class="${icon} icon" style="margin-right:4px;"></i> ${filename}</span>
  389. </div>`);
  390. count++;
  391. }
  392. if (folders.length == 0){
  393. $("#folderList").hide();
  394. }
  395. for (var i =0; i < files.length; i++){
  396. var filename = files[i].Filename;
  397. var filepath = files[i].Filepath;
  398. var ext = filename.split(".").pop();
  399. var icon = ao_module_utils.getIconFromExt(ext);
  400. var isDir = files[i].IsDir;
  401. if (isDir == true){
  402. icon = "folder";
  403. }
  404. var fileSize = files[i].Displaysize;
  405. $("#fileList").append(`<div class="fileObject item" fid="${count}" ondblclick="chooseThisFile(this);" onclick="selectThis(this,event);" filepath="${encodeURIComponent(filepath)}" filename="${encodeURIComponent(filename)}" isDir="${isDir}">
  406. <span class="fileInfo"><i class="${icon} icon" style="margin-right:4px;margin-top: 2px;"></i> ${filename}</span>
  407. </div>`);
  408. count++;
  409. }
  410. if (files.length == 0){
  411. $("#fileList").hide();
  412. }
  413. $('.pusher').scrollTop(0);
  414. }
  415. });
  416. }
  417. function requestCSRFToken(callback){
  418. $.ajax({
  419. url: "../../system/csrf/new",
  420. success: function(token){
  421. callback(token);
  422. }
  423. })
  424. }
  425. //Open folder
  426. function openFolder(event, object){
  427. event.preventDefault();
  428. var filepath = $(object).attr("filepath");
  429. filepath = decodeURIComponent(filepath);
  430. listDir(filepath);
  431. }
  432. function selectThis(object,event){
  433. //event.preventDefault();
  434. //event.stopImmediatePropagation();
  435. //Check if this object is in suitable selection type
  436. if ($(object).attr("IsDir") == "true" && type == "file"){
  437. return;
  438. }else if ($(object).attr("IsDir") == "false" && type == "folder"){
  439. return;
  440. }else if (type == "new" && $(object).attr("IsDir") == "false"){
  441. //Use this filename as the newfile name (aka overwrite mode)
  442. var newNewFilename = $(object).attr("filename");
  443. newNewFilename = decodeURIComponent(newNewFilename);
  444. $("#filename").val(newNewFilename);
  445. return;
  446. }else if (type == "new" && $(object).attr("IsDir") == "true"){
  447. //Selected a folder in new mode. Ignore it
  448. return
  449. }
  450. if (multiSelect){
  451. if (ctrlDown){
  452. //Add this into selection list
  453. $(object).addClass("selected");
  454. }else if (shiftDown){
  455. var start = lastClickedItemID;
  456. var end = $(object).attr("fid");
  457. if (start > end){
  458. start = end;
  459. end = lastClickedItemID;
  460. }
  461. var fileObjects = $(".fileObject");
  462. for (var k = start; k <= end; k++){
  463. $(fileObjects[k]).addClass("selected");
  464. }
  465. }else{
  466. //Reset and add this into selection list
  467. $(".selected").removeClass("selected");
  468. $(object).addClass("selected");
  469. }
  470. }else{
  471. $(".selected").removeClass("selected");
  472. $(object).addClass("selected");
  473. }
  474. //Update last selected id
  475. lastClickedItemID = $(object).attr('fid');
  476. //Update title
  477. var objectCount = $(".selected").length;
  478. var typeName = "object"
  479. if (type == "file"){
  480. typeName = "file";
  481. }else if (type == "folder"){
  482. typeName = "folder";
  483. }
  484. var desc = `${typeName} selected`;
  485. if (objectCount > 1){
  486. desc = `${typeName + "s"} selected`;
  487. }
  488. ao_module_setWindowTitle(`Open (${objectCount} ${desc})`);
  489. }
  490. $(window).on("keydown",function(event){
  491. if (event.which == 17){
  492. ctrlDown = true;
  493. }else if (event.which == 16){
  494. shiftDown = true;
  495. }
  496. });
  497. $(window).on("keyup",function(event){
  498. if (event.which == 17){
  499. ctrlDown = false;
  500. }else if (event.which == 16){
  501. shiftDown = false;
  502. }
  503. });
  504. $(window).on("resize",function(){
  505. updateWindowResize();
  506. });
  507. function updateWindowResize(){
  508. if (window.innerWidth < 560){
  509. //Mobile mode
  510. $("#sidebar").attr("class", "ts left overlapped sidebar");
  511. $(".pusher").css("margin-left", "0px").css("width","100%");
  512. $("#sidebar").css("margin-top", "30px");
  513. $("#sidebarToggleBtn").show();
  514. $("#addressbar").parent().css({
  515. "width": "100%",
  516. "margin-top": "4px"
  517. });
  518. $("#newfilenameInput").find(".input").css({
  519. "width": "100%",
  520. "margin-top": "4px"
  521. });
  522. $("#newFolderInput").find(".input").css({
  523. "width": "100%",
  524. "margin-top": "4px"
  525. });
  526. }else{
  527. $("#sidebar").attr("class", "ts left static visible overlapped sidebar");
  528. $(".pusher").css("margin-left", "200px").css("width","calc(100% - 200px)");
  529. $("#sidebarToggleBtn").hide();
  530. $("#sidebar").css("margin-top", "0px");
  531. $("#addressbar").parent().css({
  532. "width": "calc(100% - 180px)",
  533. "margin-top": "0px"
  534. });
  535. $("#newfilenameInput").find(".input").css({
  536. "width": "calc(100% - 180px)",
  537. "margin-top": "0px"
  538. });
  539. $("#newFolderInput").find(".input").css({
  540. "width": "calc(100% - 180px)",
  541. "margin-top": "8px"
  542. });
  543. }
  544. updateFileListTopLocation();
  545. }
  546. function updateFileListTopLocation(){
  547. $(".fileListWrapper").css("padding-top", $(".navi").height() - 38 + "px");
  548. }
  549. function initAddressBarWidth(){
  550. $("#addressbar").css("width",window.innerWidth - 220 + "px");
  551. }
  552. function chooseThisFile(object){
  553. $(".selected").removeClass('selected');
  554. $(object).addClass('selected');
  555. confirmSelection();
  556. }
  557. function parentDir(){
  558. if (currentDir.substring(currentDir.length - 1) == "/"){
  559. currentDir = currentDir.substring(0, currentDir.length - 1);
  560. }
  561. var tmp = currentDir.split("/");
  562. tmp.pop();
  563. var parentPath = tmp.join("/");
  564. if (parentPath.length == 0){
  565. //Do nothing. Already at root dir
  566. }else{
  567. listDir(parentPath);
  568. }
  569. }
  570. function backDir(){
  571. if (pathHistory.length > 1){
  572. pathHistory.pop();
  573. var targetPath = pathHistory.pop();
  574. listDir(targetPath);
  575. }
  576. }
  577. //Initialize user shortcuts
  578. function initRoots(){
  579. $.get("../../system/file_system/listRoots",function(data){
  580. $("#storagelist").html("");
  581. for (var i =0; i < data.length; i++){
  582. $('#storagelist').append(`<div class="item extrapadding" filepath="${data[i]["RootPath"]}" onclick="openShortcut(this);"><i class="disk outline icon" style="margin-right:8px;"></i> ${data[i]["RootName"]} (${data[i]["RootPath"]})</div>`);
  583. }
  584. });
  585. $.get("../../system/file_system/listRoots?user=true",function(data){
  586. $("#userlist").html("");
  587. for (var i =0; i < data.length; i++){
  588. if (data[i].IsDir == true){
  589. if (data[i]["Filename"].substring(0,1) == "."){
  590. //Do not show hidden files
  591. continue;
  592. }
  593. //Get the icon and the localization of this user root
  594. var iconAndFolderName = getUserRootIcons(data[i]["Filename"]);
  595. console.log(iconAndFolderName);
  596. $('#userlist').append(`<div class="item extrapadding" filepath="${data[i]["Filepath"]}" onclick="openShortcut(this);"><i class="${iconAndFolderName[0]} icon" style="margin-right:8px;"></i> ${iconAndFolderName[1]}</div>`);
  597. }
  598. }
  599. });
  600. }
  601. function getUserRootIcons(foldername){
  602. var icon = "folder open";
  603. var name = foldername;
  604. foldername = foldername.toLowerCase();
  605. if (foldername == "desktop"){
  606. icon = "computer";
  607. name = applocale.getString("sidebar/vroot/desktop", name);
  608. }else if (foldername == "document"){
  609. icon = "file text outline";
  610. name = applocale.getString("sidebar/vroot/document", name);
  611. }else if (foldername == "music" || foldername == "audio"){
  612. icon = "music";
  613. name = applocale.getString("sidebar/vroot/music", name);
  614. }else if (foldername == "photo" || foldername == "picture"){
  615. icon = "image";
  616. name = applocale.getString("sidebar/vroot/photo", name);
  617. }else if (foldername == "video" || foldername == "film"){
  618. icon = "video";
  619. name = applocale.getString("sidebar/vroot/video", name);
  620. }else if (foldername == "trash" || foldername == "bin" || foldername == "rubbish"){
  621. icon = "trash"
  622. name = applocale.getString("sidebar/vroot/trash", name);
  623. }else if (foldername == "download"){
  624. icon = "download"
  625. name = applocale.getString("sidebar/vroot/download", name);
  626. }else if (foldername == "www" || foldername == "web" || foldername == "mysite"){
  627. icon = "globe"
  628. name = applocale.getString("sidebar/vroot/web", name);
  629. }else if (foldername == "model"){
  630. icon = "cube"
  631. name = applocale.getString("sidebar/vroot/model", name);
  632. }else if (foldername == "appdata"){
  633. icon = "code"
  634. name = applocale.getString("sidebar/vroot/appdata", name);
  635. }
  636. return [icon, name];
  637. }
  638. function openShortcut(object){
  639. var targetdir = $(object).attr("filepath");
  640. targetdir = decodeURIComponent(targetdir);
  641. listDir(targetdir);
  642. if (window.innerWidth < 560){
  643. ts('.sidebar').sidebar('hide');
  644. }
  645. }
  646. </script>
  647. </body>
  648. </html>