/** UNAS API * UNASDesktop API UNAS.js * Version 1.0.0 for U-NAS OS V3.0 * Copyright (C) WanYou - All Rights Reserved */ /** *Define UNAS namespace *@namespace */ var UNAS = UNAS || {}; UNAS.Version = '1.0.0'; //API Version UNAS.LoginUser = ''; //the logged in user name UNAS.Apps = []; //Loaded Apps, an array of AppInfo UNAS.AppGroups = {};//a collection of App Groups. UNAS.AppGroups.XYZ is XYZ AppGroup. Created automatically through API RegisterToAppGroup(); UNAS.AppGroupsAppNames = {}; UNAS.AppLoaded = false; //AppLoaded State UNAS.ElementCanDrag = true; //Desktop Element can drag or not UNAS.ElementSortType = "gridAlign"; UNAS.CMGridAlignls = {}; //grid align sort ultimately object UNAS.DesktopNavbarImgHeight = 32; //nvabar img width and height UNAS.DesktopNavbarImgWidth = 32; UNAS.DesktopNavbarIconWidth = 40; //navbar icon width and height UNAS.DesktopNavbarIconHeight = 38; UNAS.DesktopDropTarget = "pageWrapper"; UNAS.NavbarSiteNum = {}; // navbar elements position info UNAS.IsDropTarget = "false"; UNAS.isAppCountAllLoad = 1; UNAS.isInit = false; UNAS.isDesktopReady = false; UNAS.UngridAlignApps = []; UNAS.objCount = 0; UNAS.AppCanClick = true; //双击时,避免因网络延迟出现两个DockTab; UNAS.Desktop = {}; //UNAS Desktop, everything related to Desktop UNAS.Desktop.VirtualDesktops = []; //U-NAS supports Multiple Virutual Desktop, Use CreateVirtualDesktop() API to add VD UNAS.Desktop.CurrentVirtualDesktop = 0; //Index of current virtual desktop UNAS.Desktop.CurrentLanguage = "English"; //Current language of the Desktop UNAS.Desktop.Theme = {Name: 'default', Dir: 'default', cssFiles: []}; //Desktop Theme, cssFiles:[{element:, file:}] UNAS.Desktop.Wallpaper = 'desktop/default.jpg'; //Wallpaper file, in referrenc to '/desktop/wallpapers/' UNAS.Desktop.Wallpaper.fit = 'fill'; //Wallpaper fit. default is fill. // UNAS Translation related UNAS.PreviousLanguage = "English"; //Previous language after language changes UNAS.CurrentLanguage = "English"; //Current language UNAS.SupportedLanguages = ["English"]; //List of supported languages UNAS.TranslationTable = {}; //The BIG Translation table, use property rather than array UNAS.LoadedTranslationFiles = []; //An array of the translation files loaded /** *Get all nodes under an element/node. Non-recursive. need optimizaiton. *@param {Element} node - root element *@return {Elements} An array of elements */ UNAS.NodesUnder = function (node) { var elems = []; var array = [], i = 0, k = 0, elementCount = 0, len = 0, childNodes, item; while (node != null) { //console.log(node.tagName); childNodes = node.childNodes; len = node.childNodes.length; elementCount = 0; if (len > 0) { for (i = 0; i < len; i++) { item = childNodes[i]; elems.push(item); if (item.nodeType === 1) { elementCount++; node = item; break; } } for (k = len - 1 ; k > i; k--) { item = childNodes[k]; elems.push(item); if (item.nodeType == 1) { elementCount++; array.push(item); } } if (elementCount < 1) { node = array.pop(); } } else { node = array.pop(); } } return elems; } /** *Save User's desktop information on server, under user's data (LDAP) */ UNAS.SaveUserDesktop = function(){ //collect information needs to be saved, convert to string, and do an ajax save. var desktopInfo = { 'language': UNAS.CurrentLanguage, 'theme': UNAS.Desktop.Theme.Dir, 'wallpaper': UNAS.Desktop.Wallpaper, 'fit':UNAS.Desktop.Wallpaper.fit, 'sortType':UNAS.ElementSortType, 'screenSize':UNAS.GetDesktopPositionInfo("pageWrapper"), 'shortcuts':[] }; for (var i = 0; i < UNAS.Desktop.VirtualDesktops.length; i++) { for (var j = 0; j < UNAS.Desktop.VirtualDesktops[i].Shortcuts.length; j++) { var st = UNAS.Desktop.VirtualDesktops[i].Shortcuts[j]; var img = st.getElementsByTagName("IMG"); var span = st.getElementsByTagName("SPAN"); desktopInfo.shortcuts.push({ vd: i, id: st.id, left: st.style.left, top: st.style.top, width: st.style.width, height: st.style.height, imgWidth: img[0].style.width, imgHeight: img[0].style.height, spanDisplay: span[0].style.display, parentID:st.parentElement.id }); } } if(UNAS.ElementSortType == "ungridAlign"){ UNAS.UngridAlignApps = desktopInfo.shortcuts; } var desktopStr = JSON.stringify(desktopInfo); //desktop info to be saved. var req = new Request({ url: '/api/php/UNASJS.php', method: 'POST', data: { 'DesktopState': desktopStr, 'action': 'SaveDesktop' }, onRequest: function () { }, onSuccess: function (responseText) { //return null or 1 if(!responseText) alert(UNAS._('Save Desktop failed!')); }, onFailure: function () { //alert(UNAS._('Save Desktop failed!')); //导致uncaught exception: out of memory, 堆栈错误 } }); req.send(); } /** *Load User's desktop *call the callback function after user desktop is loaded *@param {Function} callback - Callback function, invoked after User Desktop is loaded */ UNAS.LoadUserDesktop = function (callback) { //note: Admin may change things, such as remove wallpaper/theme, so LoadUserDesktop may cause problem! //Ajax get saved desktop and convert to var req = new Request({ url: '/api/php/UNASJS.php', method: 'POST', data: { 'action': 'LoadDesktop' }, onRequest: function () { }, onSuccess: function (responseText) { if (responseText == null || responseText.length == 0) { //cannot get the saved desktop } else { var desktopInfo = JSON.parse(responseText); if (desktopInfo != null) { UNAS.CurrentLanguage = desktopInfo.language; //need to fire ChangeLanguage event to update the language UNAS.LoadTheme(desktopInfo.theme); UNAS.SetWallpaper(desktopInfo.wallpaper); // for (var i = 0; i < UNAS.Desktop.VirtualDesktops.length; i++) { // for (var j = 0; j < UNAS.Desktop.VirtualDesktops[i].Shortcuts.length; j++) { // var st = UNAS.Desktop.VirtualDesktops[i].Shortcuts[j]; desktopInfo.shortcuts = eval(desktopInfo.shortcuts); jQuery('#pageWrapper > div.abs').html(""); UNAS.Desktop.VirtualDesktops[UNAS.Desktop.CurrentVirtualDesktop].Shortcuts = []; for (var k = 0; k < desktopInfo.shortcuts.length; k++) { // if (desktopInfo.shortcuts[k].id == st.id) { //found the desktop shortcut based on id var appName = desktopInfo.shortcuts[k].id.replace("DesktopShortcut",""); var appInfo = UNAS.GetAppInfo(appName); if(appInfo){ var st = document.getElementById(desktopInfo.shortcuts[k].id); if(!st){ UNAS.DesktopShortcut(appName, appInfo.appIcon, UNAS._(appName), appInfo.appStartFunc); st = document.getElementById(desktopInfo.shortcuts[k].id); } var img = st.getElementsByTagName("IMG"); var span = st.getElementsByTagName("SPAN"); st.style.left = desktopInfo.shortcuts[k].left; st.style.top = desktopInfo.shortcuts[k].top; st.style.width =desktopInfo.shortcuts[k].width; st.style.height=desktopInfo.shortcuts[k].height; img[0].style.width=desktopInfo.shortcuts[k].imgWidth; img[0].style.height=desktopInfo.shortcuts[k].imgHeight; span[0].style.display=desktopInfo.shortcuts[k].spanDisplay; if(st.parentElement.id != desktopInfo.shortcuts[k].parentID ){ //shortcut is not on desktop var elem = document.getElementById(desktopInfo.shortcuts[k].parentID); if (elem != null) { st.parentNode.removeChild(st); elem.appendChild(st);//move to the parent } } // } }else{ continue; } } // } // } var st = desktopInfo.sortType || UNAS.ElementSortType; contextMenuFun._selectedIcon(st,jQuery(document.getElementsByName(st))); if(st == "ungridAlign"){ //非网格排序 UNAS.ElementCanDrag = true; //启用拖动 UNAS.ElementSortType = st; UNAS.UngridAlignApps = desktopInfo.shortcuts; }else if(st == "autoArrange"){ UNAS.ElementSortType = st; var dstpInfo = desktopInfo.screenSize || UNAS.GetDesktopPositionInfo("pageWrapper"); contextMenuFun.__gridGenerateOrderFun(dstpInfo); contextMenuFun.__generateListOrder(); UNAS.ElementCanDrag = false; //禁用拖动 UNAS.__autoArrangeFun(dstpInfo); // if(jQuery(document.getElementById("pageWrapper")).width() != dstpInfo.Sw){ // } }else if(st == "gridAlign"){ UNAS.ElementCanDrag = true; //启用拖动 UNAS.ElementSortType = st; var dstpInfo = desktopInfo.screenSize || UNAS.GetDesktopPositionInfo("pageWrapper"); contextMenuFun.__gridGenerateOrderFun(dstpInfo); if(!desktopInfo.sortType && !desktopInfo.screenSize){ contextMenuFun.__generateListOrder(); } UNAS.__gridAlignFun(dstpInfo); // if(jQuery(document.getElementById("pageWrapper")).width() != dstpInfo.Sw){ // } } } if (callback && typeof callback === "function") { //callback when load is done callback(); } } }, onFailure: function () { alert(UNAS._('Load Desktop failed!')); } }); req.send(); } /** *Get a list of themes available *call the callback function to process the returned theme list *@param {Function} callback - Callback function, invoked after theme list is loaded */ UNAS.GetThemeList = function (callback) { var req = new Request({ url: '/api/php/UNASJS.php', method: 'POST', data: { 'action': 'GetThemeList' }, onRequest: function () { }, onSuccess: function (responseText) { if (!responseText || responseText.length <= 0) { //not found } else { var themeList = JSON.parse(responseText); if (callback && typeof callback === "function") { callback(); } } }, onFailure: function () { alert(UNAS._('Loading Theme List failed!')); } }); req.send(); } /** *Load Theme by name (directory) *@param {String} dir - Theme name, (the directory name on the server) *@param {Function} callback - Callback function, invoked after theme is loaded * */ UNAS.LoadTheme = function (dir, callback) { if (typeof dir !== 'undefined') { //load theme css files via Ajax var req = new Request({ url: '/api/php/UNASJS.php', method: 'POST', data: { 'themeDir': dir, 'action': 'GetTheme' }, onRequest: function () { }, onSuccess: function (responseText) { if (responseText == null || responseText.length == 0) { } else { var themeCSSList = JSON.parse(responseText); if (themeCSSList != null) { //first remove all old css files. for (var i = 0; i < UNAS.Desktop.Theme.cssFiles.length; i++) { if (UNAS.Desktop.Theme.cssFiles[i].element != null) { UNAS.Desktop.Theme.cssFiles[i].element.parentNode.removeChild(UNAS.Desktop.Theme.cssFiles[i].element); //remove one theme css file. } } UNAS.Desktop.Theme.cssFiles = [];//clear all //add new css files var themeCSSCount = themeCSSList.length; for (var i = 0; i < themeCSSList.length; i++) { var elem = UNAS.LoadCSS(themeCSSList[i],function(){ themeCSSCount--; if (themeCSSCount <= 0) { //now all apps loaded var timer = function(){ if(UNAS.isDesktopReady){ jQuery('#unas_desktop_waiting_content').attr("style","display:none"); jQuery('#unas_desktop_waiting_logo').attr("style","display:none"); clearTimeout(timer); }else{ setTimeout(timer,50); } }; timer(); } }); UNAS.Desktop.Theme.cssFiles.push({element:elem,file:themeCSSList[i]}); //keep a record } UNAS.Desktop.Theme.Dir = dir; if (callback && typeof callback === "function") { //load theme is done, callback callback(); } } } }, onFailure: function () { alert(UNAS._('Loading Theme failed!')); } }); req.send(); } } /** *Get the DesktopDock, 'status bar' *@returns {Element} The Desktop Dock element */ UNAS.GetDesktopDock = function(){ return document.getElementById('dockWrapper'); } /** * Get desktopHeader, 'top bar' *@returns {Element} The Desktop Header element */ UNAS.GetDesktopHeader = function(){ return document.getElementById('desktopHeader'); } /** *Get Desktop Wrapper, (it is the wrapper DIV of all Virtual Desktops, 'desktop canvas' *@returns {Element} The Desktop Canvas element */ UNAS.GetDesktopWrapper = function(){ return document.getElementById('pageWrapper'); } /** *Get Current Virtual Desktop DIV, the big wrapper. *@returns {Element} The Desktop Virtual Desktop DIV element */ UNAS.GetCurrentVirtualDesktopDIV = function () { return UNAS.Desktop.VirtualDesktops[UNAS.Desktop.CurrentVirtualDesktop].DIV; } /** *UNAS Create Virtual Desktop *Creates and adds a Virtual Desktop to the array of UNAS.Desktop.VirtalDesktops *@param {String} id - Virutal Deskto id *@param {String} name - Name of the Virtual Desktop */ UNAS.CreateVirtualDesktop = function (id, name) { var vd = { //shoudl we define this in Desktop Definition file? to support customize DIV: document.createElement("div"), VirtualDesktopName: name || '', //default name is empty Left0: 20, Top0: 20, ShortcutLeft: 20, ShortcutTop: 20, ShortcutWidth: 80, ShortcutHeight: 100, ShortcutDeltaX: 80, ShortcutDeltaY: 110, ShortcutIconSize: 48, ShortcutIconsPerColumn: 6, Shortcuts:[] }; vd.id = id || 'unas-virtual-desktop-' + UNAS.Desktop.VirtualDesktops.length; //default id; vd.DIV.className = 'abs'; //CHANGE THIS Class NAME in Theme file!!!!! vd.DIV.style.visibility = 'hidden'; //initially hidden if (typeof UNAS.GetDesktopWrapper() != 'undefined') { UNAS.GetDesktopWrapper().appendChild(vd.DIV); //insert into the desktop UNAS.Desktop.VirtualDesktops.push(vd); //add it in } } /** *Show a Virutal Desktop *@param {Integer} i - Index of the Virtual Destkop */ UNAS.ShowVirtualDesktop = function (i) { if (typeof i === 'undefined') i = UNAS.Desktop.CurrentVirtualDesktop; if (i >= 0 && i < UNAS.Desktop.VirtualDesktops.length) { for (var j = 0; j < UNAS.Desktop.VirtualDesktops.length; j++) UNAS.Desktop.VirtualDesktops[j].DIV.style.visibility = 'hidden';//hide all VDs UNAS.Desktop.CurrentVirtualDesktop = i; UNAS.Desktop.VirtualDesktops[i].DIV.style.visibility = 'visible'; MUI.Windows.windowOptions.container = UNAS.Desktop.VirtualDesktops[i].DIV; //make this Virtual Desktop the container of windows. MochaUI is BUGGY on drag window, need fix. } } /** *UNAS Translate a string *@param {String} str - English ONLY text, could have marks for id *@param {String} lang - The target langauge,use UNAS.CurrentLanguage if not provided *@return {String} Returns the translated text, if a translation does not exist return the original text * example: UNAS._('Hello'); //simple text, no duplicate translations * example: UNAS._('##$@@$##Hello##$@@$##'); * example: UNAS._('##$@1@$##Hello##$@1@$##'); * example: UNAS._('##$@1@$##Hello##$@1@$##' World!); //only part of the string needs to be translated * example: UNAS._('Hi, ##$@1@$##Hello##$@1@$## World. ##$@1@$##Welcome##$@1@$## to U-NAS world.); */ UNAS._ = function (str, lang) { //Translate var lead = '##$@'; //lead mark var end = '@$##'; //end mark var L = end.length; if (typeof (str) === 'undefined') return ""; // lang = lang || UNAS.CurrentLanguage; //just find all the sub strings need to be translated. var ss = str; var subStr = ''; var lPos = ss.indexOf(lead); var ePos = 0; var count = 0; var stringLength = ss.length; if (lPos > -1) { do { var Marker = ''; var Marker2 = ''; var id = ''; subStr = ''; if (lPos > -1) { //found lead mark ePos = ss.indexOf(end); //find end mark, MUST Have. if (ePos > -1) { subStr = ss.substring(lPos, ePos + L); Marker = ss.substring(lPos, ePos + L); id = subStr.replace(lead, ''); //remove lead mar id = id.replace(end, '');//remove end mark and now id is retrieved id = id.trim(); //remove whitespaces from both ends var tmpStr = ss.substring(ePos + L, ss.length); //the rest of the string var A = tmpStr.indexOf(lead); var B = tmpStr.indexOf(end); //find the closing part . if (B > -1) { Marker2 = tmpStr.substring(A, B + L); //end mark subStr = subStr + tmpStr.substring(0, B + L); //found subStr to translate } else { //no close mark, to end subStr = subStr + tmpStr; //found subStr to translate } } else { break; //something is wrong, don't translate. } } var text = subStr.replace(Marker, '');//remove 'lead+id+end',from both ends; this is the real text need to be translated. text = text.replace(Marker2, ''); //remove end.. if (id.length == 0) { id = '0';//default if no id is specifed. } var stest = JSON.stringify(text + lang + id);//test only, remove it after testing var tmp2 = UNAS.TranslationTable[JSON.stringify(text + lang + id)]; //translate to lang. if (tmp2) { //found translation ss = ss.replace(subStr, tmp2); //translate the orignial text } else { ss = ss.replace(subStr, text); //remove the mark, use original text (substring) } lPos = ss.indexOf(lead); count++; } while (lPos > -1 && count <= stringLength); } else { //no mark, translate the whole text var tmp3 = UNAS.TranslationTable[JSON.stringify(ss + lang + '0')]; if (tmp3) ss = tmp3; } return ss; } /** *Find Text nodes under a node *@param {node} node - the root node to be searched *@returns {Nodes} An array of nodes */ UNAS.TextNodesUnder = function (node) { var all = []; for (node = node.firstChild; node; node = node.nextSibling) { if (node.nodeType == 3) all.push(node); else all = all.concat(UNAS.TextNodesUnder(node)); } return all; } /** *UNAS Load Translation files, fire 'SupportedLanguagesChange' event to notify. *@function Dynamically load translation files *@param {String} f - File name to be loaded *@param {Function} callback - Callback function after loading completes */ UNAS.LoadTranslation = function (f,callback) { if(!Array.indexOf){ Array.prototype.indexOf = function(obj){ for(var i=0; i= 0) return; //return if no file or exists //Use Ajax to load the file var xhr = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : (XMLHttpRequest && new XMLHttpRequest()) || null; if (xhr) { xhr.open('GET', f, true); //must be synchronous.... xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ var langs = JSON.parse(xhr.responseText); var langCount = UNAS.SupportedLanguages.length; if (langs != null && typeof langs.UNASTranslation != null) { for (var i = 0; i < langs.UNASTranslation.length; i++) { //array of several languages. if (UNAS.SupportedLanguages.indexOf(langs.UNASTranslation[i].language) < 0) UNAS.SupportedLanguages.push(langs.UNASTranslation[i].language); //added to supportedLanguages var tmp = langs.UNASTranslation[i].table; for (var j = 0; j < tmp.length; j++) { var EnglishText = JSON.stringify(tmp[j][0]).slice(1, -1); //original English Text var tid = JSON.stringify(tmp[j][1]).slice(1, -1); //text id var TranslatedText = JSON.stringify(tmp[j][2]).slice(1, -1); UNAS.TranslationTable[JSON.stringify(EnglishText + langs.UNASTranslation[i].language + tid)] = TranslatedText;//use property rather than array to save the translations! [English -->Lang] UNAS.TranslationTable[JSON.stringify(TranslatedText + 'English' + tid)] = EnglishText;//use property rather than array to save the translations! [Tanslated -->English] } } UNAS.LoadedTranslationFiles.push(f); //add this file into the loaded list to avoid duplicated loading. if (langCount != UNAS.SupportedLanguages.length) { UNAS.Event.fireEvent('SupportedLanguagesChange'); //fire 'SupportedLanguagesChange' event to notify } if (callback && typeof callback === "function") { callback(); } } }else{ alert('error:' + xhr.status); } } else { //alert('Loading Translation file failed!'); } } xhr.send(); } } /** *GetWindow by window id *@param {String} id - Window id *@returns {Window Instance} or null if not found */ UNAS.GetWindow = function (id) { if (typeof id === 'undefined') return null; var win = null; // get all the window instances var instances = MUI.Windows.instances; instances.each(function (instance) { if (instance.options.id === id) { win = instance; return win; } }); return win; } /** *SetWindowTitle based window id *@param {String} id - Window id *@param {String} t - Title for the Window */ UNAS.SetWindowTitle = function (id, t) { var w = UNAS.GetWindow(id); if (w != null) { w.titleEl.set('html', t); } } /** *Translate the page of a window. *call this at the end of the page, not recommend to use *@param {String} window_id - Window id */ UNAS.TranslatePage = function (window_id) { if (typeof window_id === 'undefined') return; var appWin = UNAS.GetWindow(window_id); var pageTranslators = []; //Create an array of Node Translators if (appWin) { pageTranslators = UNAS.CreateNodesTranslators(appWin.windowEl); } //handle Change Language event,use the array of translators. var OnChangeLanguage = function (e) { //we have pageTranslators, just loop it. for (var i = 0; i < pageTranslators.length; i++) { var node = pageTranslators[i].node; // original node var p = pageTranslators[i].translateProperty; //the attribues need to be translated if (typeof node[p] === 'undefined') { node.setAttribute(p, UNAS._(pageTranslators[i].originalText)); } else { node[p] = UNAS._(pageTranslators[i].originalText); //translate } } //your additional code for Language Change... }; OnChangeLanguage(); //change language on loading page //add ChangeLanuage event on loading. UNAS.Event.addEvent('ChangeLanguage', OnChangeLanguage); // remove OnChangeLanguage event the app window is closed addEventSimple(window,'unload', function (e) { UNAS.Event.removeEvent('ChangeLanguage', OnChangeLanguage); }, false); } /** *UNAS.NodeTranslators Creates an array of translators for a root node *@constructor, returns an array of NodeTranslator for a node *@param {node} rootnode - The root node *@returns {Array} an array of translators for a root node */ UNAS.CreateNodesTranslators = function (rootnode) { //first get all textnodes var translators = []; var textnodes = UNAS.TextNodesUnder(rootnode); for (var i = 0; i < textnodes.length; i++) { if (textnodes[i].nodeValue && textnodes[i].nodeValue.length > 0) { var nodeTranslator = {}; nodeTranslator.node = textnodes[i]; //keep a track of node, reference of textnodes nodeTranslator.originalText = textnodes[i].nodeValue; //keep a copy of orginal text, maybe not needed. nodeTranslator.nodeType = textnodes[i].nodeType; //textnode.. nodeTranslator.translateProperty = 'nodeValue'; translators.push(nodeTranslator); } } //then handle all tags (textnode is not a tag) var tags = rootnode.getElementsByTagName('*'); for (var i = 0; i < tags.length; i++) { if (tags[i].title && tags[i].title.length > 0) { var tagTranslator = {}; tagTranslator.node = tags[i]; //keep a track of node, reference of textnodes tagTranslator.originalText = tags[i].title; //keep a copy of orginal text, maybe not needed. tagTranslator.nodeType = tags[i].nodeType; //record node type tagTranslator.translateProperty = 'title'; translators.push(tagTranslator); } } //inputs var inputs = rootnode.getElementsByTagName("input"); //get all inputs under rootnode for (var i = 0; i < inputs.length; i++) { var tagTranslator = {}; tagTranslator.node = inputs[i]; //keep a track of node, reference of textnodes if((inputs[i].type == "button") || (inputs[i].type == "submit")) tagTranslator.originalText = inputs[i].value; //keep a copy of orginal text, maybe not needed. tagTranslator.nodeType = inputs[i].nodeType; //record node type.. if((inputs[i].type == "button") || (inputs[i].type == "submit")) tagTranslator.translateProperty = 'value'; translators.push(tagTranslator); }; //options //select tags may contain options. could have more than one select tags. actually just find all