file_share.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. <html>
  2. <head>
  3. <title locale="title/title">File Share</title>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
  6. <style>
  7. body{
  8. background: rgba(255,255,255,01) !important;
  9. }
  10. </style>
  11. </head>
  12. <body>
  13. <div class="ui stackable grid">
  14. <div class="eight wide column">
  15. <div class="width: 100%; ">
  16. <div style="display: block; margin-left: auto; margin-right: auto;" align="center">
  17. <div id="qrcode" style="border: 10px solid white; background-color: white;">
  18. <h1><br><i class="ui loading spinner icon"></i><br></h1>
  19. </div>
  20. </div>
  21. <div style="width: 100%">
  22. <a id="sharelink" href="" target="_blank" style="margin-top:8px; font-size: 120%; padding-left: 20px; padding-right: 20px; word-break: break-all; overflow-wrap: anywhere;"></a>
  23. </div>
  24. </div>
  25. </div>
  26. <div id="shareSettingOptions" class="eight wide column" style="padding-left: 12px; display:none;">
  27. <div class="ui header whiteTheme">
  28. <span locale="share/setting/title">Share Settings</span>
  29. <div class="sub header whiteTheme" locale="share/setting/subtitle">Change who can see this file</div>
  30. </div>
  31. <div id="shareSettingForm" class="ui form">
  32. <div class="field">
  33. <label><p class="whiteTheme" locale="share/setting/options">Visable options:</p></label>
  34. <div class="ui checkboxes">
  35. <div class="ui radio checkbox">
  36. <input id="anyone" type="radio" class="shareoption" name="shareopt" value="anyone" onchange="updateSharePermission(this);">
  37. <label for="anyone">
  38. <div class="ui header">
  39. <div class="content whiteTheme">
  40. <i class="globe icon"></i> <span locale="share/setting/anyoneWithLink">Anyone with the link</span>
  41. <div class="sub header whiteTheme" locale="share/setting/anyoneWithLink/desc">Anyone who has the link can access this file</div>
  42. </div>
  43. </div>
  44. </label>
  45. </div>
  46. <br><br>
  47. <div class="ui radio checkbox">
  48. <input id="signedin" type="radio" class="shareoption" value="signedin" name="shareopt" onchange="updateSharePermission(this);">
  49. <label for="signedin">
  50. <div class="ui header">
  51. <div class="content whiteTheme">
  52. <i class="user circle outline icon"></i> <span locale="share/setting/anyoneSignedIn">Anyone signed in</span>
  53. <div class="sub header whiteTheme" locale="share/setting/anyoneSignedIn/desc">Anyone who has signed in can access this file</div>
  54. </div>
  55. </div>
  56. </label>
  57. </div>
  58. <br><br>
  59. <div class="ui radio checkbox">
  60. <input id="samegroup" type="radio" class="shareoption" value="samegroup" name="shareopt" onchange="updateSharePermission(this);">
  61. <label for="samegroup">
  62. <div class="ui header">
  63. <div class="content whiteTheme">
  64. <i class="users icon"></i> <span locale="share/setting/sameGroup">Users in the same group</span>
  65. <div class="sub header whiteTheme" locale="share/setting/sameGroup/desc">Anyone who is in the same group as you do</div>
  66. </div>
  67. </div>
  68. </label>
  69. </div>
  70. <br><br>
  71. <div class="ui accordion" id="advanceShare">
  72. <div class="title">
  73. <i class="dropdown icon"></i>
  74. <span locale="share/setting/advance/title">Advance Share Options</span>
  75. </div>
  76. <div class="content">
  77. <div class="ui radio checkbox">
  78. <input id="users" type="radio" class="shareoption" value="users" name="shareopt" onchange="updateSharePermission(this);">
  79. <label for="users">
  80. <div class="ui header">
  81. <div class="content whiteTheme">
  82. <i class="clipboard check icon"></i> <span locale="share/setting/advance/users">Selected Users</span>
  83. <div class="sub header whiteTheme" locale="share/setting/advance/usersDesc">Selected users with matching user name</div>
  84. </div>
  85. </div>
  86. </label>
  87. </div>
  88. <div id="userselector">
  89. <p style="margin-top: 1em;" locale="share/setting/advance/usersInstruct"">Select target users from the list below</p>
  90. <select id="targetUsersList" class="ui fluid search dropdown" multiple="">
  91. <option value="">Users</option>
  92. </select>
  93. <div id="noUserWarning" class="ui yellow message" style="display:none;">
  94. <i class="caret up icon"></i> <span locale="share/setting/advance/addUserToSave">Add at least one target share user to save changes</span>
  95. </div>
  96. </div>
  97. <div class="ui radio checkbox" style="margin-top: 1em;">
  98. <input id="groups" type="radio" class="shareoption" value="groups" name="shareopt" onchange="updateSharePermission(this);">
  99. <label for="groups">
  100. <div class="ui header">
  101. <div class="content whiteTheme">
  102. <i class="sitemap icon"></i> <span locale="share/setting/advance/groups">Selected Groups</span>
  103. <div class="sub header whiteTheme" locale="share/setting/advance/groupsDesc">All the users that has access to any one of the selected group(s)</div>
  104. </div>
  105. </div>
  106. </label>
  107. </div>
  108. <div id="groupselector">
  109. <p style="margin-top: 1em;" locale="share/setting/advance/groupsInstruct">Select target groups from the list below</p>
  110. <select id="targetGroupList" class="ui fluid search dropdown" multiple="">
  111. <option value="">Groups</option>
  112. </select>
  113. <div id="noGroupWarning" class="ui yellow message" style="display:none;">
  114. <i class="caret up icon"></i> <span locale="share/setting/advance/addGroupToSave">Add at least one target share group to save changes</span>
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. <br><br>
  120. <div id="udpateNotification" style="display:none;" class="ui green inverted segment">
  121. <i class=" checkmark icon"></i> <span locale="share/setting/updated">Share Setting Updated</span>
  122. </div>
  123. </div>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. <div class="ui divider"></div>
  129. <div style="width: 100%; padding-right: 12px;" align="right">
  130. <div class="ui button popupbuttons whiteTheme allowHover" onclick="copyLinkToClipboard(this)">
  131. <i class="copy icon"></i> <span locale="button/copy">Copy</span>
  132. </div>
  133. <div id="sharingRemoveBtn" class="ui red button popupbuttons negative whiteTheme allowHover" onclick="removeSharing()">
  134. <i class="remove icon"></i> <span locale="button/remove">Remove</span>
  135. </div>
  136. </div>
  137. <script>
  138. /*
  139. Usage: Pass in file descriptor to start share a file
  140. var fd = encodeURIComponent(JSON.stringify({
  141. filename: "test.txt",
  142. filepath: "user:/Desktop/test.txt"
  143. })
  144. );
  145. window.open("file_share.html#" + fd);
  146. If you want to preset a file sharing mode (aka your module handle the share mode picking),
  147. Pass in with the "shareMode" paramter. Example fd as follow:
  148. {
  149. filename: "test.txt",
  150. filepath: "user:/Desktop/test.txt",
  151. shareMode: "signedin"
  152. }
  153. To remove a share, pass in "remove" for the share mode
  154. Supported Share Mode keywords {anyone/signedin/samegroup/remove}
  155. */
  156. var shareEditingUUID = "";
  157. var shareingFileData = {};
  158. var initialized = false;
  159. var fileSharingURL = "";
  160. function PageReady(){
  161. if (initialized){
  162. return;
  163. }
  164. //Load User & Group List
  165. $.get(relpath + "../system/users/list", function(data){
  166. var groups = {};
  167. $("#targetUsersList").html(`<option value="">Users</option>`);
  168. data.forEach(user => {
  169. $("#targetUsersList").append(`<option value="${user[0]}">${user[0]}</option>`);
  170. var userGroups = user[1];
  171. userGroups.forEach(thisGroup => {
  172. groups[thisGroup] = true;
  173. });
  174. });
  175. $("#targetGroupList").html(`<option value="">Groups</option>`);
  176. for (var [key, value] of Object.entries(groups)) {
  177. $("#targetGroupList").append(`<option value="${key}">${key}</option>`);
  178. }
  179. });
  180. initialized = true;
  181. //Do localization
  182. applocale.init(relpath + "../SystemAO/locale/file_share.json", function(){
  183. applocale.translate();
  184. });
  185. $(".checkbox").checkbox();
  186. $(".dropdown").dropdown();
  187. $(".accordion").accordion();
  188. var inputFile = ao_module_loadInputFiles();
  189. if (inputFile == null){
  190. //No file selected
  191. $(".shareoption").parent().addClass("disabled");
  192. $("#qrcode").html(`<h1>No File</h1>`);
  193. $("#sharelink").text(``);
  194. $("#sharingRemoveBtn").addClass("disabled");
  195. return
  196. }
  197. //Make sure one file is choicen each time
  198. inputFile = inputFile[0];
  199. shareingFileData = inputFile;
  200. initFileDetails(shareingFileData, function(shareUUID){
  201. //Set the mode of share if it is defined
  202. if (shareingFileData.shareMode !== undefined && shareingFileData.shareMode == "remove"){
  203. //Remove the share UUID
  204. removeSharing();
  205. return;
  206. }
  207. if (shareingFileData.shareMode !== undefined){
  208. //As the share mode is defined by the caller, hide the setting interface
  209. $("#shareSettingOptions").hide();
  210. $.ajax({
  211. url: relpath + "../system/file_system/share/edit",
  212. data: {uuid: shareEditingUUID, mode: shareingFileData.shareMode},
  213. success: function(data){
  214. if (data.error !== undefined){
  215. alert(data.error);
  216. return;
  217. }
  218. //Update the checkbox
  219. $(".shareoption").each(function(){
  220. if ($(this)[0].value != shareingFileData.shareMode){
  221. $(this)[0].checked = false;
  222. }else{
  223. $(this)[0].checked = true;
  224. }
  225. });
  226. }
  227. });
  228. }else{
  229. //Default: show the setting to allow user adjustment
  230. $("#shareSettingOptions").show();
  231. }
  232. });
  233. }
  234. function initFileDetails(shareingFileData, callback=undefined){
  235. $.ajax({
  236. url: relpath + "../system/file_system/share/new",
  237. data: {path: shareingFileData.filepath},
  238. success: function(data){
  239. if (data.error !== undefined){
  240. alert(data.error);
  241. }else{
  242. console.log(data);
  243. updateShareLinkInfo(data.UUID);
  244. shareEditingUUID = data.UUID;
  245. $(".shareoption").each(function(){
  246. if ($(this)[0].value != data.Permission){
  247. $(this)[0].checked = false;
  248. }else{
  249. $(this)[0].checked = true;
  250. if (data.Permission == "users"){
  251. $("#advanceShare").accordion("open", 0);
  252. $("#targetUsersList").dropdown("set selected", data.Accessibles);
  253. $("#targetUsersList").parent().removeClass("disabled");
  254. $("#targetGroupList").parent().addClass("disabled");
  255. }else if (data.Permission == "groups"){
  256. $("#advanceShare").accordion("open", 0);
  257. $("#targetGroupList").dropdown("set selected", data.Accessibles);
  258. $("#targetUsersList").parent().addClass("disabled");
  259. $("#targetGroupList").parent().removeClass("disabled");
  260. }
  261. }
  262. });
  263. $("#targetUsersList").on("change", function(evt){
  264. updateSharePermissionByType("users");
  265. });
  266. $("#targetGroupList").on("change", function(evt){
  267. updateSharePermissionByType("groups");
  268. });
  269. //If the file is from desktop, set share icon
  270. if (ao_module_virtualDesktop == true){
  271. var fileDir = shareingFileData.filepath.split("/");
  272. fileDir.pop();
  273. fileDir = fileDir.join("/");
  274. if (fileDir == "user:/Desktop"){
  275. //Remove share icon
  276. parent.setFileShareIndicator(shareingFileData.filename);
  277. }
  278. }
  279. if (callback != undefined){
  280. callback(data.UUID)
  281. }
  282. }
  283. }
  284. });
  285. }
  286. function removeSharing(){
  287. if (shareEditingUUID == ""){
  288. return
  289. }
  290. //The target file to remove
  291. $.ajax({
  292. url: relpath + "../system/file_system/share/delete",
  293. data: {path: shareingFileData.filepath},
  294. success: function(data){
  295. if (data.error !== undefined){
  296. alert(data.error);
  297. }else{
  298. //Removed!
  299. $(".button").addClass('disabled');
  300. $(".checkbox").addClass("disabled");
  301. $("#sharelink").text("");
  302. $("#sharelink").attr("href", "#");
  303. $("#qrcode").html(`<br><br><h1><i class="green checkmark icon"></i> ${applocale.getString("message/removed", "Share Removed")}</h1>`);
  304. //If the file is located on desktop and it is web desktop mode
  305. if (ao_module_virtualDesktop == true){
  306. var fileDir = shareingFileData.filepath.split("/");
  307. fileDir.pop();
  308. fileDir = fileDir.join("/");
  309. if (fileDir == "user:/Desktop"){
  310. //Remove share icon
  311. parent.removeFileShareIndicator(shareingFileData.filename);
  312. }
  313. }
  314. }
  315. }
  316. });
  317. }
  318. function updateSharePermission(object){
  319. var newPermission = $(object).attr('value');
  320. updateSharePermissionByType(newPermission);
  321. }
  322. function updateSharePermissionByType(newPermission){
  323. if (newPermission == "users"){
  324. //Build the user list
  325. $("#targetUsersList").parent().removeClass("disabled");
  326. $("#targetGroupList").parent().addClass("disabled");
  327. var selectedUsers = $("#targetUsersList").val();
  328. if (selectedUsers.length == 0){
  329. //Show tips message
  330. $("#noUserWarning").slideDown("fast");
  331. return;
  332. }else{
  333. $("#noUserWarning").slideUp("fast");
  334. }
  335. //Rewrite it to permission handling description
  336. newPermission = "users:" + selectedUsers.join(",");
  337. }else if (newPermission == "groups"){
  338. //Build the group list
  339. $("#targetUsersList").parent().addClass("disabled");
  340. $("#targetGroupList").parent().removeClass("disabled");
  341. var selectedGroups = $("#targetGroupList").val();
  342. if (selectedGroups.length == 0){
  343. //Show tips message
  344. $("#noGroupWarning").slideDown("fast");
  345. return;
  346. }else{
  347. $("#noGroupWarning").slideUp("fast");
  348. }
  349. //Rewrite it to permission handling description
  350. newPermission = "groups:" + selectedGroups.join(",");
  351. }
  352. $.ajax({
  353. url: relpath + "../system/file_system/share/edit",
  354. data: {uuid: shareEditingUUID, mode: newPermission},
  355. success: function(data){
  356. if (data.error !== undefined){
  357. alert(data.error);
  358. return;
  359. }
  360. $("#udpateNotification").slideDown("fast").delay(3000).slideUp("fast");
  361. }
  362. });
  363. }
  364. function updateShareLinkInfo(uuid){
  365. $("#qrcode").html("");
  366. let protocol = "https://";
  367. if (location.protocol !== 'https:') {
  368. protocol = "http://";
  369. }
  370. var port = ":" + window.location.port;
  371. if (window.location.port == ""){
  372. port = "";
  373. }
  374. var shareURL = protocol + window.location.hostname + port + "/share/" + uuid;
  375. shareEditingUUID = uuid;
  376. fileSharingURL = shareURL;
  377. new QRCode(document.getElementById("qrcode"), shareURL);
  378. $("#sharelink").text(shareURL);
  379. $("#sharelink").attr("href", shareURL)
  380. }
  381. /*
  382. Dynamic Script Loader
  383. This is a really experimental implementation of importing a script from anywhere
  384. under the ArozOS web root. This section of code must be written in plain JS to make sure
  385. it works without jQuery and other libraries.
  386. This function try to load jQuery and ao_module from the script folder.
  387. Also loading the semantic js and the css main body
  388. */
  389. //The possible location for desktop.system, standard webapp module, SystemAO interfaces and iui sub-interfaces
  390. let possibleLocations = ["script/", "../script/", "../../script/", "../../../script/"];
  391. let loopCount = Math.min(possibleLocations.length, JSON.parse(JSON.stringify(window.location.toString())).split("/").length - 3);
  392. function tryLoad(relpath, filename, successCallback=undefined){
  393. var request = new XMLHttpRequest();
  394. request.open('GET', relpath + filename, true);
  395. request.onreadystatechange = function(){
  396. if (request.readyState === 4){
  397. if (request.status == 200 || request.status == 304) {
  398. if (typeof(successCallback) != "undefined"){
  399. successCallback(relpath, filename);
  400. }
  401. }
  402. }
  403. };
  404. request.send();
  405. }
  406. function injectOtherJavaScriptLibrary(relpath){
  407. //Check if ao_module is loaded
  408. if (typeof(ao_module_virtualDesktop) == "undefined"){
  409. var script = document.createElement('script');
  410. script.setAttribute('src', relpath + "ao_module.js");
  411. document.getElementsByTagName('head')[0].appendChild(script);
  412. }else{
  413. //This routine already run
  414. return;
  415. }
  416. //Inject QR Code library
  417. var script = document.createElement('script');
  418. script.setAttribute('src', relpath + "qrcode.min.js");
  419. document.getElementsByTagName('head')[0].appendChild(script);
  420. //Inject applocale
  421. script = document.createElement('script');
  422. script.setAttribute('src', relpath + "applocale.js");
  423. document.getElementsByTagName('head')[0].appendChild(script);
  424. //Inject semmantic css and js anyway
  425. var head = document.getElementsByTagName('head')[0];
  426. var link = document.createElement('link');
  427. link.id = "semantic";
  428. link.rel = 'stylesheet';
  429. link.type = 'text/css';
  430. link.href = relpath + 'semantic/semantic.min.css';
  431. link.media = 'all';
  432. head.appendChild(link);
  433. var script = document.createElement('script');
  434. script.setAttribute('src', relpath + "semantic/semantic.min.js");
  435. document.getElementsByTagName('head')[0].appendChild(script);
  436. setTimeout(function(){
  437. PageReady();
  438. }, 1000);
  439. }
  440. //Load jQuery first
  441. if (typeof(window.jQuery) == "undefined"){
  442. //jQuery not found. Laod it
  443. for (var i = 0; i < loopCount; i++){
  444. var relpath = possibleLocations[i];
  445. tryLoad(relpath, "jquery.min.js", function(relpath, filename){
  446. //Generate the jquery script element
  447. var script = document.createElement('script');
  448. script.setAttribute('src', relpath + filename);
  449. document.getElementsByTagName('head')[0].appendChild(script);
  450. doAfterJqueryLoaded(function(){
  451. injectOtherJavaScriptLibrary(relpath);
  452. });
  453. });
  454. }
  455. }else{
  456. //jQuery exists. Load ao_module
  457. dynamicLoadAoModule();
  458. }
  459. function doAfterJqueryLoaded(callback){
  460. setTimeout(function(){
  461. //Wait until it is loaded
  462. if (typeof(window.jQuery) == "undefined"){
  463. doAfterJqueryLoaded(callback);
  464. return
  465. }else{
  466. callback();
  467. }
  468. }), 300;
  469. }
  470. function copyLinkToClipboard(btn){
  471. //Copy text
  472. const area = document.createElement('textarea');
  473. document.body.appendChild(area);
  474. area.value = fileSharingURL;
  475. area.select();
  476. document.execCommand('copy');
  477. document.body.removeChild(area);
  478. //Do visual feedback
  479. let oldContent = $(btn).html();
  480. $(btn).html(`<i class="green checkmark icon"></i> ${applocale.getString("button/copied","Copied!")}`);
  481. setTimeout(function(){
  482. $(btn).html(oldContent);
  483. }, 3000);
  484. }
  485. </script>
  486. </body>
  487. </html>