file_share.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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 id="udpateNotification" style="display:none;" class="ui green inverted segment">
  72. <i class=" checkmark icon"></i> <span locale="share/setting/updated">Share Setting Updated</span>
  73. </div>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. </div>
  79. <div class="ui divider"></div>
  80. <div style="width: 100%; padding-right: 12px;" align="right">
  81. <div class="ui button popupbuttons whiteTheme allowHover" onclick="copyLinkToClipboard(this)">
  82. <i class="copy icon"></i> <span locale="button/copy">Copy</span>
  83. </div>
  84. <div id="sharingRemoveBtn" class="ui red button popupbuttons negative whiteTheme allowHover" onclick="removeSharing()">
  85. <i class="remove icon"></i> <span locale="button/remove">Remove</span>
  86. </div>
  87. </div>
  88. <script>
  89. /*
  90. Usage: Pass in file descriptor to start share a file
  91. var fd = encodeURIComponent(JSON.stringify({
  92. filename: "test.txt",
  93. filepath: "user:/Desktop/test.txt"
  94. })
  95. );
  96. window.open("file_share.html#" + fd);
  97. If you want to preset a file sharing mode (aka your module handle the share mode picking),
  98. Pass in with the "shareMode" paramter. Example fd as follow:
  99. {
  100. filename: "test.txt",
  101. filepath: "user:/Desktop/test.txt",
  102. shareMode: "signedin"
  103. }
  104. To remove a share, pass in "remove" for the share mode
  105. Supported Share Mode keywords {anyone/signedin/samegroup/remove}
  106. */
  107. var shareEditingUUID = "";
  108. var shareingFileData = {};
  109. var initialized = false;
  110. var fileSharingURL = "";
  111. function PageReady(){
  112. if (initialized){
  113. return;
  114. }
  115. initialized = true;
  116. //Do localization
  117. applocale.init(relpath + "../SystemAO/locale/file_share.json", function(){
  118. applocale.translate();
  119. });
  120. $(".checkbox").checkbox();
  121. var inputFile = ao_module_loadInputFiles();
  122. if (inputFile == null){
  123. //No file selected
  124. $(".shareoption").parent().addClass("disabled");
  125. $("#qrcode").html(`<h1>No File</h1>`);
  126. $("#sharelink").text(``);
  127. $("#sharingRemoveBtn").addClass("disabled");
  128. return
  129. }
  130. //Make sure one file is choicen each time
  131. inputFile = inputFile[0];
  132. shareingFileData = inputFile;
  133. initFileDetails(shareingFileData, function(shareUUID){
  134. //Set the mode of share if it is defined
  135. if (shareingFileData.shareMode !== undefined && shareingFileData.shareMode == "remove"){
  136. //Remove the share UUID
  137. removeSharing();
  138. return;
  139. }
  140. if (shareingFileData.shareMode !== undefined){
  141. //As the share mode is defined by the caller, hide the setting interface
  142. $("#shareSettingOptions").hide();
  143. $.ajax({
  144. url: relpath + "../system/file_system/share/edit",
  145. data: {uuid: shareEditingUUID, mode: shareingFileData.shareMode},
  146. success: function(data){
  147. if (data.error !== undefined){
  148. alert(data.error);
  149. return;
  150. }
  151. //Update the checkbox
  152. $(".shareoption").each(function(){
  153. if ($(this)[0].value != shareingFileData.shareMode){
  154. $(this)[0].checked = false;
  155. }else{
  156. $(this)[0].checked = true;
  157. }
  158. });
  159. }
  160. });
  161. }else{
  162. //Default: show the setting to allow user adjustment
  163. $("#shareSettingOptions").show();
  164. }
  165. });
  166. }
  167. function initFileDetails(shareingFileData, callback=undefined){
  168. $.ajax({
  169. url: relpath + "../system/file_system/share/new",
  170. data: {path: shareingFileData.filepath},
  171. success: function(data){
  172. if (data.error !== undefined){
  173. alert(data.error);
  174. }else{
  175. updateShareLinkInfo(data.UUID);
  176. shareEditingUUID = data.UUID;
  177. $(".shareoption").each(function(){
  178. if ($(this)[0].value != data.Permission){
  179. $(this)[0].checked = false;
  180. }else{
  181. $(this)[0].checked = true;
  182. }
  183. });
  184. //If the file is from desktop, set share icon
  185. if (ao_module_virtualDesktop == true){
  186. var fileDir = shareingFileData.filepath.split("/");
  187. fileDir.pop();
  188. fileDir = fileDir.join("/");
  189. if (fileDir == "user:/Desktop"){
  190. //Remove share icon
  191. parent.setFileShareIndicator(shareingFileData.filename);
  192. }
  193. }
  194. if (callback != undefined){
  195. callback(data.UUID)
  196. }
  197. }
  198. }
  199. });
  200. }
  201. function removeSharing(){
  202. if (shareEditingUUID == ""){
  203. return
  204. }
  205. //The target file to remove
  206. $.ajax({
  207. url: relpath + "../system/file_system/share/delete",
  208. data: {path: shareingFileData.filepath},
  209. success: function(data){
  210. if (data.error !== undefined){
  211. alert(data.error);
  212. }else{
  213. //Removed!
  214. $(".button").addClass('disabled');
  215. $(".checkbox").addClass("disabled");
  216. $("#sharelink").text("");
  217. $("#sharelink").attr("href", "#");
  218. $("#qrcode").html(`<br><br><h1><i class="green checkmark icon"></i> ${applocale.getString("message/removed", "Share Removed")}</h1>`);
  219. //If the file is located on desktop and it is web desktop mode
  220. if (ao_module_virtualDesktop == true){
  221. var fileDir = shareingFileData.filepath.split("/");
  222. fileDir.pop();
  223. fileDir = fileDir.join("/");
  224. if (fileDir == "user:/Desktop"){
  225. //Remove share icon
  226. parent.removeFileShareIndicator(shareingFileData.filename);
  227. }
  228. }
  229. }
  230. }
  231. });
  232. }
  233. function updateSharePermission(object){
  234. var newPermission = $(object).attr('value');
  235. $.ajax({
  236. url: relpath + "../system/file_system/share/edit",
  237. data: {uuid: shareEditingUUID, mode: newPermission},
  238. success: function(data){
  239. if (data.error !== undefined){
  240. alert(data.error);
  241. return;
  242. }
  243. $("#udpateNotification").slideDown("fast").delay(3000).slideUp("fast");
  244. }
  245. });
  246. }
  247. function updateShareLinkInfo(uuid){
  248. $("#qrcode").html("");
  249. let protocol = "https://";
  250. if (location.protocol !== 'https:') {
  251. protocol = "http://";
  252. }
  253. var port = ":" + window.location.port;
  254. if (window.location.port == ""){
  255. port = "";
  256. }
  257. var shareURL = protocol + window.location.hostname + port + "/share/" + uuid;
  258. shareEditingUUID = uuid;
  259. fileSharingURL = shareURL;
  260. new QRCode(document.getElementById("qrcode"), shareURL);
  261. $("#sharelink").text(shareURL);
  262. $("#sharelink").attr("href", shareURL)
  263. }
  264. /*
  265. Dynamic Script Loader
  266. This is a really experimental implementation of importing a script from anywhere
  267. under the ArozOS web root. This section of code must be written in plain JS to make sure
  268. it works without jQuery and other libraries.
  269. This function try to load jQuery and ao_module from the script folder.
  270. Also loading the semantic js and the css main body
  271. */
  272. //The possible location for desktop.system, standard webapp module, SystemAO interfaces and iui sub-interfaces
  273. let possibleLocations = ["script/", "../script/", "../../script/", "../../../script/"];
  274. let loopCount = Math.min(possibleLocations.length, JSON.parse(JSON.stringify(window.location.toString())).split("/").length - 3);
  275. function tryLoad(relpath, filename, successCallback=undefined){
  276. var request = new XMLHttpRequest();
  277. request.open('GET', relpath + filename, true);
  278. request.onreadystatechange = function(){
  279. if (request.readyState === 4){
  280. if (request.status == 200 || request.status == 304) {
  281. if (typeof(successCallback) != "undefined"){
  282. successCallback(relpath, filename);
  283. }
  284. }
  285. }
  286. };
  287. request.send();
  288. }
  289. function injectOtherJavaScriptLibrary(relpath){
  290. //Check if ao_module is loaded
  291. if (typeof(ao_module_virtualDesktop) == "undefined"){
  292. var script = document.createElement('script');
  293. script.setAttribute('src', relpath + "ao_module.js");
  294. document.getElementsByTagName('head')[0].appendChild(script);
  295. }else{
  296. //This routine already run
  297. return;
  298. }
  299. //Inject QR Code library
  300. var script = document.createElement('script');
  301. script.setAttribute('src', relpath + "qrcode.min.js");
  302. document.getElementsByTagName('head')[0].appendChild(script);
  303. //Inject applocale
  304. script = document.createElement('script');
  305. script.setAttribute('src', relpath + "applocale.js");
  306. document.getElementsByTagName('head')[0].appendChild(script);
  307. //Inject semmantic css and js anyway
  308. var head = document.getElementsByTagName('head')[0];
  309. var link = document.createElement('link');
  310. link.id = "semantic";
  311. link.rel = 'stylesheet';
  312. link.type = 'text/css';
  313. link.href = relpath + 'semantic/semantic.min.css';
  314. link.media = 'all';
  315. head.appendChild(link);
  316. var script = document.createElement('script');
  317. script.setAttribute('src', relpath + "semantic/semantic.min.js");
  318. document.getElementsByTagName('head')[0].appendChild(script);
  319. setTimeout(function(){
  320. PageReady();
  321. }, 1000);
  322. }
  323. //Load jQuery first
  324. if (typeof(window.jQuery) == "undefined"){
  325. //jQuery not found. Laod it
  326. for (var i = 0; i < loopCount; i++){
  327. var relpath = possibleLocations[i];
  328. tryLoad(relpath, "jquery.min.js", function(relpath, filename){
  329. //Generate the jquery script element
  330. var script = document.createElement('script');
  331. script.setAttribute('src', relpath + filename);
  332. document.getElementsByTagName('head')[0].appendChild(script);
  333. doAfterJqueryLoaded(function(){
  334. injectOtherJavaScriptLibrary(relpath);
  335. });
  336. });
  337. }
  338. }else{
  339. //jQuery exists. Load ao_module
  340. dynamicLoadAoModule();
  341. }
  342. function doAfterJqueryLoaded(callback){
  343. setTimeout(function(){
  344. //Wait until it is loaded
  345. if (typeof(window.jQuery) == "undefined"){
  346. doAfterJqueryLoaded(callback);
  347. return
  348. }else{
  349. callback();
  350. }
  351. }), 300;
  352. }
  353. function copyLinkToClipboard(btn){
  354. //Copy text
  355. const area = document.createElement('textarea');
  356. document.body.appendChild(area);
  357. area.value = fileSharingURL;
  358. area.select();
  359. document.execCommand('copy');
  360. document.body.removeChild(area);
  361. //Do visual feedback
  362. let oldContent = $(btn).html();
  363. $(btn).html(`<i class="green checkmark icon"></i> ${applocale.getString("button/copied","Copied!")}`);
  364. setTimeout(function(){
  365. $(btn).html(oldContent);
  366. }, 3000);
  367. }
  368. </script>
  369. </body>
  370. </html>