Skip to content

Instantly share code, notes, and snippets.

@zhenyanghua
Last active December 16, 2016 02:57
Show Gist options
  • Save zhenyanghua/b8fc4ebc74732db706b9 to your computer and use it in GitHub Desktop.
Save zhenyanghua/b8fc4ebc74732db706b9 to your computer and use it in GitHub Desktop.
ArcGIS Web Appbuilder Secrets

Up and run with Tutorial

Esri Tutorial covers most part of the content for you to get up and running a customized widget that can be used in the Web Appbuilder.

However, the current release of the Appbuilder (1.3) is still buggy and doesn't cover some on-demand customization. Here are some points that will come in handy when you need them.

How to debug a widget in development?

How to debug a configuration page in development?

How to ship and reference external resources inside of a widget?

  • CSS postCreate injection.
  • external JS referencing.

In the life cycle of postCreate, one can inject external css to the Appbuilder to bundle external resource to the widget so that the widget dependency is off the hands of users when they add the widget to their app.

Here is an an example of injecting external css to the Appbuilder only when the widget is instantiated.

postCreate: function() {
	this.inherited(arguments);
	console.log('postCreate');

  /* Inject Widget Stylesheet */
	var link = document.createElement('link');
	link.href = require.toUrl('widgets/CUSTOMIZED_WIDGET_FOLDER/PATH_TO_EXTERNAL_STYLE.css');
	link.rel = 'stylesheet';
	link.type = 'text/css';
	var head = document.getElementsByTagName('head')[0];
	var links = head.getElementsByTagName('link');
	// Check if the same style sheet has already been loaded by the app or the other widgets.
	var isLoaded = false;
	array.forEach(links, function(entry) {
		if (entry.href.indexOf(link.href) > -1 ){
			isLoaded = true;
		}
	});
	if (isLoaded) return;
	head.insertBefore(link, links[links.length - 1]);
}
{
"theme": {
"name": "FoldableTheme"
},
"portalUrl": "http://www.arcgis.com",
"appId":"",
"title": "ArcGIS Web Application - Dev Widgets",
"subtitle": "RelateTable",
"geometryService": "http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer",
"links":[
{
"label": "Woolpert"
}
],
"widgetOnScreen": {
"widgets": [{
"uri": "themes/FoldableTheme/widgets/HeaderController/Widget",
"positionRelativeTo": "browser",
"position": {
"left": 0,
"top": 0,
"right": 0,
"height": 45
}
}, {
"uri": "widgets/samplewidgets/WidgetCommunication/WidgetA/Widget",
"position": {
"left": 45,
"top": 45
}
}]
},
"map": {
"3D": false,
"2D": true,
"itemId": "WEBMAP_ITEM_ID",
"position": {
"left": 0,
"top": 45,
"right": 0,
"bottom": 0
}
},
"widgetPool": {
"panel": {
"uri": "themes/FoldableTheme/panels/FoldablePanel/Panel",
"positionRelativeTo": "map",
"position": {
"top": 1,
"right": 1,
"bottom": 1
}
},
"widgets": [{
"label": "RelateTable",
"uri": "widgets/RelateTable/Widget"
}]
}
}
///////////////////////////////////////////////////////////////////////////
// Copyright © 2014 Esri. All Rights Reserved.
//
// 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.
///////////////////////////////////////////////////////////////////////////
define(['dojo/_base/declare',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/_base/html',
'dojo/Deferred',
'dojo/topic',
'dojo/Evented',
'dojo/on',
'dojo/aspect',
'dojo/json',
'dojo/query',
'dojo/request/xhr',
'dojo/promise/all',
'./utils',
'jimu/tokenUtils',
'./dijit/Message'
],
function (declare, lang, array, html, Deferred, topic, Evented, on, aspect,
json, query, xhr, all, utils, tokenUtils, Message)
{
var instance = null,
clazz = declare(Evented, {
constructor: function ()
{
//-------------------------------------------------------------------------------
//CONSTUCT A UNIQUE PARMATER TO ADD TO FILES URLS.
//
var myHostName = "localhost"
var uid = Date.now()
if (window.location.hostname.toLowerCase() != myHostName)
{
var d = new Date();
uid = d.getTime();
}
this.preventCacheParameter = "?preventCache=" + uid;
//-------------------------------------------------------------------------------
//the loaded widget list
this.loaded = [];
//action is triggered, but the widget has not been loaded
//{id: widgetId, action: {}}
this.missedActions = [];
this.activeWidget = null;
if (window.isBuilder)
{
topic.subscribe("app/mapLoaded", lang.hitch(this, this._onMapLoaded));
topic.subscribe("app/mapChanged", lang.hitch(this, this._onMapChanged));
} else
{
topic.subscribe("mapLoaded", lang.hitch(this, this._onMapLoaded));
topic.subscribe("mapChanged", lang.hitch(this, this._onMapChanged));
}
if (window.isBuilder)
{
topic.subscribe("app/appConfigLoaded", lang.hitch(this, this._onAppConfigLoaded));
topic.subscribe("app/appConfigChanged", lang.hitch(this, this._onAppConfigChanged));
} else
{
topic.subscribe("appConfigLoaded", lang.hitch(this, this._onAppConfigLoaded));
topic.subscribe("appConfigChanged", lang.hitch(this, this._onAppConfigChanged));
}
topic.subscribe('userSignIn', lang.hitch(this, this._onUserSignIn));
topic.subscribe('userSignOut', lang.hitch(this, this._onUserSignOut));
//events from builder
topic.subscribe('builder/actionTriggered', lang.hitch(this, this._onActionTriggered));
//see panel manager
topic.subscribe('/dnd/move/start', lang.hitch(this, this._onMoveStart));
},
loadWidget: function (setting)
{
// summary:
// load and create widget, return deferred. when defer is resolved,
// widget is returned.
// description:
// setting should contain 2 properties:
// id: id should be unique, same id will return same widget object.
// uri: the widget's main class
var def = new Deferred(),
findWidget;
setting = lang.clone(setting);
if (!setting.folderUrl)
{
utils.processWidgetSetting(setting);
}
findWidget = this.getWidgetById(setting.id);
if (findWidget)
{
//widget have loaded(identified by id)
def.resolve(findWidget);
} else
{
all([this.loadWidgetClass(setting), this.loadWidgetManifest(setting)])
.then(lang.hitch(this, function (results)
{
var clazz = results[0];
var setting = results[1];
this.loadWidgetResources(setting).then(lang.hitch(this, function (resouces)
{
try
{
var widget = this.createWidget(setting, clazz, resouces);
console.log('widget [' + setting.uri + '] created.');
} catch (err)
{
console.log('create [' + setting.uri + '] error:' + err.stack);
new Message({
message: 'create widget error: ' + setting.uri
});
def.reject(err);
}
//use timeout to let the widget can get the correct dimension in startup function
setTimeout(lang.hitch(this, function ()
{
def.resolve(widget);
this.emit('widget-created', widget);
topic.publish('widgetCreated', widget);
}), 50);
}), function (err)
{
def.reject(err);
});
}), function (err)
{
def.reject(err);
});
}
return def;
},
loadWidgetClass: function (setting)
{
//-------------------------------------------------------------------------------
//APPEND THE PREVENT CACHE PARAM TO THE WIDGET.JS FILE
setting.uri = setting.uri + ".js" + this.preventCacheParameter;
//-------------------------------------------------------------------------------
// summary:
// load the widget's main class, and return deferred
var def = new Deferred();
require(utils.getRequireConfig(), [setting.uri], lang.hitch(this, function (clazz)
{
def.resolve(clazz);
}));
utils.checkError(setting.uri, def);
return def;
},
loadWidgetResources: function (setting)
{
// summary:
// load the widget's resources(local, style, etc.), and return deferred
var def = new Deferred(),
defConfig, defI18n, defStyle, defTemplate, defs = [];
var setting2 = lang.clone(setting);
defConfig = this.tryLoadWidgetConfig(setting2);
defI18n = this._tryLoadResource(setting2, 'i18n');
defStyle = this._tryLoadResource(setting2, 'style');
defTemplate = this._tryLoadResource(setting2, 'template');
defs.push(defConfig);
defs.push(defI18n);
defs.push(defTemplate);
defs.push(defStyle);
all(defs).then(lang.hitch(this, function (results)
{
var res = {};
res.config = results[0];
res.i18n = results[1];
res.template = results[2];
res.style = results[3];
def.resolve(res);
}), function (err)
{
def.reject(err);
});
return def;
},
loadWidgetManifest: function (widgetJson)
{
var def = new Deferred();
//-------------------------------------------------------------------------------
//APPEND THE PREVENT CACHE PARAMATER TO THE URL
var url = widgetJson.folderUrl + 'manifest.json' + this.preventCacheParameter;
//-------------------------------------------------------------------------------
//json.manifest is added in configmanager if manifest is merged.
if (widgetJson.manifest)
{
def.resolve(widgetJson);
return def;
}
xhr(url, {
handleAs: 'json'
}).then(lang.hitch(this, function (manifest)
{
manifest.amdFolder = widgetJson.amdFolder;
manifest.category = 'widget';
if (!widgetJson.label)
{
utils.addI18NLabel(manifest).then(lang.hitch(this, function ()
{
this._processManifest(manifest);
utils.addManifest2WidgetJson(widgetJson, manifest);
def.resolve(widgetJson);
}));
} else
{
this._processManifest(manifest);
utils.addManifest2WidgetJson(widgetJson, manifest);
def.resolve(widgetJson);
}
}), function (err)
{
def.reject(err);
});
return def;
},
getWidgetMarginBox: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return {};
}
}
if (widget._marginBox)
{
return widget._marginBox;
}
var position = {
left: -9999,
top: -9999,
relativeTo: widget.position.relativeTo
};
widget.setPosition(position);
this.openWidget(widget);
widget._marginBox = widget.getMarginBox();
this.closeWidget(widget);
return widget._marginBox;
},
_processManifest: function (manifest)
{
utils.addManifestProperies(manifest);
utils.processManifestLabel(manifest, window.dojoConfig.locale);
},
createWidget: function (setting, clazz, resouces)
{
var widget;
//here, check whether widget have loaded again because loading and create a widget
//needs some time. If in this period time, more then one loading request will create
//more widgets with the same id, it's a error.
if (this.getWidgetById(setting.id))
{
return this.getWidgetById(setting.id);
}
//the config can contain i18n placeholders
if (resouces.config && resouces.i18n)
{
resouces.config = utils.replacePlaceHolder(resouces.config, resouces.i18n);
}
setting.rawConfig = setting.config;
setting.config = resouces.config || {};
if (this.appConfig._appData)
{
this._mergeAgolConfig(setting);
}
setting.nls = resouces.i18n || {};
if (resouces.template)
{
setting.templateString = resouces.template;
}
setting['class'] = 'jimu-widget';
if (!setting.label)
{
setting.label = setting.name;
}
if (this.map)
{
setting.map = this.map;
}
setting.appConfig = this.appConfig;
// for IE8
var setting2 = {};
for (var prop in setting)
{
if (setting.hasOwnProperty(prop))
{
setting2[prop] = setting[prop];
}
}
setting2.widgetManager = this;
widget = new clazz(setting2);
widget.clazz = clazz;
aspect.after(widget, 'startup', lang.hitch(this, this._postWidgetStartup, widget));
aspect.before(widget, 'destroy', lang.hitch(this, this._onDestroyWidget, widget));
on(widget.domNode, 'click', lang.hitch(this, this._onClickWidget, widget));
this.loaded.push(widget);
return widget;
},
getAllWidgets: function ()
{
return this.loaded;
},
destroyAllWidgets: function ()
{
var allWidgetIds = array.map(this.loaded, function (widget)
{
return widget.id;
});
array.forEach(allWidgetIds, function (widgetId)
{
this.destroyWidget(widgetId);
}, this);
this.loaded = [];
},
//load the widget setting page class and create setting page object
//do not cache for now.
loadWidgetSettingPage: function (setting)
{
var def = new Deferred();
setting = lang.clone(setting);
setting.id = setting.id + '_setting';
all([this.loadWidgetSettingClass(setting)]).
then(lang.hitch(this, function (results)
{
var clazz = results[0];
this.loadWidgetSettingPageResources(setting).then(lang.hitch(this, function (resources)
{
var settingObject; // style = results[2]
// for IE8
var setting2 = {
nls: resources.i18n,
templateString: resources.template,
appConfig: this.appConfig,
map: this.map,
'class': 'jimu-widget-setting'
};
for (var prop in setting)
{
if (setting.hasOwnProperty(prop))
{
setting2[prop] = setting[prop];
}
}
try
{
settingObject = new clazz(setting2);
aspect.before(settingObject, 'destroy',
lang.hitch(this, this._onDestroyWidgetSetting, settingObject));
def.resolve(settingObject);
} catch (err)
{
new Message({
message: 'Create widget setting page error:' + setting.uri
});
def.reject(err);
}
}), function (err)
{
console.log(err);
});
}), function (err)
{
def.reject(err);
});
return def;
},
loadWidgetSettingClass: function (setting)
{
// summary:
// load the widget's main class, and return deferred
var def = new Deferred();
require(utils.getRequireConfig(), [setting.folderUrl + 'setting/Setting.js' + this.preventCacheParameter],
lang.hitch(this, function (clazz)
{
def.resolve(clazz);
}));
utils.checkError(setting.folderUrl + 'setting/Setting.js' + this.preventCacheParameter, def);
return def;
},
loadWidgetSettingPageResources: function (setting)
{
var def = new Deferred();
var defI18n, defStyle, defTemplate, defs = [];
setting = lang.clone(setting);
defI18n = this._tryLoadResource(setting, 'settingI18n');
defTemplate = this._tryLoadResource(setting, 'settingTemplate');
defStyle = this._tryLoadResource(setting, 'settingStyle');
defs.push(defI18n);
defs.push(defTemplate);
defs.push(defStyle);
all(defs).then(lang.hitch(this, function (results)
{
var res = {};
res.i18n = results[0] || {};
res.template = results[1];
res.style = results[2];
def.resolve(res);
}), function (err)
{
console.log(err);
});
return def;
},
getWidgetById: function (id)
{
var ret;
array.some(this.loaded, function (w)
{
if (w.id === id)
{
ret = w;
return true;
}
}, this);
return ret;
},
getWidgetByLabel: function (label)
{
var ret;
array.some(this.loaded, function (w)
{
if (w.label === label)
{
ret = w;
return true;
}
}, this);
return ret;
},
getWidgetsByName: function (name)
{
var ret = [];
array.some(this.loaded, function (w)
{
if (w.name === name)
{
ret.push(w);
}
}, this);
return ret;
},
//normal, minimized, maximized
changeWindowStateTo: function (widget, state)
{
if (state === 'normal')
{
this.normalizeWidget(widget);
} else if (state === 'minimized')
{
this.minimizeWidget(widget);
} else if (state === 'maximized')
{
this.maximizeWidget(widget);
} else
{
console.log('error state: ' + state);
}
},
closeWidget: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
if (widget.state !== 'closed')
{
if (this.activeWidget && this.activeWidget.id === widget.id)
{
this.activeWidget.onDeActive();
this.activeWidget = null;
}
html.setStyle(widget.domNode, 'display', 'none');
widget.setState('closed');
try
{
widget.onClose();
} catch (err)
{
console.log(console.error('fail to close widget ' + widget.name + '. ' + err.stack));
}
}
},
openWidget: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
if (!widget.started)
{
try
{
widget.started = true;
widget.startup();
} catch (err)
{
console.error('fail to startup widget ' + widget.name + '. ' + err.stack);
}
}
if (widget.state === 'closed')
{
html.setStyle(widget.domNode, 'display', '');
widget.setState('opened');
try
{
widget.onOpen();
} catch (err)
{
console.error('fail to open widget ' + widget.name + '. ' + err.stack);
}
}
},
maximizeWidget: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
if (widget.state === 'closed')
{
this.openWidget(widget);
}
widget.setWindowState('maximized');
try
{
widget.onMaximize();
} catch (err)
{
console.log(console.error('fail to maximize widget ' + widget.name + '. ' + err.stack));
}
},
minimizeWidget: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
if (widget.state === 'closed')
{
this.openWidget(widget);
}
widget.setWindowState('minimized');
try
{
widget.onMinimize();
} catch (err)
{
console.log(console.error('fail to minimize widget ' + widget.name + '. ' + err.stack));
}
},
normalizeWidget: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
if (widget.state === 'closed')
{
this.openWidget(widget);
}
widget.setWindowState('normal');
try
{
widget.onNormalize();
} catch (err)
{
console.log(console.error('fail to normalize widget ' + widget.name + '. ' +
err.stack));
}
},
destroyWidget: function (widget)
{
var m;
if (typeof widget === 'string')
{
m = this.getWidgetById(widget);
if (!m)
{
//maybe, the widget is loading
return;
} else
{
widget = m;
}
}
this._removeWidget(widget);
try
{
widget.destroy();
} catch (err)
{
console.log(console.error('fail to destroy widget ' + widget.name + '. ' + err.stack));
}
},
tryLoadWidgetConfig: function (setting)
{
return this._tryLoadWidgetConfig(setting).then(lang.hitch(this, function (config)
{
return this._upgradeWidgetConfig(setting, config).then(function (widgetConfig)
{
setting.config = widgetConfig;
return widgetConfig;
});
}));
},
_tryLoadWidgetConfig: function (setting)
{
var def = new Deferred();
//need load config first, because the template may be use the config data
if (setting.config && lang.isObject(setting.config))
{
//if widget is configurated in the app config.json, the i18n has beed processed
def.resolve(setting.config);
return def;
} else if (setting.config)
{
if (require.cache['url:' + setting.config])
{
def.resolve(json.parse(require.cache['url:' + setting.config]));
return def;
}
var configFile = utils.processUrlInAppConfig(setting.config);
// The widgetConfig filename is dependent on widget label,
// IE8 & IE9 do not encode automatically while attempt to request file.
var configFileArray = configFile.split('/');
configFileArray[configFileArray.length - 1] =
encodeURIComponent(configFileArray[configFileArray.length - 1]);
configFile = configFileArray.join('/');
return xhr(configFile, {
handleAs: "json"
});
} else
{
return this._tryLoadResource(setting, 'config');
}
},
_upgradeWidgetConfig: function (json, oldConfig)
{
var def = new Deferred();
var widgetVersion = json.manifest.version;
var configVersion = json.version;
var newConfig;
if (widgetVersion === configVersion)
{
def.resolve(oldConfig);
return def;
}
if (json.hasVersionManager === false)
{
//widget config loaded from builder needs update version
json.version = widgetVersion;
//if widget doesn't have version manager, we assume the widget
//is old version compatible
def.resolve(oldConfig);
return def;
}
require(utils.getRequireConfig(), [json.amdFolder + 'VersionManager'],
lang.hitch(this, function (VersionManager)
{
var versionManager = new VersionManager();
var configVersionIndex = versionManager.getVersionIndex(configVersion);
var widgetVersionIndex = versionManager.getVersionIndex(widgetVersion);
if (configVersionIndex > widgetVersionIndex)
{
def.reject('Bad widget version number, ' + json.name + ',' + configVersion);
} else
{
try
{
newConfig = versionManager.upgrade(oldConfig, configVersion, widgetVersion);
json.version = widgetVersion;
def.resolve(newConfig);
} catch (err)
{
console.log('Read widget [' + json.name + '] old config error,' + err.stack);
def.resolve(oldConfig);
}
}
}));
return def;
},
/*
* Load the css file in a widget.
* This function load the widget's css file and insert it into the HTML page through <link>.
* It also ensure that the css file is inserted only one time.
*/
loadWidgetStyle: function (widgetSetting)
{
var id = 'widget/style/' + widgetSetting.uri,
def = new Deferred();
id = this._replaceId(id);
if (html.byId(id))
{
def.resolve('load');
return def;
}
var themeCommonStyleId = 'theme_' + this.appConfig.theme.name + '_style_common';
//insert widget style before theme style, to let theme style over widget style
return utils.loadStyleLink(id, widgetSetting.styleFile, themeCommonStyleId);
},
loadWidgetSettingStyle: function (widgetSetting)
{
var id = 'widget/style/' + widgetSetting.uri + '/setting',
def = new Deferred();
id = this._replaceId(id);
if (html.byId(id))
{
def.resolve('load');
return def;
}
return utils.loadStyleLink(id, widgetSetting.settingStyleFile);
},
loadWidgetConfig: function (widgetSetting)
{
var configFilePath = require(utils.getRequireConfig()).toUrl(widgetSetting.configFile);
if (require.cache['url:' + configFilePath])
{
var def = new Deferred();
def.resolve(json.parse(require.cache['url:' + configFilePath]));
return def;
}
return xhr(configFilePath, {
handleAs: "json"
});
},
loadWidgetI18n: function (widgetSetting)
{
var def = new Deferred();
require(utils.getRequireConfig(), ['dojo/i18n!' + widgetSetting.i18nFile],
function (bundle)
{
def.resolve(bundle);
});
return def;
},
loadWidgetSettingI18n: function (widgetSetting)
{
var def = new Deferred();
require(utils.getRequireConfig(), ['dojo/i18n!' + widgetSetting.settingI18nFile],
function (bundle)
{
def.resolve(bundle);
});
return def;
},
loadWidgetTemplate: function (widgetSetting)
{
var def = new Deferred();
require(utils.getRequireConfig(), ['dojo/text!' + widgetSetting.templateFile],
function (template)
{
def.resolve(template);
});
utils.checkError(widgetSetting.templateFile, def);
return def;
},
loadWidgetSettingTemplate: function (widgetSetting)
{
var def = new Deferred();
require(utils.getRequireConfig(), ['dojo/text!' + widgetSetting.settingTemplateFile],
function (template)
{
def.resolve(template);
});
utils.checkError(widgetSetting.settingTemplateFile, def);
return def;
},
removeWidgetStyle: function (widget)
{
html.destroy(this._replaceId('widget/style/' + widget.uri));
},
removeWidgetSettingStyle: function (widget)
{
html.destroy(this._replaceId('widget/style/' + widget.uri + '/setting'));
},
getControllerWidgets: function ()
{
return array.filter(this.loaded, function (widget)
{
return widget.isController;
});
},
getOffPanelWidgets: function ()
{
return array.filter(this.loaded, function (widget)
{
return !widget.inPanel;
});
},
getOnScreenOffPanelWidgets: function ()
{
return array.filter(this.loaded, function (widget)
{
return widget.isOnScreen && !widget.inPanel;
});
},
closeOtherWidgetsInTheSameGroup: function (widget)
{
if (typeof widget === 'string')
{
widget = this.getWidgetById(widget);
if (!widget)
{
return;
}
}
for (var i = 0; i < this.loaded.length; i++)
{
if (this.loaded[i].gid === widget.gid && this.loaded[i].id !== widget.id)
{
this.closeWidget(this.loaded[i]);
}
}
},
closeAllWidgetsInGroup: function (groupId)
{
for (var i = 0; i < this.loaded.length; i++)
{
if (this.loaded[i].gid === groupId)
{
this.closeWidget(this.loaded[i]);
}
}
},
// Merge AGOL configs when first open widget (because the
// widgetConfig just loaded if the widget has not been edited yet).
// This method only merge fields in widget config,
// the other fields were merged in ConfigManager.js
_mergeAgolConfig: function (setting)
{
var values = this.appConfig._appData.values;
function doMerge(sectionKey)
{
for (var key in values)
{
var sectionKeyIndex = key.replace(/\//g, '_').indexOf(sectionKey + '_config');
if (sectionKeyIndex >= 0)
{
utils.template.setConfigValue(setting,
key.replace(/\//g, '_').substr(sectionKeyIndex, key.length).replace(sectionKey, 'widget'),
values[key]);
}
}
}
var sectionKey;
sectionKey = 'widgets[' + setting.id + ']';
doMerge(sectionKey);
},
_onUserSignIn: function (credential)
{
array.forEach(this.loaded, function (m)
{
m.onSignIn(credential);
}, this);
},
_onUserSignOut: function ()
{
array.forEach(this.loaded, function (m)
{
m.onSignOut();
}, this);
},
_activeWidget: function (widget)
{
if (this.activeWidget)
{
if (this.activeWidget.id === widget.id)
{
//zIndex may be reset by widget self
if (this.activeWidget.moveTopOnActive)
{
html.setStyle(this.activeWidget.domNode, 'zIndex', 101);
}
return;
}
if (this.activeWidget.state === 'active')
{
this.activeWidget.setState('opened');
html.setStyle(widget.domNode, 'zIndex',
'zIndex' in widget.position ? widget.position.zIndex : 'auto');
this.activeWidget.onDeActive();
}
}
this.activeWidget = widget;
if (this.activeWidget.state !== 'opened')
{
return;
}
this.activeWidget.setState('active');
if (this.activeWidget.moveTopOnActive)
{
html.setStyle(this.activeWidget.domNode, 'zIndex', 101);
}
this.activeWidget.onActive();
topic.publish('widgetActived', widget);
},
_onClickWidget: function (widget, evt)
{
var childWidgets = query('.jimu-widget', widget.domNode);
if (childWidgets.length > 0)
{
for (var i = 0; i < childWidgets.length; i++)
{
if (evt.target === childWidgets[i] || html.isDescendant(evt.target, childWidgets[i]))
{
//click on the child widget or child widget's children dom
return;
}
}
}
this._activeWidget(widget);
},
_onMoveStart: function (mover)
{
array.forEach(this.loaded, function (widget)
{
if (widget.domNode === mover.node)
{
this._activeWidget(widget);
}
}, this);
},
_onAppConfigLoaded: function (_appConfig)
{
var appConfig = lang.clone(_appConfig);
this.appConfig = appConfig;
tokenUtils.setPortalUrl(appConfig.portalUrl);
},
_onMapLoaded: function (map)
{
this.map = map;
},
_onMapChanged: function (map)
{
this.map = map;
},
_onAppConfigChanged: function (_appConfig, reason, changedData, otherOptions)
{
var appConfig = lang.clone(_appConfig);
this.appConfig = appConfig;
array.forEach(this.loaded, function (w)
{
if (!w)
{
//widget maybe deleted in the handler of appConfigChange event
return;
}
w.onAppConfigChanged(appConfig, reason, changedData, otherOptions);
if (reason === 'widgetChange')
{
this._onConfigChanged(changedData.id, changedData.config, otherOptions);
}
}, this);
},
_onConfigChanged: function (id, config)
{
//summary:
// widget which care it's own config change should override onConfigChanged function
var w = this.getWidgetById(id);
if (!w)
{
return;
}
w.onConfigChanged(config);
lang.mixin(w.config, config);
},
_onActionTriggered: function (info)
{
if (info.elementId === 'map' || info.elementId === 'app')
{
return;
}
var m = this.getWidgetById(info.elementId);
if (!m)
{
this.missedActions.push({
id: info.elementId,
action: {
name: info.action,
data: info.data
}
});
} else
{
m.onAction(info.action, info.data);
}
//may be the controller widget also need process the action
array.forEach(this.getControllerWidgets(), function (ctrlWidget)
{
if (ctrlWidget.widgetIsControlled(info.elementId))
{
ctrlWidget.onAction(info.action, {
widgetId: info.elementId,
data: info.data
});
}
}, this);
},
_postWidgetStartup: function (widgetObject)
{
widgetObject.started = true;//for backward compatibility
utils.setVerticalCenter(widgetObject.domNode);
aspect.after(widgetObject, 'resize', lang.hitch(this,
utils.setVerticalCenter, widgetObject.domNode));
this.openWidget(widgetObject);
// if(widgetObject.defaultState){
// this.changeWindowStateTo(widgetObject, widgetObject.defaultState);
// }
var portalUrl = this.appConfig.portalUrl;
var credential = tokenUtils.getPortalCredential(portalUrl);
if (credential)
{
widgetObject.onSignIn(credential);
} else
{
widgetObject.onSignOut();
}
this._triggerMissedAction(widgetObject);
},
_triggerMissedAction: function (widget)
{
this.missedActions.forEach(function (info)
{
if (info.id === widget.id)
{
widget.onAction(info.action.name, info.action.data);
}
});
},
_remove: function (id)
{
return array.some(this.loaded, function (w, i)
{
if (w.id === id)
{
this.loaded.splice(i, 1);
return true;
}
}, this);
},
_tryLoadResource: function (setting, flag)
{
//-------------------------------------------------------------------------------
//PREVENT CACHE ON RESOURCES
setting.configFile = setting.configFile + this.preventCacheParameter;
setting.icon = setting.icon + this.preventCacheParameter;
setting.styleFile = setting.styleFile + this.preventCacheParameter;
setting.templateFile = setting.templateFile + this.preventCacheParameter;
setting.thumbnail = setting.thumbnail + this.preventCacheParameter;
//-------------------------------------------------------------------------------
var file, hasp,
def = new Deferred(),
doLoad = function ()
{
var loadDef;
if (flag === 'config')
{
loadDef = this.loadWidgetConfig(setting);
} else if (flag === 'style')
{
loadDef = this.loadWidgetStyle(setting);
} else if (flag === 'i18n')
{
loadDef = this.loadWidgetI18n(setting);
} else if (flag === 'template')
{
loadDef = this.loadWidgetTemplate(setting);
} else if (flag === 'settingTemplate')
{
loadDef = this.loadWidgetSettingTemplate(setting);
} else if (flag === 'settingStyle')
{
loadDef = this.loadWidgetSettingStyle(setting);
} else if (flag === 'settingI18n')
{
loadDef = this.loadWidgetSettingI18n(setting);
} else
{
return def;
}
loadDef.then(function (data)
{
def.resolve(data);
}, function (err)
{
new Message({
message: 'load widget resouce error: ' + setting.uri
});
def.reject(err);
});
};
if (flag === 'config')
{
file = setting.amdFolder + 'config.json' + this.preventCacheParameter;
setting.configFile = file;
hasp = 'hasConfig';
} else if (flag === 'style')
{
file = setting.amdFolder + 'css/style.css' + this.preventCacheParameter;
setting.styleFile = file;
hasp = 'hasStyle';
} else if (flag === 'i18n')
{
file = setting.amdFolder + 'nls/strings.js' + this.preventCacheParameter;
setting.i18nFile = setting.amdFolder + 'nls/strings';
hasp = 'hasLocale';
} else if (flag === 'template')
{
file = setting.amdFolder + 'Widget.html' + this.preventCacheParameter;
setting.templateFile = file;
hasp = 'hasUIFile';
} else if (flag === 'settingTemplate')
{
file = setting.amdFolder + 'setting/Setting.html' + this.preventCacheParameter;
setting.settingTemplateFile = file;
hasp = 'hasSettingUIFile';
} else if (flag === 'settingI18n')
{
file = setting.amdFolder + 'setting/nls/strings.js' + this.preventCacheParameter;
setting.settingI18nFile = setting.amdFolder + 'setting/nls/strings';
hasp = 'hasSettingLocale';
} else if (flag === 'settingStyle')
{
file = setting.amdFolder + 'setting/css/style.css' + this.preventCacheParameter;
setting.settingStyleFile = file;
hasp = 'hasSettingStyle';
} else
{
return def;
}
if (setting[hasp])
{
doLoad.apply(this);
} else
{
def.resolve(null);
}
return def;
},
_replaceId: function (id)
{
return id.replace(/\//g, '_').replace(/\./g, '_');
},
_onDestroyWidget: function (widget)
{
if (widget.state !== 'closed')
{
this.closeWidget(widget);
}
this._removeWidget(widget);
console.log('destroy widget [' + widget.uri + '].');
},
_onDestroyWidgetSetting: function (settingWidget)
{
this.removeWidgetSettingStyle(settingWidget);
},
_removeWidget: function (widget)
{
var m;
if (typeof widget === 'string')
{
m = this.getWidgetById(widget);
if (!m)
{
//maybe, the widget is loading
return;
} else
{
widget = m;
}
}
if (this.activeWidget && this.activeWidget.id === widget.id)
{
this.activeWidget = null;
}
this._remove(widget.id);
if (this.getWidgetsByName(widget.name).length === 0)
{
this.removeWidgetStyle(widget);
}
}
});
clazz.getInstance = function (urlParams)
{
if (instance === null)
{
instance = new clazz(urlParams);
}
return instance;
};
return clazz;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment