ao_module.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. ArOZ Online Module API wrapper
  3. This script is used for wrapping all the API that can be called by the ArOZ Online Module under VDI mode.
  4. For faster development, please include this script into your module and call through this script.
  5. Or otherwise, you can call directly to the ArOZ Online System via GET / POST request.
  6. <!> Warning! This script require jQuery to work.
  7. Although some functions might not require jquery, it is still recommended. You can include the jquery file from
  8. AOR/script/jquery.min.js
  9. Toby Chui @ IMUS Laboratory, All Right Reserved
  10. */
  11. //Check if current module is called in Virtal Desktop Mode
  12. var ao_module_virtualDesktop = !(!parent.isFunctionBar);
  13. //Get the current windowID if in Virtual Desktop Mode, return false if VDI is not detected
  14. var ao_module_windowID = false;
  15. var ao_module_parentID = false;
  16. var ao_module_callback = false;
  17. if (ao_module_virtualDesktop)ao_module_windowID = $(window.frameElement).parent().attr("id");
  18. if (ao_module_virtualDesktop)ao_module_parentID = $(window.frameElement).parent().find(".floatWindow").attr("puid");
  19. if (ao_module_virtualDesktop)ao_module_callback = $(window.frameElement).parent().find(".floatWindow").attr("callback");
  20. //Set the current FloatWindow with specified icon
  21. function ao_module_setWindowIcon(icon){
  22. if (ao_module_virtualDesktop){
  23. parent.setWindowIcon(ao_module_windowID + "",icon);
  24. return true;
  25. }
  26. return false;
  27. }
  28. //Set the current FloatWindow with specified title tag
  29. function ao_module_setWindowTitle(title){
  30. if (ao_module_virtualDesktop){
  31. parent.changeWindowTitle(ao_module_windowID + "",title);
  32. return true;
  33. }
  34. return false;
  35. }
  36. //Set the current FloatWindow to GlassEffect Window (Cannot switch back to origianl mode)
  37. function ao_module_setGlassEffectMode(){
  38. if (ao_module_virtualDesktop){
  39. parent.setGlassEffectMode(ao_module_windowID + "");
  40. return true;
  41. }
  42. return false;
  43. }
  44. //Set the current FloatWindow to Fixed Size Window (Non-resizable), default Resizable
  45. function ao_module_setFixedWindowSize(){
  46. if (ao_module_virtualDesktop){
  47. parent.setWindowFixedSize(ao_module_windowID + "");
  48. return true;
  49. }
  50. return false;
  51. }
  52. //Set the current FloatWindow size (width, height)
  53. function ao_module_setWindowSize(w,h){
  54. if (ao_module_virtualDesktop){
  55. parent.setWindowPreferdSize(ao_module_windowID + "",w,h);
  56. return true;
  57. }
  58. return false;
  59. }
  60. //Close the current window
  61. function ao_module_close(){
  62. if (ao_module_virtualDesktop){
  63. parent.closeWindow(ao_module_windowID);
  64. return true;
  65. }
  66. return false;
  67. }
  68. //Get the windows that is running the given module name and return an id list for floatWindow
  69. function ao_module_getProcessID(modulename){
  70. if (ao_module_virtualDesktop){
  71. return parent.getWindowFromModule(modulename);
  72. }
  73. return false;
  74. }
  75. //Crashed
  76. function ao_module_declareCrash(crashmsg){
  77. return false;
  78. }
  79. //Open file selector
  80. /**
  81. * File Explorer powered by ArOZ Online File System
  82. * To pop up a file selector and return an object of files, you can call the following function with the given variable.
  83. * For example, this is a function which FFmpeg Factory calls to the file selector
  84. *
  85. * ao_module_openFileSelector("FFFSelector","addFileFromSelector",undefined,undefined,true);
  86. * This will allow the file selector get files (as selectMode default value is "file") and allow multiple selections
  87. * The selectMode option provide modes for file / folder / mix, where mix means user can select both files and folders
  88. * The allowMultiple means if the user can select multiple files. True for allow and false for disallow multi selections.
  89. *
  90. * To catch the callback of the selector, you can put the following script into your callBack function (In this case, 'addFileFromSelector')
  91. *
  92. * function addFileFromSelector(fileData){
  93. * result = JSON.parse(fileData);
  94. * for (var i=0; i < result.length; i++){
  95. * var filename = result[i].filename;
  96. * var filepath = result[i].filepath;
  97. * //DO SOMETHING HERE
  98. * }
  99. * }
  100. *
  101. * REMINDER
  102. * If you call this function in default mode, please use the "ao_module_openFileSelectorTab" and pass in the relative location of AOR (Root of ArOZ) as the first variable.
  103. * You will also need to handle the listen of chnage in the uid in localStorage for cross tab communication
  104. **/
  105. function ao_module_openFileSelector(uid,callBackFunctionName, windowWidth = 1080, windowHeight = 645, allowMultiple = false, selectMode = "file"){
  106. //selectMode: file / folder / mix
  107. //allowMultiple: true / false
  108. if (allowMultiple){
  109. allowMultiple = "true";
  110. }else{
  111. allowMultiple = "false";
  112. }
  113. if (ao_module_virtualDesktop){
  114. //Launch inside VDI
  115. ao_module_newfw("SystemAOB/functions/file_system/fileSelector.php?allowMultiple=" + allowMultiple + "&selectMode=" + selectMode,"Starting file selector","spinner",uid,windowWidth,windowHeight,ao_module_getLeft() + 30,ao_module_getTop() + 30,undefined,undefined,ao_module_windowID,callBackFunctionName);
  116. return true;
  117. }else{
  118. return false;
  119. }
  120. }
  121. //Request file selection OUTSIDE OF VDI MODE (REQUIRE localStorage)
  122. /**
  123. This function can be used to call the file selector in non-VDI mode.
  124. The following example shows the method of calling, similar to that in VDI mode.
  125. Assume we have a module at AOR/Dummy/index.php, the script running in that module has an aor = ../
  126. ao_module_openFileSelectorTab("RamdomUUID","../",true,"file",fileProcesser);
  127. //fileProcessor will catch the file selection
  128. function fileProcesser(fileData){
  129. result = JSON.parse(fileData);
  130. for (var i=0; i < result.length; i++){
  131. var filename = result[i].filename;
  132. var filepath = result[i].filepath;
  133. //DO SOMETHING HERE
  134. }
  135. }
  136. **/
  137. var ao_module_fileSelectorCallBack,ao_module_fileSelectorWindowObject,ao_module_fileSelectorReplyObject,ao_module_fileSelectorFileAwait;
  138. function ao_module_openFileSelectorTab(uid, aor,allowMultiple = false, selectMode = "file",callBack=console.log){
  139. //selectMode: file / folder / mix
  140. //allowMultiple: true / false
  141. if (allowMultiple){
  142. allowMultiple = "true";
  143. }else{
  144. allowMultiple = "false";
  145. }
  146. if (aor.slice(-1) != "/"){
  147. aor = aor + "/";
  148. }
  149. ao_module_fileSelectorReplyObject = uid;
  150. ao_module_fileSelectorCallBack = callBack;
  151. var windowObject = window.open(aor + "/SystemAOB/functions/file_system/fileSelector.php?allowMultiple=" + allowMultiple + "&selectMode=" + selectMode + "&puid=" + uid);
  152. ao_module_fileSelectorWindowObject = windowObject;
  153. ao_module_fileSelectorFileAwait = setInterval(ao_module_listenFileSelectionInput,5000);
  154. return windowObject;
  155. }
  156. //Cross-tab File Selector Listener for File Selector Callback purpose. This is not a usable function. Do not touch this function.
  157. function ao_module_listenFileSelectionInput(){
  158. var ao_module_fileSelectorReturnedFiles = ao_module_readTmp(ao_module_fileSelectorReplyObject);
  159. if (ao_module_fileSelectorReturnedFiles == false && ao_module_fileSelectorReturnedFiles.length == undefined){
  160. }else{
  161. //File found! Closing all selection windows and load the files
  162. clearInterval(ao_module_fileSelectorFileAwait);
  163. if (ao_module_fileSelectorReturnedFiles.length == 0){
  164. //Cancel selection
  165. ao_module_fileSelectorCallBack(JSON.stringify([]));
  166. }else{
  167. ao_module_fileSelectorWindowObject.close();
  168. ao_module_removeTmp(ao_module_fileSelectorReplyObject);
  169. ao_module_fileSelectorReplyObject = undefined;
  170. ao_module_fileSelectorCallBack(JSON.stringify(ao_module_fileSelectorReturnedFiles));
  171. }
  172. }
  173. }
  174. //Open an ArOZ Online Path with the given targetPath from ArOZ Online Root
  175. /**
  176. For example, if you want to open the folder:
  177. "AOR/Audio/uploads/"
  178. Then you can call this function as follow:
  179. ao_module_openPath("Audio/uploads");
  180. **/
  181. function ao_module_openPath(targetPath, windowWidth = 1080, windowHeight = 580,posx = undefined,posy = undefined){
  182. if (ao_module_virtualDesktop){
  183. var uid = Math.floor(Date.now() / 1000);
  184. parent.newEmbededWindow("SystemAOB/functions/file_system/index.php?controlLv=2&subdir=" + targetPath, "Loading", "folder open outline",uid,windowWidth,windowHeight,posx,posy);
  185. return uid;
  186. }
  187. return false;
  188. }
  189. //Open an ArOZ Online File with the given targetPath and filename (display name) from ArOZ Online Root
  190. /**
  191. For example, if you want to open the file:
  192. "AOR/Desktop/files/admin/helloworld.txt"
  193. Then you can call this function as follow:
  194. ao_module_openFile("Desktop/files/admin/helloworld.txt","helloworld.txt");
  195. The targetpath can be something different from the filename (display name). For example, an encoded file with path:
  196. "Desktop/files/TC/inithe38090e5b08fe9878ee5b48ee4babae38091546f75686f754d4144202d20546f75686f752026204e69746f72692047657420446f776e2120282b6c797269632920e380904844e38091205b373230705d.mp4"
  197. can be opened with filename
  198. "【小野崎人】TouhouMAD - Touhou %26 Nitori Get Down! (+lyric) 【HD】 [720p].mp4" with the following command:
  199. ao_module_openFile("Desktop/files/TC/inithe38090e5b08fe9878ee5b48ee4babae38091546f75686f754d4144202d20546f75686f752026204e69746f72692047657420446f776e2120282b6c797269632920e380904844e38091205b373230705d.mp4","【小野崎人】TouhouMAD - Touhou %26 Nitori Get Down! (+lyric) 【HD】 [720p].mp4");
  200. **/
  201. function ao_module_openFile(targetPath,filename){
  202. if (ao_module_virtualDesktop){
  203. parent.newEmbededWindow("SystemAOB/functions/file_system/index.php?controlLv=2&mode=file&dir=" + targetPath + "&filename=" + filename, filename, "file outline","fileOpenMiddleWare",0,0,-10,-10);
  204. return true;
  205. }
  206. return false;
  207. }
  208. //Open a FloatWindow
  209. /**
  210. Example 1: opening the Memo index with the following code:
  211. ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',475,700);
  212. Example 2: opening the Memo index with minimal parameter:
  213. ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded');
  214. Example 3: opening a sub-module and tell the sub-module the parent's window id that is not yourself:
  215. ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',undefined,undefined,undefined,undefined,undefined,undefined,"someoneElseUID");
  216. Example 4: opening a sub-module and ask for a callback: (Default parentUID is set to this module's WindowID and hence, the call back will be called to this content window)
  217. ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',undefined,undefined,undefined,undefined,undefined,undefined,undefined,"callBackFunctionName");
  218. Reminder:
  219. - If you open multiple windows with the same UID, the previous one will be overwritten and reload to the latest page.
  220. - windowname parameter must not contain chars that cannot be put inside an id field (e.g. "&", "." etc)
  221. - For a list of icons, please reference https://tocas-ui.com/elements/icon/
  222. **/
  223. function ao_module_newfw(src,windowname,icon,uid,sizex = undefined,sizey = undefined,posx = undefined,posy = undefined,fixsize = undefined,glassEffect = undefined,parentUID=null, callbackFunct=null){
  224. if (parentUID === null){
  225. parentUID = ao_module_windowID;
  226. }
  227. if (ao_module_virtualDesktop){
  228. parent.newEmbededWindow(src,windowname,icon,uid,sizex,sizey,posx,posy,fixsize,glassEffect,parentUID,callbackFunct);
  229. return true;
  230. }
  231. return false;
  232. }
  233. //Request fullscreen access from VDI module
  234. function ao_module_fullScreen(){
  235. if (ao_module_virtualDesktop){
  236. parent.openFullscreen();
  237. return true;
  238. }
  239. return false;
  240. }
  241. //Get the basic information of the floatWindows (including the width, height, left and top value)
  242. function ao_module_getWidth(){
  243. if (ao_module_virtualDesktop){
  244. return parent.document.getElementById(ao_module_windowID).offsetWidth;
  245. }else{
  246. return -1;
  247. }
  248. }
  249. function ao_module_getHeight(){
  250. if (ao_module_virtualDesktop){
  251. return parent.document.getElementById(ao_module_windowID).offsetHeight;
  252. }else{
  253. return -1;
  254. }
  255. }
  256. function ao_module_getLeft(){
  257. if (ao_module_virtualDesktop){
  258. return parent.document.getElementById(ao_module_windowID).getBoundingClientRect().left;
  259. }else{
  260. return -1;
  261. }
  262. }
  263. function ao_module_getTop(){
  264. if (ao_module_virtualDesktop){
  265. return parent.document.getElementById(ao_module_windowID).getBoundingClientRect().top;
  266. }else{
  267. return -1;
  268. }
  269. }
  270. //Showing msgbox at the notification side bar
  271. /**
  272. For example, the most basic use of this command will be:
  273. ao_module_msgbox("This is a demo message from the aroz online module.","Hello World");
  274. You can add more object to the message including HTML tags in msg and title, and redirection path for opening the target etc.
  275. If auto close = false, the side bar will not get hidden after 4 seconds.
  276. **/
  277. function ao_module_msgbox(warningMsg,title="",redirectpath="",autoclose=true){
  278. if (ao_module_virtualDesktop){
  279. parent.msgbox(warningMsg,title,redirectpath,autoclose);
  280. return true;
  281. }
  282. return false;
  283. }
  284. //Focus this floatWindow and bring it to the front
  285. /**
  286. This function bring the current floatWindow content to the front of all FloatWindows.
  287. Please use this only in urgent / warning information. This might bring interuption to user's operation and making them unhappy.
  288. **/
  289. function ao_module_focus(){
  290. parent.focusFloatWindow(ao_module_windowID);
  291. }
  292. //Return the object in which the main interface iframe (The most backgound iframe. Mostly Desktop when you are using VDI mode. But you can change it if required).
  293. function ao_module_callToInterface(){
  294. return parent.callToInterface();
  295. }
  296. //Cross iFrame communication pipeline
  297. /**
  298. This function can send data to parent callback function if necessary.
  299. Data has to be an data object
  300. Given the following condition
  301. parentID: test
  302. callback: setBackgroundColor
  303. with a function named setBackgroundColor(data) in the parent window (iframe)
  304. Then you can use the following example to send data to the parent frame
  305. Example: ao_module_parentCallback({color:"white"});
  306. The returned value will be the data object in stringify JSON.
  307. To get the original value of the data received by another window:
  308. function ao_module_parentCallback(data){
  309. object = (JSON.parse(data));
  310. console.log(object.color);
  311. }
  312. Console output:
  313. >>white
  314. **/
  315. function ao_module_parentCallback(data){
  316. if (ao_module_virtualDesktop && ao_module_parentID !== undefined && ao_module_callback !== undefined){
  317. data = JSON.stringify(data);
  318. var ao_module_parentTarget = parent.getWindowObjectFromID(ao_module_parentID);
  319. if (ao_module_parentTarget !== null){
  320. ao_module_parentTarget.eval(ao_module_callback + "('" + data + "')");
  321. return true;
  322. }else{
  323. return false;
  324. }
  325. }else{
  326. return false;
  327. }
  328. }
  329. /**
  330. REMINDER
  331. When your module require save and loading data from localStorage, we recommend using the naming method as follow.
  332. [ModuleName]_[Username]_[Properties].
  333. For example, you are developing a new "MusicMixer" Module and want to store the "songList" properties for user "Admin". Then the recommended localStorage syntax will be:
  334. MusicMixer_Admin_songList
  335. Example:
  336. ao_module_getStorage("MusicMixer_Admin_songList");
  337. ao_module_saveStorage("MusicMixer_Admin_songList","{some JSON string here}");
  338. **/
  339. //Load something from localStorage with given tag
  340. function ao_module_getStorage(moduleName,username,itemname){
  341. moduleName = moduleName.split("_").join("-");
  342. username = username.split("_").join("-");
  343. itemname = itemname.split("_").join("-");
  344. return localStorage.getItem(moduleName + "_" + username + "_" + itemname);
  345. }
  346. //Save something into localStoarge with give tag and value
  347. function ao_module_saveStorage(moduleName,username,itemname,value){
  348. moduleName = moduleName.split("_").join("-");
  349. username = username.split("_").join("-");
  350. itemname = itemname.split("_").join("-");
  351. localStorage.setItem(moduleName + "_" + username + "_" + itemname, value);
  352. return true;
  353. }
  354. //Write something to tmp, which can be used as callback or anything that is not important
  355. //The value can also be an object
  356. function ao_module_writeTmp(uid,value){
  357. uid = "tmp_" + uid;
  358. localStorage.setItem(uid,JSON.stringify(value));
  359. }
  360. function ao_module_readTmp(uid){
  361. uid = "tmp_" + uid;
  362. var value = localStorage.getItem(uid);
  363. if (value == null || value == "null"){
  364. return false;
  365. }
  366. return JSON.parse(value);
  367. }
  368. function ao_module_removeTmp(uid){
  369. uid = "tmp_" + uid;
  370. if (ao_module_readTmp(uid) == false){
  371. localStorage.removeItem(uid);
  372. }
  373. }
  374. //Check if the storage exists on this browser or not
  375. function ao_module_checkStorage(id){
  376. if (typeof(Storage) !== "undefined") {
  377. return true;
  378. } else {
  379. return false;
  380. }
  381. }
  382. class ao_module_codec{
  383. //Decode umfilename into standard filename in utf-8, which umfilename usually start with "inith"
  384. //Example: ao_module_codec.decodeUmFilename(umfilename_here);
  385. static decodeUmFilename(umfilename){
  386. if (umfilename.includes("inith")){
  387. var data = umfilename.split(".");
  388. var extension = data.pop();
  389. var filename = data[0];
  390. filename = filename.replace("inith",""); //Javascript replace only remove the first instances (i.e. the first inith in filename)
  391. var decodedname = ao_module_codec.decode_utf8(ao_module_codec.hex2bin(filename));
  392. if (decodedname != "false"){
  393. //This is a umfilename
  394. return decodedname + "." + extension;
  395. }else{
  396. //This is not a umfilename
  397. return umfilename;
  398. }
  399. }else{
  400. //This is not umfilename as it doesn't have the inith prefix
  401. return umfilename;
  402. }
  403. }
  404. //Decode hexFoldername into standard foldername in utf-8, return the original name if it is not a hex foldername
  405. //Example: ao_module_codec.decodeHexFoldername(hexFolderName_here);
  406. static decodeHexFoldername(folderName){
  407. var decodedFoldername = ao_module_codec.decode_utf8(ao_module_codec.hex2bin(folderName));
  408. if (decodedFoldername == "false"){
  409. //This is not a hex encoded foldername
  410. decodedFoldername = folderName;
  411. }else{
  412. //This is a hex encoded foldername
  413. decodedFoldername = "*" + decodedFoldername;
  414. }
  415. return decodedFoldername;
  416. }
  417. static hex2bin(s){
  418. var ret = []
  419. var i = 0
  420. var l
  421. s += ''
  422. for (l = s.length; i < l; i += 2) {
  423. var c = parseInt(s.substr(i, 1), 16)
  424. var k = parseInt(s.substr(i + 1, 1), 16)
  425. if (isNaN(c) || isNaN(k)) return false
  426. ret.push((c << 4) | k)
  427. }
  428. return String.fromCharCode.apply(String, ret)
  429. }
  430. static decode_utf8(s) {
  431. return decodeURIComponent(escape(s));
  432. }
  433. }
  434. /**
  435. Screenshot related functions
  436. This function make use of the html2canvas JavaScript library. For license and author, please refer to the html2canvas.js head section.
  437. target value are used to defined the operation after the screenshot.
  438. default / newWindow --> Open screenshot in new window
  439. dataurl --> return data url of the image as string
  440. canvas --> return the canvas object
  441. **/
  442. //Updates Removed Screenshot feature due to waste of resources
  443. /**
  444. //Take a screenshot from module body
  445. function ao_html2canvas_screenshot(target="newWindow",callback){
  446. if (typeof html2canvas != undefined){
  447. html2canvas(document.body).then(function(canvas) {
  448. if (target == "newWindow"){
  449. window.open(canvas.toDataURL("image/png"), '_blank');
  450. return true;
  451. }else if (target == "dataurl"){
  452. callback(canvas.toDataURL("image/png"));
  453. }else if (target == "canvas"){
  454. callback(canvas);
  455. }else{
  456. window.open(canvas.toDataURL("image/png"), '_blank');
  457. return true;
  458. }
  459. });
  460. }else{
  461. return false;
  462. }
  463. }
  464. function ao_html2canvas_getPreview(w,h){
  465. if (typeof html2canvas != undefined){
  466. html2canvas(document.body,{width: w,height: h}).then(function(canvas) {
  467. parent.updatePreview(canvas);
  468. });
  469. }else{
  470. return false;
  471. }
  472. }
  473. **/