/*
* Copyright 2016 Anyware Services
*
* Licensed 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.
*/
/**
* This tool displays the steps to perform to configured Ametys after a fresh installation.
* It is meant to be the first tool displayed to the administrator user, helping him/her in the configuration.
* It is opened at admin workspace startup when there are unperformed steps (if userpref 'display-admin-welcome-tool' is not explicitly false)
*/
Ext.define('Ametys.plugins.web.administration.AdminWelcomeTool', {
extend: 'Ametys.tool.Tool',
statics: {
/**
* Checks if the tool can be opened and if so, dot it.
*/
open: function()
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.core.ui.UIToolsFactoriesManager",
id: "uitool-admin-welcome",
methodName: "canOpenTool",
parameters: [],
callback: {
handler: this._openCb,
scope: this
},
waitMessage: false,
errorMessage: true
});
},
/**
* @private
* Opens the tool if necessary after retrieving from the server if the tool can be opened
* @param {Number} canBeOpened Server told it can be opened
*/
_openCb: function(canBeOpened)
{
if (Ametys.tool.ToolsManager.getTool("uitool-admin-welcome") == null // not already open
&& Ametys.userprefs.UserPrefsDAO.getValue("display-admin-welcome-tool") != "false" // user did not explictly say to not open this tool
&& canBeOpened) // server told it can be opened
{
Ametys.tool.ToolsManager.openTool("uitool-admin-welcome");
}
}
},
/**
* @private
* @property {Number} _currentStep The index of the current step
*/
/**
* @private
* @property {Object} _targetIds The target ids (per message type) which lead to a refresh of the tool. Fo instance, can be equals to {"modified": ["^profile$"], "deleted": ["^profile$", "^site$"]}
*/
_targetIds: {},
createPanel: function ()
{
this._panel = Ext.create('Ext.container.Container', {
cls: 'admin-tool-welcome',
scrollable: true,
items: [{
xtype: 'container',
itemId: 'steps',
items: [],
flex: 1
}, {
xtype: 'checkbox',
cls: 'checkbox-do-not-display',
boxLabel: '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_DO_NOT_DISPLAY}}',
checked: !(Ametys.userprefs.UserPrefsDAO.getValue("display-admin-welcome-tool") == 'true'),
handler: function(checkbox, checked)
{
Ametys.userprefs.UserPrefsDAO.saveValues( { "display-admin-welcome-tool": [(!checked).toString()] }, Ext.emptyFn, "/admin");
}
}]
});
return this._panel;
},
/**
* @private
* Function called after retrieving the steps from the server.
* @param {Object[]} steps The steps given by the server
*/
_getStepsCb: function(steps)
{
this._displaySteps(steps);
this._setTargetIds(steps);
this.showRefreshed();
},
/**
* @private
* Displays the steps of the tool
* @param {Object[]} steps The steps given by the server
*/
_displaySteps: function(steps)
{
var stepsContainer = this._panel.items.get("steps");
stepsContainer.removeAll();
stepsContainer.add({
xtype: 'component',
html: "{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_INTRO_MESSAGE}}",
cls: 'welcome-intro'
});
var count = steps.length;
Ext.Array.forEach(steps, function(step, index) {
var cls = 'welcome-step ' + ((this._currentStep == index) ? 'welcome-step-current' : (step.performed ? 'welcome-step-performed' : 'welcome-step-todo')),
stepNumber = index + 1,
title = '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_NUMBER_STEP_1}}' + stepNumber + '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_NUMBER_STEP_2}}' + count + ' : ' + step.title,
desc = this._insertImages(this._insertActions(step.description, step.actions), step.images),
html = '<h1 class="welcome-step-title">' + title + '</h1>' + '<p>' + desc + '</p>',
isLast = (index == count - 1),
attachListener = this._currentStep != -1 && isLast; // attach a listener for scrolling to the current only if it is the last component rendered
stepsContainer.add({
xtype: 'component',
itemId: 'step' + index,
html: html,
cls: cls,
listeners: attachListener ? {
'afterrender': Ext.bind(function(component, eOpts) {
this._scrollToCurrent();
}, this)
} : {}
});
}, this);
if (this._currentStep == -1)
{
// All steps were performed
stepsContainer.add({
xtype: "image",
itemId: 'image',
src: Ametys.getPluginDirectPrefix('core-ui') + '/app_logo.jpg',
alt: 'Ametys'
}, {
xtype: 'component',
html: "{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_COMPLETED}}",
listeners: {
'afterrender': Ext.bind(function(component, eOpts) {
this._scrollToCurrent();
}, this)
}
});
}
},
/**
* @private
* Scrolls the tool to the current step
*/
_scrollToCurrent: function()
{
this._panel.getScrollable().scrollTo({y: 0}, false);
var cmp;
if (this._currentStep != -1)
{
cmp = this._panel.items.get('steps').items.get('step' + this._currentStep);
}
else
{
cmp = this._panel.items.get('steps').items.get('image');
}
var posTopTool = this._panel.getY(),
posTopStep = cmp.getY(),
diff = posTopStep - posTopTool;
this._panel.getScrollable().scrollTo({y: diff - 1 /* plus one pixel to be prettier */}, false);
},
/**
* @private
* Inserts the actions of steps into the <a> elments of the HTML text as href javascript actions
* @param {String} initialText The HTML text
* @param {String[]} actions The JS actions
* @return {String} The HTML text with href attributes on <a> elements
*/
_insertActions: function(initialText, actions)
{
var result = '';
var cursor = 0;
var linkIndex = initialText.indexOf("<a>", 0);
var actionIndex = 0;
while (linkIndex != -1 || actionIndex > actions.length)
{
result += initialText.substring(cursor, linkIndex);
result += "<a href=\"javascript:void(0)\" onclick=\""+ actions[actionIndex] + "\">";
cursor = linkIndex + 3;
linkIndex = initialText.indexOf("<a>", linkIndex + 3);
actionIndex++;
}
result += initialText.substring(cursor);
return result;
},
/**
* @private
* Inserts the image paths of steps into the <img/> elments of the HTML text as src attributes
* @param {String} initialText The HTML text
* @param {String[]} images The image paths
* @return {String} The HTML text with src attributes on <img/> elements
*/
_insertImages: function(initialText, images)
{
var result = '';
var cursor = 0;
var tagIndex = initialText.indexOf("<img/>", 0);
var imageIndex = 0;
while (tagIndex != -1 || imageIndex > images.length)
{
result += initialText.substring(cursor, tagIndex);
result += "<img src=\""+ images[imageIndex] + "\"/>";
cursor = tagIndex + 6;
tagIndex = initialText.indexOf("<img/>", tagIndex + 6);
imageIndex++;
}
result += initialText.substring(cursor);
return result;
},
/**
* @private
* Sets the target ids.
* @param {Object[]} steps The steps given by the server
*/
_setTargetIds: function(steps)
{
Ametys.message.MessageBus.unAll(this);
this._targetIds = {};
Ext.Array.forEach(steps, function(step) {
Ext.Object.each(step.targetIds || {}, function(messageType, targetIds) {
var regExpTargetIds = targetIds.map(function(targetId) {return new RegExp(targetId, "g");});
this._targetIds[messageType] = Ext.Array.merge(this._targetIds[messageType] || [], regExpTargetIds);
}, this);
}, this);
Ext.Object.each(this._targetIds, function(messageType) {
Ametys.message.MessageBus.on(messageType, Ext.bind(this._messageListener, this), this);
}, this);
},
refresh: function()
{
this.showRefreshing();
this.serverCall("getCurrentStep", [], function(currentStep) {
this._currentStep = currentStep;
this.serverCall("getSteps", [], this._getStepsCb);
});
},
setParams: function(params)
{
this.callParent(arguments);
this.showOutOfDate();
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool. MB_TYPE_LISTENING;
},
/**
* @private
* Listener on message
* @param {Ametys.message.Message} message The message
*/
_messageListener: function(message)
{
var targetIds = this._targetIds[message.getType()] || [];
var targets = message.getTargets(function(target) {
return Ext.Array.filter(targetIds, function(regExp) {return regExp.exec(target.getId()) != null;})
.length > 0;
});
if (targets.length > 0)
{
this.showOutOfDate();
}
}
});
/*
* Calls the open static method at startup
*/
Ametys.message.MessageBus.on(Ametys.message.Message.SELECTION_CHANGED, function(message) {
Ametys.plugins.web.administration.AdminWelcomeTool.open();
Ametys.message.MessageBus.unAll(Ametys.plugins.web.administration.AdminWelcomeTool);
}, Ametys.plugins.web.administration.AdminWelcomeTool);