I've worked out a way to allow multiple groups (curated content) inside the Add Data widget. I'm sharing this hack as this has been requested by a few people: add Open Data to Add Data Widget and allow multiple Curated Categories
A couple things to note:
- There are probably better ways to do this: like make it dynamic instead of all the hard coded references
- This modifies the Add Data code once the widget has been deployed. As such, you cannot go and modify the app-widget using the builder.
- These changes were made against WAB 2.10
After creating your App with an Add Data widget, you'll need to update 4 files
- Configs\AddData\config_widget_AddData_Widget_xx.json
- Widgets\AddData\search\templates\ScopeOptions.html
- Widgets\AddData\widget.js
- Widgets\AddData\search\ScopeOptions.js
The first step is to turn the config of Curated items into a list. You can add as many into the list as you want. The rest of the workflow has been setup for 6 groups. If you want more than 6, that's fine, just make sure to match relevant nodes. Yes, the syntax is a little strange with the 'Curated' key:value pairing inside the list. This was done to reduce the number of JavaScript code changes.
"Curated":[{
"Curated":{
"allow": true,
"label": "Group 1",
"filter": "group:abcdef12346"
}
},
{
"Curated":{
"allow": true,
"label": "Group 10",
"filter": "group:zywyx987"
}
}],
You then need to update the HTML template. The important point here is the data-dojo-attach-point with the 0-indexed buttons. If you have more than 6 groups you'll need to continue adding them into this template file and updating the value. If you have less than 6 groups within the config, that's fine, the code will remove them from the widget UI.
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle0"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle1"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle2"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle3"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle4"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
<button type="button" class="btn btn-sm btn-default" name="${id}_scope"
data-dojo-attach-point="CuratedToggle5"
data-dojo-attach-event="onClick: optionClicked"
data-option-name="Curated">
${i18n.search.scopeOptions.curated}
</button>
The changes to widget.js are straight forward. Around line 123, you need to comment out the initOption check and add code to loop through instead. (Remember the config was turned into a list of groups)
options["Curated"].forEach(function(c){
initOption(c,"Curated");
});
Also within the _initTabs function, we need need to disable the chkAllowSearch('Curated') -- about line 350. We're simply skipping this because if you're going to the work of updating the config with more groups to search, why do you need to do an allow-check? If you don't comment this out, further work on fixing the chkAllowSearch will be required.
The ScopeOptions.js requires the most updates. (Changes are listed here, but it'd be easier to grab them from the zip file)
Update the initOptions function
initOptions: function() {
var context = this.searchPane.searchContext;
var hasUsername = (typeof context.username === "string" && context.username.length > 0);
var options = this.getConfig().scopeOptions;
this.curatedFilter = options.Curated.filter;
var activeNode = null;
var initOption = function(name, node) {
if (typeof name === 'string' || name instanceof String) {
var opt = options[name];
var cure = false;
} else {
var cure = true;
var opt = name['Curated'];
}
if (opt && opt.allow) {
if (typeof opt.label === "string" && lang.trim(opt.label).length > 0) {
util.setNodeText(node,lang.trim(opt.label));
} else {
if (!hasUsername && name === "MyOrganization") {
util.setNodeText(node,i18n.search.scopeOptions.anonymousContent);
}
}
if (options.defaultScope === name || cure) {
activeNode = node;
node.id = opt.filter;
}
} else {
node.style.display = "none";
}
};
initOption("MyContent", this.MyContentToggle);
initOption("MyOrganization", this.MyOrganizationToggle);
initOption("ArcGISOnline", this.ArcGISOnlineToggle);
var curArray = {
0: this.CuratedToggle0,
1: this.CuratedToggle1,
2: this.CuratedToggle2,
3: this.CuratedToggle3,
4: this.CuratedToggle4,
5: this.CuratedToggle5
}
options["Curated"].forEach(function(c, i){
initOption(c, curArray[i]);
});
for(var i= options["Curated"].length; i < Object.keys(curArray).length; i++ ){
curArray[i].style.display = "none";
}
if (!activeNode) {
if (options.MyOrganization.allow) {
activeNode = this.MyOrganizationToggle;
} else if (options.ArcGISOnline.allow) {
activeNode = this.ArcGISOnlineToggle;
} else if (options.Curated) {
activeNode = this.CuratedToggle;
} else if (options.MyContent.allow) {
activeNode = this.MyContentToggle;
}
}
if (activeNode) {
domClass.add(activeNode, "active");
this.scopePlaceholderText.innerHTML = activeNode.innerHTML;
}
},
Update the appendQueryParams function from the start to just before the if-scope per content grouping logic
appendQueryParams: function(params, task) {
var scope = null;
var filter = null;
array.some(this.btnGroup.children, function(node) {
if (domClass.contains(node, "active")) {
scope = node.getAttribute("data-option-name");
filter = node.id;
return true;
}
});
if (typeof scope === "undefined") {
scope = null;
}
var q = null;
var curatedFilter = null
if (scope === "Curated"){
curatedFilter = filter;
}else{
curatedFilter= this.curatedFilter;
}
var context = this.searchPane.searchContext;
var username = context.username;
var orgId = context.orgId;
var considerOrg = true;
if (context.portal && context.portal.isPortal) {
considerOrg = false;
}