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:
After creating your App with an Add Data widget, you'll need to update 4 files
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)
//initOption(options,"Curated");
// Loop through the list of Curated items from the JSON
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.
//chkAllowSearch("Curated");
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 hasOrgId = (typeof context.orgId === "string" && context.orgId.length > 0);
var options = this.getConfig().scopeOptions;
//This will be incorrectly set, but we won't use this any more
// CuratedFilter is handled further on with the togglebutton ID
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;
// Curated is no longer a string, special handling
} 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") {
// "My Organization as a label doesn't make sense
util.setNodeText(node,i18n.search.scopeOptions.anonymousContent);
}
}
//Special handling of Curated
if (options.defaultScope === name || cure) {
activeNode = node;
//Using the id of the ToggleButton to hold the filter
node.id = opt.filter;
}
} else {
node.style.display = "none";
}
};
initOption("MyContent", this.MyContentToggle);
initOption("MyOrganization", this.MyOrganizationToggle);
initOption("ArcGISOnline", this.ArcGISOnlineToggle);
//initOption("Curated", this.CuratedToggle);
//As Curated is now a list, we need to loop through and match them to a ToggleButton
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]);
});
// Hide all the ToggleButtons that we don't need
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;
//Allow is an element on the Curated item (within the list)
//} else if (options.Curated.allow) {
} else if (options.Curated) {
// This is actually wrong, but never seems to be called
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");
//Always set the filter to the node.id
// Only the Curated have an appropraite filter set here, we'll
// straigthen this out below
filter = node.id;
return true;
}
});
if (typeof scope === "undefined") {
scope = null;
}
//console.warn("scope",scope);
var q = null;
var curatedFilter = null
// If Curated, we have a good filter
if (scope === "Curated"){
curatedFilter = filter;
// Otherwise fall back to the filter that was set in Init
}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;
}
Hello,
Does anybody has the complete widget set?