/* ArOZ Online Module API wrapper This script is used for wrapping all the API that can be called by the ArOZ Online Module under VDI mode. For faster development, please include this script into your module and call through this script. Or otherwise, you can call directly to the ArOZ Online System via GET / POST request. Warning! This script require jQuery to work. Although some functions might not require jquery, it is still recommended. You can include the jquery file from AOR/script/jquery.min.js Toby Chui @ IMUS Laboratory, All Right Reserved */ //Check if current module is called in Virtal Desktop Mode var ao_module_virtualDesktop = !(!parent.isFunctionBar); //Get the current windowID if in Virtual Desktop Mode, return false if VDI is not detected var ao_module_windowID = false; var ao_module_parentID = false; var ao_module_callback = false; if (ao_module_virtualDesktop)ao_module_windowID = $(window.frameElement).parent().attr("id"); if (ao_module_virtualDesktop)ao_module_parentID = $(window.frameElement).parent().find(".floatWindow").attr("puid"); if (ao_module_virtualDesktop)ao_module_callback = $(window.frameElement).parent().find(".floatWindow").attr("callback"); //Set the current FloatWindow with specified icon function ao_module_setWindowIcon(icon){ if (ao_module_virtualDesktop){ parent.setWindowIcon(ao_module_windowID + "",icon); return true; } return false; } //Set the current FloatWindow with specified title tag function ao_module_setWindowTitle(title){ if (ao_module_virtualDesktop){ parent.changeWindowTitle(ao_module_windowID + "",title); return true; } return false; } //Set the current FloatWindow to GlassEffect Window (Cannot switch back to origianl mode) function ao_module_setGlassEffectMode(){ if (ao_module_virtualDesktop){ parent.setGlassEffectMode(ao_module_windowID + ""); return true; } return false; } //Set the current FloatWindow to Fixed Size Window (Non-resizable), default Resizable function ao_module_setFixedWindowSize(){ if (ao_module_virtualDesktop){ parent.setWindowFixedSize(ao_module_windowID + ""); return true; } return false; } //Set the current FloatWindow size (width, height) function ao_module_setWindowSize(w,h){ if (ao_module_virtualDesktop){ parent.setWindowPreferdSize(ao_module_windowID + "",w,h); return true; } return false; } //Close the current window function ao_module_close(){ if (ao_module_virtualDesktop){ parent.closeWindow(ao_module_windowID); return true; } return false; } //Get the windows that is running the given module name and return an id list for floatWindow function ao_module_getProcessID(modulename){ if (ao_module_virtualDesktop){ return parent.getWindowFromModule(modulename); } return false; } //Crashed function ao_module_declareCrash(crashmsg){ return false; } //Open file selector /** * File Explorer powered by ArOZ Online File System * To pop up a file selector and return an object of files, you can call the following function with the given variable. * For example, this is a function which FFmpeg Factory calls to the file selector * * ao_module_openFileSelector("FFFSelector","addFileFromSelector",undefined,undefined,true); * This will allow the file selector get files (as selectMode default value is "file") and allow multiple selections * The selectMode option provide modes for file / folder / mix, where mix means user can select both files and folders * The allowMultiple means if the user can select multiple files. True for allow and false for disallow multi selections. * * To catch the callback of the selector, you can put the following script into your callBack function (In this case, 'addFileFromSelector') * * function addFileFromSelector(fileData){ * result = JSON.parse(fileData); * for (var i=0; i < result.length; i++){ * var filename = result[i].filename; * var filepath = result[i].filepath; * //DO SOMETHING HERE * } * } * * REMINDER * 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. * You will also need to handle the listen of chnage in the uid in localStorage for cross tab communication **/ function ao_module_openFileSelector(uid,callBackFunctionName, windowWidth = 1080, windowHeight = 645, allowMultiple = false, selectMode = "file"){ //selectMode: file / folder / mix //allowMultiple: true / false if (allowMultiple){ allowMultiple = "true"; }else{ allowMultiple = "false"; } if (ao_module_virtualDesktop){ //Launch inside VDI 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); return true; }else{ return false; } } //Request file selection OUTSIDE OF VDI MODE (REQUIRE localStorage) /** This function can be used to call the file selector in non-VDI mode. The following example shows the method of calling, similar to that in VDI mode. Assume we have a module at AOR/Dummy/index.php, the script running in that module has an aor = ../ ao_module_openFileSelectorTab("RamdomUUID","../",true,"file",fileProcesser); //fileProcessor will catch the file selection function fileProcesser(fileData){ result = JSON.parse(fileData); for (var i=0; i < result.length; i++){ var filename = result[i].filename; var filepath = result[i].filepath; //DO SOMETHING HERE } } **/ var ao_module_fileSelectorCallBack,ao_module_fileSelectorWindowObject,ao_module_fileSelectorReplyObject,ao_module_fileSelectorFileAwait; function ao_module_openFileSelectorTab(uid, aor,allowMultiple = false, selectMode = "file",callBack=console.log){ //selectMode: file / folder / mix //allowMultiple: true / false if (allowMultiple){ allowMultiple = "true"; }else{ allowMultiple = "false"; } if (aor.slice(-1) != "/"){ aor = aor + "/"; } ao_module_fileSelectorReplyObject = uid; ao_module_fileSelectorCallBack = callBack; var windowObject = window.open(aor + "/SystemAOB/functions/file_system/fileSelector.php?allowMultiple=" + allowMultiple + "&selectMode=" + selectMode + "&puid=" + uid); ao_module_fileSelectorWindowObject = windowObject; ao_module_fileSelectorFileAwait = setInterval(ao_module_listenFileSelectionInput,5000); return windowObject; } //Cross-tab File Selector Listener for File Selector Callback purpose. This is not a usable function. Do not touch this function. function ao_module_listenFileSelectionInput(){ var ao_module_fileSelectorReturnedFiles = ao_module_readTmp(ao_module_fileSelectorReplyObject); if (ao_module_fileSelectorReturnedFiles == false && ao_module_fileSelectorReturnedFiles.length == undefined){ }else{ //File found! Closing all selection windows and load the files clearInterval(ao_module_fileSelectorFileAwait); if (ao_module_fileSelectorReturnedFiles.length == 0){ //Cancel selection ao_module_fileSelectorCallBack(JSON.stringify([])); }else{ ao_module_fileSelectorWindowObject.close(); ao_module_removeTmp(ao_module_fileSelectorReplyObject); ao_module_fileSelectorReplyObject = undefined; ao_module_fileSelectorCallBack(JSON.stringify(ao_module_fileSelectorReturnedFiles)); } } } //Open an ArOZ Online Path with the given targetPath from ArOZ Online Root /** For example, if you want to open the folder: "AOR/Audio/uploads/" Then you can call this function as follow: ao_module_openPath("Audio/uploads"); **/ function ao_module_openPath(targetPath, windowWidth = 1080, windowHeight = 580,posx = undefined,posy = undefined){ if (ao_module_virtualDesktop){ var uid = Math.floor(Date.now() / 1000); parent.newEmbededWindow("SystemAOB/functions/file_system/index.php?controlLv=2&subdir=" + targetPath, "Loading", "folder open outline",uid,windowWidth,windowHeight,posx,posy); return uid; } return false; } //Open an ArOZ Online File with the given targetPath and filename (display name) from ArOZ Online Root /** For example, if you want to open the file: "AOR/Desktop/files/admin/helloworld.txt" Then you can call this function as follow: ao_module_openFile("Desktop/files/admin/helloworld.txt","helloworld.txt"); The targetpath can be something different from the filename (display name). For example, an encoded file with path: "Desktop/files/TC/inithe38090e5b08fe9878ee5b48ee4babae38091546f75686f754d4144202d20546f75686f752026204e69746f72692047657420446f776e2120282b6c797269632920e380904844e38091205b373230705d.mp4" can be opened with filename "【小野崎人】TouhouMAD - Touhou %26 Nitori Get Down! (+lyric) 【HD】 [720p].mp4" with the following command: ao_module_openFile("Desktop/files/TC/inithe38090e5b08fe9878ee5b48ee4babae38091546f75686f754d4144202d20546f75686f752026204e69746f72692047657420446f776e2120282b6c797269632920e380904844e38091205b373230705d.mp4","【小野崎人】TouhouMAD - Touhou %26 Nitori Get Down! (+lyric) 【HD】 [720p].mp4"); **/ function ao_module_openFile(targetPath,filename){ if (ao_module_virtualDesktop){ parent.newEmbededWindow("SystemAOB/functions/file_system/index.php?controlLv=2&mode=file&dir=" + targetPath + "&filename=" + filename, filename, "file outline","fileOpenMiddleWare",0,0,-10,-10); return true; } return false; } //Open a FloatWindow /** Example 1: opening the Memo index with the following code: ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',475,700); Example 2: opening the Memo index with minimal parameter: ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded'); Example 3: opening a sub-module and tell the sub-module the parent's window id that is not yourself: ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',undefined,undefined,undefined,undefined,undefined,undefined,"someoneElseUID"); 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) ao_module_newfw('Memo/index.php','Memo','sticky note outline','memoEmbedded',undefined,undefined,undefined,undefined,undefined,undefined,undefined,"callBackFunctionName"); Reminder: - If you open multiple windows with the same UID, the previous one will be overwritten and reload to the latest page. - windowname parameter must not contain chars that cannot be put inside an id field (e.g. "&", "." etc) - For a list of icons, please reference https://tocas-ui.com/elements/icon/ **/ function ao_module_newfw(src,windowname,icon,uid,sizex = undefined,sizey = undefined,posx = undefined,posy = undefined,fixsize = undefined,glassEffect = undefined,parentUID=null, callbackFunct=null){ if (parentUID === null){ parentUID = ao_module_windowID; } if (ao_module_virtualDesktop){ parent.newEmbededWindow(src,windowname,icon,uid,sizex,sizey,posx,posy,fixsize,glassEffect,parentUID,callbackFunct); return true; } return false; } //Request fullscreen access from VDI module function ao_module_fullScreen(){ if (ao_module_virtualDesktop){ parent.openFullscreen(); return true; } return false; } //Get the basic information of the floatWindows (including the width, height, left and top value) function ao_module_getWidth(){ if (ao_module_virtualDesktop){ return parent.document.getElementById(ao_module_windowID).offsetWidth; }else{ return -1; } } function ao_module_getHeight(){ if (ao_module_virtualDesktop){ return parent.document.getElementById(ao_module_windowID).offsetHeight; }else{ return -1; } } function ao_module_getLeft(){ if (ao_module_virtualDesktop){ return parent.document.getElementById(ao_module_windowID).getBoundingClientRect().left; }else{ return -1; } } function ao_module_getTop(){ if (ao_module_virtualDesktop){ return parent.document.getElementById(ao_module_windowID).getBoundingClientRect().top; }else{ return -1; } } //Showing msgbox at the notification side bar /** For example, the most basic use of this command will be: ao_module_msgbox("This is a demo message from the aroz online module.","Hello World"); You can add more object to the message including HTML tags in msg and title, and redirection path for opening the target etc. If auto close = false, the side bar will not get hidden after 4 seconds. **/ function ao_module_msgbox(warningMsg,title="",redirectpath="",autoclose=true){ if (ao_module_virtualDesktop){ parent.msgbox(warningMsg,title,redirectpath,autoclose); return true; } return false; } //Focus this floatWindow and bring it to the front /** This function bring the current floatWindow content to the front of all FloatWindows. Please use this only in urgent / warning information. This might bring interuption to user's operation and making them unhappy. **/ function ao_module_focus(){ parent.focusFloatWindow(ao_module_windowID); } //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). function ao_module_callToInterface(){ return parent.callToInterface(); } //Cross iFrame communication pipeline /** This function can send data to parent callback function if necessary. Data has to be an data object Given the following condition parentID: test callback: setBackgroundColor with a function named setBackgroundColor(data) in the parent window (iframe) Then you can use the following example to send data to the parent frame Example: ao_module_parentCallback({color:"white"}); The returned value will be the data object in stringify JSON. To get the original value of the data received by another window: function ao_module_parentCallback(data){ object = (JSON.parse(data)); console.log(object.color); } Console output: >>white **/ function ao_module_parentCallback(data){ if (ao_module_virtualDesktop && ao_module_parentID !== undefined && ao_module_callback !== undefined){ data = JSON.stringify(data); var ao_module_parentTarget = parent.getWindowObjectFromID(ao_module_parentID); if (ao_module_parentTarget !== null){ ao_module_parentTarget.eval(ao_module_callback + "('" + data + "')"); return true; }else{ return false; } }else{ return false; } } /** REMINDER When your module require save and loading data from localStorage, we recommend using the naming method as follow. [ModuleName]_[Username]_[Properties]. 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: MusicMixer_Admin_songList Example: ao_module_getStorage("MusicMixer_Admin_songList"); ao_module_saveStorage("MusicMixer_Admin_songList","{some JSON string here}"); **/ //Load something from localStorage with given tag function ao_module_getStorage(moduleName,username,itemname){ moduleName = moduleName.split("_").join("-"); username = username.split("_").join("-"); itemname = itemname.split("_").join("-"); return localStorage.getItem(moduleName + "_" + username + "_" + itemname); } //Save something into localStoarge with give tag and value function ao_module_saveStorage(moduleName,username,itemname,value){ moduleName = moduleName.split("_").join("-"); username = username.split("_").join("-"); itemname = itemname.split("_").join("-"); localStorage.setItem(moduleName + "_" + username + "_" + itemname, value); return true; } //Write something to tmp, which can be used as callback or anything that is not important //The value can also be an object function ao_module_writeTmp(uid,value){ uid = "tmp_" + uid; localStorage.setItem(uid,JSON.stringify(value)); } function ao_module_readTmp(uid){ uid = "tmp_" + uid; var value = localStorage.getItem(uid); if (value == null || value == "null"){ return false; } return JSON.parse(value); } function ao_module_removeTmp(uid){ uid = "tmp_" + uid; if (ao_module_readTmp(uid) == false){ localStorage.removeItem(uid); } } //Check if the storage exists on this browser or not function ao_module_checkStorage(id){ if (typeof(Storage) !== "undefined") { return true; } else { return false; } } class ao_module_codec{ //Decode umfilename into standard filename in utf-8, which umfilename usually start with "inith" //Example: ao_module_codec.decodeUmFilename(umfilename_here); static decodeUmFilename(umfilename){ if (umfilename.includes("inith")){ var data = umfilename.split("."); var extension = data.pop(); var filename = data[0]; filename = filename.replace("inith",""); //Javascript replace only remove the first instances (i.e. the first inith in filename) var decodedname = ao_module_codec.decode_utf8(ao_module_codec.hex2bin(filename)); if (decodedname != "false"){ //This is a umfilename return decodedname + "." + extension; }else{ //This is not a umfilename return umfilename; } }else{ //This is not umfilename as it doesn't have the inith prefix return umfilename; } } //Decode hexFoldername into standard foldername in utf-8, return the original name if it is not a hex foldername //Example: ao_module_codec.decodeHexFoldername(hexFolderName_here); static decodeHexFoldername(folderName){ var decodedFoldername = ao_module_codec.decode_utf8(ao_module_codec.hex2bin(folderName)); if (decodedFoldername == "false"){ //This is not a hex encoded foldername decodedFoldername = folderName; }else{ //This is a hex encoded foldername decodedFoldername = "*" + decodedFoldername; } return decodedFoldername; } static hex2bin(s){ var ret = [] var i = 0 var l s += '' for (l = s.length; i < l; i += 2) { var c = parseInt(s.substr(i, 1), 16) var k = parseInt(s.substr(i + 1, 1), 16) if (isNaN(c) || isNaN(k)) return false ret.push((c << 4) | k) } return String.fromCharCode.apply(String, ret) } static decode_utf8(s) { return decodeURIComponent(escape(s)); } } /** Screenshot related functions This function make use of the html2canvas JavaScript library. For license and author, please refer to the html2canvas.js head section. target value are used to defined the operation after the screenshot. default / newWindow --> Open screenshot in new window dataurl --> return data url of the image as string canvas --> return the canvas object **/ //Updates Removed Screenshot feature due to waste of resources /** //Take a screenshot from module body function ao_html2canvas_screenshot(target="newWindow",callback){ if (typeof html2canvas != undefined){ html2canvas(document.body).then(function(canvas) { if (target == "newWindow"){ window.open(canvas.toDataURL("image/png"), '_blank'); return true; }else if (target == "dataurl"){ callback(canvas.toDataURL("image/png")); }else if (target == "canvas"){ callback(canvas); }else{ window.open(canvas.toDataURL("image/png"), '_blank'); return true; } }); }else{ return false; } } function ao_html2canvas_getPreview(w,h){ if (typeof html2canvas != undefined){ html2canvas(document.body,{width: w,height: h}).then(function(canvas) { parent.updatePreview(canvas); }); }else{ return false; } } **/