mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	1. Fix populating g_allowUserViewAllDomainAccounts flag. This was implemented incorrectly and caused flag's effect to not reflect directly after login. 2. Filter account/project names only for add operation. update template permissions API is implemented in such a way that it allows removal of any account that could have had permissions but allows only adding accounts/projects which are in caller's domain. 3. Added some checks where null variable could result in crash.
		
			
				
	
	
		
			512 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			512 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Licensed to the Apache Software Foundation (ASF) under one
 | |
| // or more contributor license agreements.  See the NOTICE file
 | |
| // distributed with this work for additional information
 | |
| // regarding copyright ownership.  The ASF licenses this file
 | |
| // to you under the Apache License, Version 2.0 (the
 | |
| // "License"); you may not use this file except in compliance
 | |
| // with the License.  You may obtain a copy of the License at
 | |
| //
 | |
| //   http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing,
 | |
| // software distributed under the License is distributed on an
 | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | |
| // KIND, either express or implied.  See the License for the
 | |
| // specific language governing permissions and limitations
 | |
| // under the License.
 | |
| (function(cloudStack, $) {
 | |
|     $.extend(cloudStack, {
 | |
|         home: 'dashboard',
 | |
| 
 | |
|         sectionPreFilter: function(args) {
 | |
|             var sections = [];
 | |
| 
 | |
|             if (isAdmin()) {
 | |
|                 sections = ["dashboard", "instances", "storage", "network", "templates", "roles", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"];
 | |
|             } else if (isDomainAdmin()) {
 | |
|                 sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "configuration", "regions", "affinityGroups"];
 | |
|             } else if (g_userProjectsEnabled) {
 | |
|                 sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions", "affinityGroups"];
 | |
|             } else { //normal user
 | |
|                 sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "regions", "affinityGroups"];
 | |
|             }
 | |
| 
 | |
|             $.each(cloudStack.plugins, function(idx, plugin) {
 | |
|                 if (cloudStack.sections.hasOwnProperty(plugin) && !cloudStack.sections[plugin].showOnNavigation) {
 | |
|                     sections.push('plugins');
 | |
|                     return false;
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|             return sections;
 | |
|         },
 | |
|         sections: {
 | |
|             /**
 | |
|              * Dashboard
 | |
|              */
 | |
|             dashboard: {},
 | |
|             instances: {},
 | |
|             affinityGroups: {},
 | |
|             storage: {},
 | |
|             network: {},
 | |
|             templates: {},
 | |
|             events: {},
 | |
|             projects: {},
 | |
|             roles: {},
 | |
|             accounts: {},
 | |
| 
 | |
|             domains: {}, //domain-admin and root-admin only
 | |
| 
 | |
|             regions: {}, //root-admin only
 | |
|             system: {}, //root-admin only
 | |
|             'global-settings': {}, //root-admin only
 | |
|             configuration: {}, //root-admin only
 | |
|             plugins: {}
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     $(window).bind('cloudStack.pluginReady', function() {
 | |
|         // Get language
 | |
|         g_lang = $.cookie('lang') ? $.cookie('lang') : 'en';
 | |
| 
 | |
|         /**
 | |
|          * Generic error handling
 | |
|          */
 | |
| 
 | |
|         $.ajaxSetup({
 | |
|             url: clientApiUrl,
 | |
|             async: true,
 | |
|             dataType: 'json',
 | |
|             cache: false,
 | |
|             error: function(data) {
 | |
|                 var clickAction = false;
 | |
|                 if (isValidJsonString(data.responseText)) {
 | |
|                     var json = JSON.parse(data.responseText);
 | |
|                     if (json != null) {
 | |
|                         var property;
 | |
|                         for (property in json) {}
 | |
|                         var errorObj = json[property];
 | |
|                         if (errorObj.errorcode == 401 && errorObj.errortext == "unable to verify user credentials and/or request signature") {
 | |
|                             clickAction = function() {
 | |
|                                 $('#user-options a').eq(0).trigger('click');
 | |
|                             };
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 cloudStack.dialog.notice({
 | |
|                     message: parseXMLHttpResponse(data),
 | |
|                     clickAction: clickAction
 | |
|                 });
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         var $container = $('#cloudStack3-container');
 | |
| 
 | |
|         var loginArgs = {
 | |
|             $container: $container,
 | |
| 
 | |
|             // Use this for checking the session, to bypass login screen
 | |
|             bypassLoginCheck: function(args) { //determine to show or bypass login screen
 | |
|                 if (g_loginResponse == null) { //show login screen
 | |
|                     var unBoxCookieValue = function (cookieName) {
 | |
|                         return decodeURIComponent($.cookie(cookieName)).replace(/"([^"]+(?="))"/g, '$1');
 | |
|                     };
 | |
|                     // sessionkey is a HttpOnly cookie now, no need to pass as API param
 | |
|                     g_sessionKey = null;
 | |
|                     g_role = unBoxCookieValue('role');
 | |
|                     g_userid = unBoxCookieValue('userid');
 | |
|                     g_domainid = unBoxCookieValue('domainid');
 | |
|                     g_account = unBoxCookieValue('account');
 | |
|                     g_username = unBoxCookieValue('username');
 | |
|                     g_userfullname = unBoxCookieValue('userfullname');
 | |
|                     g_timezone = unBoxCookieValue('timezone');
 | |
|                     g_timezoneoffset = unBoxCookieValue('timezoneoffset');
 | |
|                 } else { //single-sign-on (bypass login screen)
 | |
|                     g_sessionKey = encodeURIComponent(g_loginResponse.sessionkey);
 | |
|                     g_role = g_loginResponse.type;
 | |
|                     g_username = g_loginResponse.username;
 | |
|                     g_userid = g_loginResponse.userid;
 | |
|                     g_account = g_loginResponse.account;
 | |
|                     g_domainid = g_loginResponse.domainid;
 | |
|                     g_userfullname = g_loginResponse.firstname + ' ' + g_loginResponse.lastname;
 | |
|                     g_timezone = g_loginResponse.timezone;
 | |
|                     g_timezoneoffset = g_loginResponse.timezoneoffset;
 | |
|                 }
 | |
| 
 | |
|                 var userValid = false;
 | |
|                 $.ajax({
 | |
|                     url: createURL("listCapabilities"),
 | |
|                     dataType: "json",
 | |
|                     async: false,
 | |
|                     success: function(json) {
 | |
|                         g_capabilities = json.listcapabilitiesresponse.capability;
 | |
|                         g_supportELB = json.listcapabilitiesresponse.capability.supportELB.toString(); //convert boolean to string if it's boolean
 | |
|                         g_kvmsnapshotenabled = json.listcapabilitiesresponse.capability.kvmsnapshotenabled; //boolean
 | |
|                         g_regionsecondaryenabled = json.listcapabilitiesresponse.capability.regionsecondaryenabled; //boolean
 | |
|                         if (json.listcapabilitiesresponse.capability.userpublictemplateenabled != null) {
 | |
|                             g_userPublicTemplateEnabled = json.listcapabilitiesresponse.capability.userpublictemplateenabled.toString(); //convert boolean to string if it's boolean
 | |
|                         }
 | |
| 
 | |
|                         g_allowUserExpungeRecoverVm = json.listcapabilitiesresponse.capability.allowuserexpungerecovervm;
 | |
|                         g_userProjectsEnabled = json.listcapabilitiesresponse.capability.allowusercreateprojects;
 | |
| 
 | |
|                         g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion;
 | |
|                         // Allow users to see all accounts within a domain
 | |
|                         g_allowUserViewAllDomainAccounts = json.listcapabilitiesresponse.capability.allowuserviewalldomainaccounts;
 | |
| 
 | |
|                         if (json.listcapabilitiesresponse.capability.apilimitinterval != null && json.listcapabilitiesresponse.capability.apilimitmax != null) {
 | |
|                             var intervalLimit = ((json.listcapabilitiesresponse.capability.apilimitinterval * 1000) / json.listcapabilitiesresponse.capability.apilimitmax) * 3; //multiply 3 to be on safe side
 | |
|                             //intervalLimit = 9999; //this line is for testing only, comment it before check in
 | |
|                             if (intervalLimit > g_queryAsyncJobResultInterval)
 | |
|                                 g_queryAsyncJobResultInterval = intervalLimit;
 | |
|                         }
 | |
| 
 | |
|                         userValid = true;
 | |
|                     },
 | |
|                     error: function(xmlHTTP) { //override default error handling, do nothing instead of showing error "unable to verify user credentials" on login screen
 | |
|                     },
 | |
|                     beforeSend: function(XMLHttpResponse) {
 | |
|                         return true;
 | |
|                     }
 | |
|                 });
 | |
| 
 | |
|                 // Update global pagesize for list APIs in UI
 | |
|                 $.ajax({
 | |
|                     type: 'GET',
 | |
|                     url: createURL('listConfigurations'),
 | |
|                     data: {name: 'default.ui.page.size'},
 | |
|                     dataType: 'json',
 | |
|                     async: false,
 | |
|                     success: function(data, textStatus, xhr) {
 | |
|                         if (data && data.listconfigurationsresponse && data.listconfigurationsresponse.configuration) {
 | |
|                             var config = data.listconfigurationsresponse.configuration[0];
 | |
|                             if (config && config.name == 'default.ui.page.size') {
 | |
|                                 pageSize = parseInt(config.value);
 | |
|                             }
 | |
|                         }
 | |
|                     },
 | |
|                     error: function(xhr) { // ignore any errors, fallback to the default
 | |
|                     }
 | |
|                 });
 | |
| 
 | |
|                 // Update global pagesize for sort key in UI
 | |
|                 $.ajax({
 | |
|                     type: 'GET',
 | |
|                     url: createURL('listConfigurations'),
 | |
|                     data: {name: 'sortkey.algorithm'},
 | |
|                     dataType: 'json',
 | |
|                     async: false,
 | |
|                     success: function(data, textStatus, xhr) {
 | |
|                         if (data && data.listconfigurationsresponse && data.listconfigurationsresponse.configuration) {
 | |
|                             var config = data.listconfigurationsresponse.configuration[0];
 | |
|                             if (config && config.name == 'sortkey.algorithm') {
 | |
|                                 g_sortKeyIsAscending = config.value == 'true';
 | |
|                             }
 | |
|                         }
 | |
|                     },
 | |
|                     error: function(xhr) { // ignore any errors, fallback to the default
 | |
|                     }
 | |
|                 });
 | |
| 
 | |
|                 // Populate IDP list
 | |
|                 $.ajax({
 | |
|                     type: 'GET',
 | |
|                     url: createURL('listIdps'),
 | |
|                     dataType: 'json',
 | |
|                     async: false,
 | |
|                     success: function(data, textStatus, xhr) {
 | |
|                         if (data && data.listidpsresponse && data.listidpsresponse.idp) {
 | |
|                             var idpList = data.listidpsresponse.idp.sort(function (a, b) {
 | |
|                                 return a.orgName.localeCompare(b.orgName);
 | |
|                             });
 | |
|                             g_idpList = idpList;
 | |
|                         }
 | |
|                     },
 | |
|                     error: function(xhr) {
 | |
|                     }
 | |
|                 });
 | |
| 
 | |
|                 return userValid ? {
 | |
|                     user: {
 | |
|                         userid: g_userid,
 | |
|                         username: g_username,
 | |
|                         account: g_account,
 | |
|                         name: g_userfullname,
 | |
|                         role: g_role,
 | |
|                         domainid: g_domainid
 | |
|                     }
 | |
|                 } : false;
 | |
|             },
 | |
| 
 | |
|             // Actual login process, via form
 | |
|             loginAction: function(args) {
 | |
|                 var array1 = [];
 | |
|                 array1.push("&username=" + encodeURIComponent(args.data.username));
 | |
| 
 | |
|                 cloudStack.addPasswordToCommandUrlParameterArray(array1, args.data.password);
 | |
|                 var domain;
 | |
|                 if (args.data.domain != null && args.data.domain.length > 0) {
 | |
|                     if (args.data.domain.charAt(0) != "/")
 | |
|                         domain = "/" + args.data.domain;
 | |
|                     else
 | |
|                         domain = args.data.domain;
 | |
|                     array1.push("&domain=" + encodeURIComponent(domain));
 | |
|                 } else {
 | |
|                     array1.push("&domain=" + encodeURIComponent("/"));
 | |
|                 }
 | |
| 
 | |
|                 var loginCmdText = array1.join("");
 | |
| 
 | |
|                 $.ajax({
 | |
|                     type: "POST",
 | |
|                     data: "command=login" + loginCmdText + "&response=json",
 | |
|                     dataType: "json",
 | |
|                     async: false,
 | |
|                     success: function(json) {
 | |
|                         var loginresponse = json.loginresponse;
 | |
|                         // sessionkey is recevied as a HttpOnly cookie
 | |
|                         // therefore reset any g_sessionKey value, an explicit
 | |
|                         // param in the API call is no longer needed
 | |
|                         g_sessionKey = null;
 | |
|                         g_role = loginresponse.type;
 | |
|                         g_username = loginresponse.username;
 | |
|                         g_userid = loginresponse.userid;
 | |
|                         g_account = loginresponse.account;
 | |
|                         g_domainid = loginresponse.domainid;
 | |
|                         g_timezone = loginresponse.timezone;
 | |
|                         g_timezoneoffset = loginresponse.timezoneoffset;
 | |
|                         g_userfullname = loginresponse.firstname + ' ' + loginresponse.lastname;
 | |
| 
 | |
|                         $.cookie('username', g_username, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('account', g_account, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('domainid', g_domainid, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('role', g_role, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('timezone', g_timezone, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('timezoneoffset', g_timezoneoffset, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('userfullname', g_userfullname, {
 | |
|                             expires: 1
 | |
|                         });
 | |
|                         $.cookie('userid', g_userid, {
 | |
|                             expires: 1
 | |
|                         });
 | |
| 
 | |
|                         $.ajax({
 | |
|                             url: createURL("listCapabilities"),
 | |
|                             dataType: "json",
 | |
|                             async: false,
 | |
|                             success: function(json) {
 | |
|                                 g_capabilities = json.listcapabilitiesresponse.capability;
 | |
|                                 g_supportELB = json.listcapabilitiesresponse.capability.supportELB.toString(); //convert boolean to string if it's boolean
 | |
|                                 g_kvmsnapshotenabled = json.listcapabilitiesresponse.capability.kvmsnapshotenabled; //boolean
 | |
|                                 g_regionsecondaryenabled = json.listcapabilitiesresponse.capability.regionsecondaryenabled; //boolean
 | |
|                                 if (json.listcapabilitiesresponse.capability.userpublictemplateenabled != null) {
 | |
|                                     g_userPublicTemplateEnabled = json.listcapabilitiesresponse.capability.userpublictemplateenabled.toString(); //convert boolean to string if it's boolean
 | |
|                                 }
 | |
|                                 g_allowUserExpungeRecoverVm = json.listcapabilitiesresponse.capability.allowuserexpungerecovervm;
 | |
|                                 g_userProjectsEnabled = json.listcapabilitiesresponse.capability.allowusercreateprojects;
 | |
| 
 | |
|                                 g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion;
 | |
|                                 // Allow users to see all accounts within a domain
 | |
|                                 g_allowUserViewAllDomainAccounts = json.listcapabilitiesresponse.capability.allowuserviewalldomainaccounts;
 | |
| 
 | |
|                                 if (json.listcapabilitiesresponse.capability.apilimitinterval != null && json.listcapabilitiesresponse.capability.apilimitmax != null) {
 | |
|                                     var intervalLimit = ((json.listcapabilitiesresponse.capability.apilimitinterval * 1000) / json.listcapabilitiesresponse.capability.apilimitmax) * 3; //multiply 3 to be on safe side
 | |
|                                     //intervalLimit = 8888; //this line is for testing only, comment it before check in
 | |
|                                     if (intervalLimit > g_queryAsyncJobResultInterval)
 | |
|                                         g_queryAsyncJobResultInterval = intervalLimit;
 | |
|                                 }
 | |
| 
 | |
|                                 args.response.success({
 | |
|                                     data: {
 | |
|                                         user: $.extend(true, {}, loginresponse, {
 | |
|                                             name: loginresponse.firstname + ' ' + loginresponse.lastname,
 | |
|                                             role: loginresponse.type == 1 ? 'admin' : 'user',
 | |
|                                             type: loginresponse.type
 | |
|                                         })
 | |
|                                     }
 | |
|                                 });
 | |
|                             },
 | |
|                             error: function(xmlHTTP) {
 | |
|                                 args.response.error();
 | |
|                             }
 | |
|                         });
 | |
| 
 | |
|                         // Get project configuration
 | |
|                         // TEMPORARY -- replace w/ output of capability response, etc., once implemented
 | |
|                         window.g_projectsInviteRequired = false;
 | |
|                     },
 | |
|                     error: function(XMLHttpRequest) {
 | |
|                         var errorMsg = parseXMLHttpResponse(XMLHttpRequest);
 | |
|                         if (errorMsg.length == 0 && XMLHttpRequest.status == 0)
 | |
|                             errorMsg = dictionary['error.unable.to.reach.management.server'];
 | |
|                         else
 | |
|                             errorMsg = _l('error.invalid.username.password'); //override error message
 | |
|                         args.response.error(errorMsg);
 | |
|                     },
 | |
|                     beforeSend: function(XMLHttpResponse) {
 | |
|                         return true;
 | |
|                     }
 | |
|                 });
 | |
|             },
 | |
| 
 | |
|             logoutAction: function(args) {
 | |
|                 $.ajax({
 | |
|                     url: createURL('logout'),
 | |
|                     async: false,
 | |
|                     success: function() {
 | |
|                         g_sessionKey = null;
 | |
|                         g_username = null;
 | |
|                         g_account = null;
 | |
|                         g_domainid = null;
 | |
|                         g_timezoneoffset = null;
 | |
|                         g_timezone = null;
 | |
|                         g_supportELB = null;
 | |
|                         g_kvmsnapshotenabled = null;
 | |
|                         g_regionsecondaryenabled = null;
 | |
|                         g_loginCmdText = null;
 | |
|                         g_allowUserViewAllDomainAccounts = null;
 | |
| 
 | |
|                         // Remove any cookies
 | |
|                         var cookies = document.cookie.split(";");
 | |
|                         for (var i = 0; i < cookies.length; i++) {
 | |
|                             var cookieName = $.trim(cookies[i].split("=")[0]);
 | |
|                             if (['login-option', 'lang'].indexOf(cookieName) < 0) {
 | |
|                                 $.cookie(cookieName, null);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         if (onLogoutCallback()) { //onLogoutCallback() will set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen.
 | |
|                             document.location.reload(); //when onLogoutCallback() returns true, reload the current document.
 | |
|                         }
 | |
|                     },
 | |
|                     error: function() {
 | |
|                         if (onLogoutCallback()) { //onLogoutCallback() will set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen.
 | |
|                             document.location.reload(); //when onLogoutCallback() returns true, reload the current document.
 | |
|                         }
 | |
|                     },
 | |
|                     beforeSend: function(XMLHttpResponse) {
 | |
|                         return true;
 | |
|                     }
 | |
|                 });
 | |
|             },
 | |
| 
 | |
|             samlLoginAction: function(args) {
 | |
|                 g_sessionKey = null;
 | |
|                 g_username = null;
 | |
|                 g_account = null;
 | |
|                 g_domainid = null;
 | |
|                 g_timezoneoffset = null;
 | |
|                 g_timezone = null;
 | |
|                 g_supportELB = null;
 | |
|                 g_kvmsnapshotenabled = null;
 | |
|                 g_regionsecondaryenabled = null;
 | |
|                 g_loginCmdText = null;
 | |
|                 g_allowUserViewAllDomainAccounts = null;
 | |
| 
 | |
|                 // Remove any cookies
 | |
|                 var cookies = document.cookie.split(";");
 | |
|                 for (var i = 0; i < cookies.length; i++) {
 | |
|                     var cookieName = $.trim(cookies[i].split("=")[0]);
 | |
|                     if (['login-option', 'lang'].indexOf(cookieName) < 0) {
 | |
|                         $.cookie(cookieName, null);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 var url = 'samlSso';
 | |
|                 if (args.data.idpid) {
 | |
|                     url = url + '&idpid=' + args.data.idpid;
 | |
|                 }
 | |
|                 if (args.data.domain) {
 | |
|                     url = url + '&domain=' + args.data.domain;
 | |
|                 }
 | |
|                 window.location.href = createURL(url);
 | |
|             },
 | |
| 
 | |
|             // Show cloudStack main UI widget
 | |
|             complete: function(args) {
 | |
|                 var context = {
 | |
|                     users: [args.user]
 | |
|                 };
 | |
|                 var cloudStackArgs = $.extend(cloudStack, {
 | |
|                     context: context
 | |
|                 });
 | |
| 
 | |
|                 // Check to invoke install wizard
 | |
|                 cloudStack.installWizard.check({
 | |
|                     context: context,
 | |
|                     response: {
 | |
|                         success: function(args) {
 | |
|                             if (args.doInstall && isAdmin()) {
 | |
|                                 var initInstallWizard = function() {
 | |
|                                     cloudStack.uiCustom.installWizard({
 | |
|                                         $container: $container,
 | |
|                                         context: context,
 | |
|                                         complete: function() {
 | |
|                                             // Show cloudStack main UI
 | |
|                                             $container.cloudStack($.extend(cloudStackArgs, {
 | |
|                                                 hasLogo: false
 | |
|                                             }));
 | |
|                                         }
 | |
|                                     });
 | |
|                                 };
 | |
| 
 | |
|                                 initInstallWizard();
 | |
|                             } else {
 | |
|                                 // Show cloudStack main UI
 | |
|                                 $container.cloudStack($.extend(cloudStackArgs, {
 | |
|                                     hasLogo: false
 | |
|                                 }));
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 });
 | |
| 
 | |
|                 // Logout action
 | |
|                 $(document).on('click', '#user-options a', function() {
 | |
|                   loginArgs.logoutAction({
 | |
|                     context: cloudStack.context
 | |
|                   });
 | |
|                 });
 | |
| 
 | |
|                 window._reloadUI = function() {
 | |
|                     $('#container').html('');
 | |
|                     $('#container').cloudStack(window.cloudStack);
 | |
|                 };
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         if ($.urlParam('loginUrl') != 0) {
 | |
|             // SSO
 | |
|             loginArgs.hideLoginScreen = true;
 | |
|         }
 | |
| 
 | |
|         // Localization
 | |
|         if (!$.isFunction(cloudStack.localizationFn)) { // i.e., localize is overridden by a plugin/module
 | |
|             cloudStack.localizationFn = function(str) {
 | |
|                 var localized = dictionary[str];
 | |
| 
 | |
|                 return localized ? localized : str;
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         // Localize validation messages
 | |
|         cloudStack.localizeValidatorMessages();
 | |
| 
 | |
|         cloudStack.uiCustom.login(loginArgs);
 | |
| 
 | |
|         document.title = _l(cloudStackOptions.docTitle);
 | |
|     });
 | |
| })(cloudStack, jQuery);
 |