diff --git a/viewer/js/config/viewer.js b/viewer/js/config/viewer.js index 610ac4ca2..e4131e10d 100644 --- a/viewer/js/config/viewer.js +++ b/viewer/js/config/viewer.js @@ -159,6 +159,9 @@ define([ ], */ + // ignore the visibility of group layers in dynamic layers? default = true + //ignoreDynamicGroupVisibility: false, + // operationalLayers: Array of Layers to load on top of the basemap: valid 'type' options: 'dynamic', 'tiled', 'feature'. // The 'options' object is passed as the layers options for constructor. Title will be used in the legend only. id's must be unique and have no spaces. // 3 'mode' options: MODE_SNAPSHOT = 0, MODE_ONDEMAND = 1, MODE_SELECTION = 2 @@ -223,7 +226,9 @@ define([ opacity: 1.0, visible: true, imageParameters: buildImageParameters({ - layerIds: [0, 2, 4, 5, 8, 10, 12, 21], + // include only sub layer ids. + // group layers omitted + layerIds: [2, 4, 5, 8, 12, 21], layerOption: 'show' }) }, @@ -231,6 +236,7 @@ define([ layerIds: [2, 4, 5, 8, 12, 21] }, layerControlLayerInfos: { + // group layers included to maintain folder hierarchy, not visibility. layerIds: [0, 2, 4, 5, 8, 9, 10, 12, 21] }, legendLayerInfos: { diff --git a/viewer/js/gis/dijit/Identify.js b/viewer/js/gis/dijit/Identify.js index 7b4104823..57d41f1a7 100644 --- a/viewer/js/gis/dijit/Identify.js +++ b/viewer/js/gis/dijit/Identify.js @@ -380,17 +380,18 @@ define([ layerIds = [ref.layerId]; } } else if (ref.layerInfos) { - layerIds = this.getLayerInfos(ref, selectedIds); + layerIds = this.getLayerInfos(layer, selectedIds); } } } return layerIds; }, - getLayerInfos: function (ref, selectedIds) { - var layerIds = []; + getLayerInfos: function (layer, selectedIds) { + var layerIds = [], + ref = layer.ref; array.forEach(ref.layerInfos, lang.hitch(this, function (layerInfo) { - if (!this.includeSubLayer(layerInfo, ref, selectedIds)) { + if (!this.includeSubLayer(layerInfo, layer, selectedIds)) { return; } layerIds.push(layerInfo.id); @@ -629,7 +630,7 @@ define([ } } else { // dynamic layer array.forEach(ref.layerInfos, lang.hitch(this, function (layerInfo) { - if (!this.includeSubLayer(layerInfo, ref, selectedIds)) { + if (!this.includeSubLayer(layerInfo, layer, selectedIds)) { return; } identifyItems.push({ @@ -666,13 +667,14 @@ define([ this.identifyLayerDijit.set('value', id); }, - includeSubLayer: function (layerInfo, ref, selectedIds) { + includeSubLayer: function (layerInfo, layer, selectedIds) { // exclude group layers if (layerInfo.subLayerIds !== null) { return false; } - if (this.isDefaultLayerVisibility(ref) && !this.checkVisibilityRecursive(ref, layerInfo.id)) { + var ref = layer.ref; + if (this.isDefaultLayerVisibility(ref) && !this.checkVisibilityRecursive(layer, layerInfo.id)) { return false; } else if (array.indexOf(ref.visibleLayers, layerInfo.id) < 0) { return false; @@ -707,18 +709,18 @@ define([ * this only needs to be done if the layers visibleLayers array is * set to the default visibleLayers. After setVisibleLayers * is called the first time group layers are NOT included. - * @param {esri/layers/DynamicMapServiceLayer} layer The layer reference + * @param {object} layer layerInfo reference * @param {Integer} id The sublayer id to check for visibility * @return {Boolean} Whether or not the sublayer is visible based on its parent(s) visibility */ checkVisibilityRecursive: function (layer, id) { - var layerInfos = array.filter(layer.layerInfos, function (layerInfo) { + var ref = layer.ref; + var layerInfos = array.filter(ref.layerInfos, function (layerInfo) { return (layerInfo.id === id); }); if (layerInfos.length > 0) { var info = layerInfos[0]; - if (layer.visibleLayers.indexOf(id) !== -1 && - (info.parentLayerId === -1 || this.checkVisibilityRecursive(layer, info.parentLayerId))) { + if ((ref.visibleLayers.indexOf(id) !== -1) && (layer.layerInfo.ignoreDynamicGroupVisibility || info.parentLayerId === -1 || this.checkVisibilityRecursive(layer, info.parentLayerId))) { return true; } } diff --git a/viewer/js/gis/dijit/LayerControl.js b/viewer/js/gis/dijit/LayerControl.js index bce4c9fbf..583f04996 100644 --- a/viewer/js/gis/dijit/LayerControl.js +++ b/viewer/js/gis/dijit/LayerControl.js @@ -40,8 +40,8 @@ define([ indeterminate: 'fa-minus fa-fw fa-border layerControlIcon-Indeterminate', update: 'fa-refresh layerControlIcon-Update', menu: 'fa-bars layerControlIcon-Menu', - folder: 'fa-folder-o fa-fw layerControlIcon-Folder', - folderOpen: 'fa-folder-open-o fa-fw layerControlIcon-Folder layerControlIcon-FolderOpen' + folder: 'fa-folder fa-fw layerControlIcon-Folder', + folderOpen: 'fa-folder-open fa-fw layerControlIcon-Folder layerControlIcon-FolderOpen' }, separated: false, overlayReorder: false, @@ -203,6 +203,10 @@ define([ } } + // re-initialize the groupedLayerInfos once + // the grouped layers have been added. + this._groupedLayerInfos = {}; + this._checkReorder(); })); }, @@ -259,7 +263,7 @@ define([ noTransparency: null, swipe: null, expanded: false, - sublayers: true, + sublayers: true, // used by dynamic layers only layerGroup: null, menu: this.menu[layerInfo.type], subLayerMenu: this.subLayerMenu[layerInfo.type] diff --git a/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js b/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js index c4ce2a847..6793f320e 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js @@ -43,11 +43,13 @@ define([ var DynamicControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'dynamic', // constant - //_sublayerControls: [], // sublayer/folder controls + _sublayerControls: [], // sublayer controls + _folderControls: [], // folder controls _hasSublayers: false, // true when sublayers created _visLayersHandler: null, constructor: function () { this._sublayerControls = []; + this._folderControls = []; }, _layerTypePreInit: function () { if (this.layer.layerInfos.length > 1 && this.controlOptions.sublayers) { @@ -61,15 +63,15 @@ define([ var isLegend = legendUtil.isLegend(this.controlOptions.noLegend, this.controller.noLegend); if (isLegend && this.controlOptions.sublayers === true) { this._expandClick(); - this._createSublayers(this.layer); - aspect.after(this, '_createSublayers', lang.hitch(this, legendUtil.dynamicSublayerLegend(this.layer, this.expandNode))); + this._createControls(this.layer); + aspect.after(this, '_createControls', lang.hitch(this, legendUtil.dynamicSublayerLegend(this.layer, this.expandNode))); } else if (this.controlOptions.sublayers === false && isLegend) { this._expandClick(); legendUtil.layerLegend(this.layer, this.expandNode); } else if (this.controlOptions.sublayers === true && !isLegend) { this._expandClick(); - aspect.after(this, '_createSublayers', lang.hitch(this, '_removeSublayerLegends')); - this._createSublayers(this.layer); + aspect.after(this, '_createControls', lang.hitch(this, '_removeSublayerLegends')); + this._createControls(this.layer); } else { this._expandRemove(); } @@ -103,67 +105,98 @@ define([ this._setVisibleLayers(); }, // add folder/sublayer controls per layer.layerInfos - _createSublayers: function (layer) { + _createControls: function (layer) { // check for single sublayer - if so no sublayer/folder controls if (layer.layerInfos.length > 1) { var allLayers = array.map(layer.layerInfos, function (l) { return l.id; }); - array.forEach(layer.layerInfos, lang.hitch(this, function (info) { - // see if there was any override needed from the subLayerInfos array in the controlOptions - var sublayerInfo = array.filter(this.controlOptions.subLayerInfos, function (sli) { - return sli.id === info.id; - }).shift(); - lang.mixin(info, sublayerInfo); - var pid = info.parentLayerId, - slids = info.subLayerIds, - controlId = layer.id + '-' + info.id + '-sublayer-control', - control; - // it's a top level - if (pid === -1 || allLayers.indexOf(pid) === -1) { - if (slids === null) { - // it's a top level sublayer - control = new DynamicSublayer({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, this.expandNode, 'last'); - } else if (slids !== null) { - // it's a top level folder - control = new DynamicFolder({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, this.expandNode, 'last'); - } - } else if (pid !== -1 && slids !== null) { - // it's a nested folder - control = new DynamicFolder({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, registry.byId(layer.id + '-' + info.parentLayerId + '-sublayer-control').expandNode, 'last'); - } else if (pid !== -1 && slids === null) { - // it's a nested sublayer - control = new DynamicSublayer({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, registry.byId(layer.id + '-' + info.parentLayerId + '-sublayer-control').expandNode, 'last'); - } - control.startup(); - this._sublayerControls.push(control); - })); + array.forEach(layer.layerInfos, lang.hitch(this, '_createControl', layer, allLayers)); + if (this.controlOptions.ignoreDynamicGroupVisibility) { + array.forEach(this._folderControls, function (control) { + control._checkFolderVisibility(); + }); + } + } + }, + + _createControl: function (layer, allLayers, info) { + // see if there was any override needed from the subLayerInfos array in the controlOptions + var sublayerInfo = array.filter(this.controlOptions.subLayerInfos, function (sli) { + return sli.id === info.id; + }).shift(); + lang.mixin(info, sublayerInfo); + var pid = info.parentLayerId, + slids = info.subLayerIds; + + // it is top level + if (pid === -1 || allLayers.indexOf(pid) === -1) { + if (slids === null) { + // it's a top level sublayer + this._createDynamicSubLayer(info, layer); + } else if (slids !== null) { + // it's a top level folder + this._createDynamicFolder(info, layer); + } + // it is nested within a folder + } else if (pid !== -1 && slids !== null) { + // it's a nested folder + this._createDynamicFolder(info, layer); + } else if (pid !== -1 && slids === null) { + // it's a nested sublayer + this._createDynamicSubLayer(info, layer); + } + }, + + _createDynamicSubLayer: function (info, layer) { + var controlId = layer.id + '-' + info.id + '-sublayer-control', + pid = info.parentLayerId, + parent = null, + control = new DynamicSublayer({ + id: controlId, + control: this, + sublayerInfo: info, + icons: this.icons + }); + + if (pid === -1) { + parent = this.expandNode; + } else { + parent = registry.byId(layer.id + '-' + pid + '-sublayer-control').expandNode; + } + + if (parent) { + domConst.place(control.domNode, parent, 'last'); + control.startup(); + this._sublayerControls.push(control); } + }, + + _createDynamicFolder: function (info, layer) { + var controlId = layer.id + '-' + info.id + '-sublayer-control', + pid = info.parentLayerId, + parent = null, + control = new DynamicFolder({ + id: controlId, + control: this, + sublayerInfo: info, + icons: this.icons + }); + + if (pid === -1) { + parent = this.expandNode; + } else { + parent = registry.byId(layer.id + '-' + pid + '-sublayer-control').expandNode; + } + + if (parent) { + domConst.place(control.domNode, parent, 'last'); + control.startup(); + this._folderControls.push(control); + } + }, + // simply remove expandClickNode _removeSublayerLegends: function () { array.forEach(this._sublayerControls, function (control) { @@ -176,57 +209,101 @@ define([ _setVisibleLayers: function () { // remove aspect handler this._visLayersHandler.remove(); - // because ags doesn't respect a layer group's visibility - // i.e. layer 3 (the group) is not in array but it's sublayers are; sublayers will show - // so check and if group is off also remove the sublayers var layer = this.layer, - setLayers = []; - array.forEach(query('.' + layer.id + '-layerControlSublayerCheck'), function (i) { - if (domAttr.get(i, 'data-checked') === 'checked') { - setLayers.push(parseInt(domAttr.get(i, 'data-sublayer-id'), 10)); + visibleLayers = [], + allVisibleLayers = [], + ignoreDynamicGroupVisibility = this.controlOptions.ignoreDynamicGroupVisibility; + + // get visibility of sub layers not in folders + array.forEach(this._sublayerControls, function (subLayer) { + if (subLayer._isVisible() && subLayer.parentLayerId === -1) { + visibleLayers.push(subLayer.sublayerInfo.id); + allVisibleLayers.push(subLayer.sublayerInfo.id); } }); - array.forEach(layer.layerInfos, function (info) { - if (info.subLayerIds !== null && array.indexOf(setLayers, info.id) === -1) { - array.forEach(info.subLayerIds, function (sub) { - if (array.indexOf(setLayers, sub) !== -1) { - setLayers.splice(array.indexOf(setLayers, sub), 1); - } - }); - } else if (info.subLayerIds !== null && array.indexOf(setLayers, info.id) !== -1) { - setLayers.splice(array.indexOf(setLayers, info.id), 1); + + // get visibility of folders + array.forEach(this._folderControls, lang.hitch(this, function (folder) { + if (folder._isVisible() || (ignoreDynamicGroupVisibility && folder._hasAnyVisibleLayer())) { + allVisibleLayers.push(folder.sublayerInfo.id); } - }); - if (!setLayers.length) { - setLayers.push(-1); + })); + + // get visibility of sub layers that are contained within a folder + array.forEach(this._folderControls, lang.hitch(this, function (folder) { + var subLayers = folder._getSubLayerControls(); + array.forEach(subLayers, lang.hitch(this, function (subLayer) { + if (subLayer._isVisible()) { + allVisibleLayers.push(subLayer.sublayerInfo.id); + if (ignoreDynamicGroupVisibility) { + visibleLayers.push(subLayer.sublayerInfo.id); + return; + } + } + var currentLayer = subLayer; + var oldLayer = null; + function checkParent (f) { + if (f.sublayerInfo.id === currentLayer.sublayerInfo.parentLayerId) { + currentLayer = f; + } + } + while (currentLayer._isVisible() && currentLayer.sublayerInfo.parentLayerId !== -1 && oldLayer !== currentLayer) { + oldLayer = currentLayer; + array.forEach(this._folderControls, checkParent); + } + if (currentLayer._isVisible()) { + visibleLayers.push(subLayer.sublayerInfo.id); + } + })); + })); + + if (!visibleLayers.length) { + visibleLayers.push(-1); } - layer.setVisibleLayers(setLayers); + if (ignoreDynamicGroupVisibility) { + array.forEach(this._folderControls, function (control) { + control._checkFolderVisibility(); + }); + } + + layer.setVisibleLayers(visibleLayers); layer.refresh(); + topic.publish('layerControl/setVisibleLayers', { id: layer.id, - visibleLayers: setLayers + visibleLayers: visibleLayers + }); + + topic.publish('layerControl/setAllVisibleLayers', { + id: layer.id, + allVisibleLayers: allVisibleLayers }); + // set aspect handler this._visLayersHandler = aspect.after(this.layer, 'setVisibleLayers', lang.hitch(this, '_onSetVisibleLayers'), true); }, - _onSetVisibleLayers: function (visLayers) { - var visibleIds = []; - array.forEach(this.layer.layerInfos, function (info) { - if (array.indexOf(visLayers, info.id) !== -1) { - visibleIds.push(info.id); - } - if (info.parentLayerId !== -1 && array.indexOf(visibleIds, info.parentLayerId) === -1) { - visibleIds.push(info.parentLayerId); - } - }); + _onSetVisibleLayers: function (visLayers, noPublish) { + // set the sub layer visibility first array.forEach(this._sublayerControls, function (control) { - if (array.indexOf(visibleIds, control.sublayerInfo.id) !== -1) { - control._setSublayerCheckbox(true); - } else { - control._setSublayerCheckbox(false); - } + var viz = (array.indexOf(visLayers, control.sublayerInfo.id) !== -1); + control._setSublayerCheckbox(viz, null, noPublish); + }); + + // setting the folder (group layer) visibility will change + // visibility for all children sub layer and folders + array.forEach(this._folderControls, function (control) { + var viz = (array.indexOf(visLayers, control.sublayerInfo.id) !== -1); + control._setFolderCheckbox(viz, null, noPublish); }); + + if (this.controlOptions.ignoreDynamicGroupVisibility) { + // finally, set the folder UI (state of checkbox) based on + // the sub layers and folders within the parent folder + array.forEach(this._folderControls, function (control) { + control._checkFolderVisibility(); + }); + } } }); return DynamicControl; -}); +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl/controls/Grouped.js b/viewer/js/gis/dijit/LayerControl/controls/Grouped.js index 707d1d480..e9029b78a 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Grouped.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Grouped.js @@ -32,6 +32,11 @@ define([ _layerType: 'grouped', // constant _esriLayerType: null, // constant + constructor: function () { + this.inherited(arguments); + this.icons.expand = this.icons.groupFolder || this.icons.folder; + this.icons.collapse = this.icons.groupFolderOpen || this.icons.folderOpen; + }, // create and legend _layerTypePreInit: function () { array.forEach(this.layerDetails, lang.hitch(this, function (layerDetail) { diff --git a/viewer/js/gis/dijit/LayerControl/controls/_Control.js b/viewer/js/gis/dijit/LayerControl/controls/_Control.js index 229a5e33c..1ccdcccb7 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_Control.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_Control.js @@ -43,7 +43,7 @@ define([ _expandClickHandler: null, // the click handler for the expandNode constructor: function (params) { if (params.controller) { - this.icons = params.controller.icons; + this.icons = lang.clone(params.controller.icons); } // if not you've got bigger problems this._handlers = []; }, diff --git a/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js b/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js index 15a601720..943caedb5 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js @@ -3,6 +3,7 @@ define([ 'dojo/_base/lang', 'dojo/_base/array', 'dojo/on', + 'dojo/query', 'dojo/dom-class', 'dojo/dom-style', 'dojo/dom-attr', @@ -16,6 +17,7 @@ define([ lang, array, on, + query, domClass, domStyle, domAttr, @@ -33,29 +35,15 @@ define([ templateString: folderTemplate, _expandClickHandler: null, _handlers: [], + postCreate: function () { this.inherited(arguments); - // Should the control be visible or hidden (depends on subLayerInfos)? - if (this.control.controlOptions.subLayerInfos && !this.control.controlOptions.includeUnspecifiedLayers) { - var subLayerInfos = array.map(this.control.controlOptions.subLayerInfos, function (sli) { - return sli.id; - }); - if (array.indexOf(subLayerInfos, this.sublayerInfo.id) < 0) { - domClass.add(this.domNode, 'layerControlHidden'); - } - } - // Should the control be visible or hidden? - if (this.control.controlOptions.layerIds && array.indexOf(this.control.controlOptions.layerIds, this.sublayerInfo.id) < 0) { - domClass.add(this.domNode, 'layerControlHidden'); - } + this._checkHideControl(); var checkNode = this.checkNode; domAttr.set(checkNode, 'data-sublayer-id', this.sublayerInfo.id); + domAttr.set(checkNode, 'data-layer-folder', true); domClass.add(checkNode, this.control.layer.id + '-layerControlSublayerCheck'); - if (array.indexOf(this.control.layer.visibleLayers, this.sublayerInfo.id) !== -1) { - this._setSublayerCheckbox(true, checkNode); - } else { - this._setSublayerCheckbox(false, checkNode); - } + this._handlers.push(on(checkNode, 'click', lang.hitch(this, function (event) { // prevent click event from bubbling @@ -63,12 +51,16 @@ define([ event.stopPropagation(); } - if (domAttr.get(checkNode, 'data-checked') === 'checked') { - this._setSublayerCheckbox(false, checkNode); + if (this.control.controlOptions.ignoreDynamicGroupVisibility) { + if (!this._hasAnyInvisibleLayer()) { + this._setFolderCheckbox(false, checkNode); + } else { + this._setFolderCheckbox(true, checkNode); + } } else { - this._setSublayerCheckbox(true, checkNode); + this._setFolderCheckbox(!this._isVisible(), checkNode); } - this.control._setVisibleLayers(); + this._checkboxScaleRange(); }))); html.set(this.labelNode, this.sublayerInfo.name); @@ -78,6 +70,7 @@ define([ this._handlers.push(this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange'))); } }, + // add on event to expandClickNode _expandClick: function () { var i = this.icons; @@ -99,18 +92,151 @@ define([ } }))); }, - // set checkbox based on layer so it's always in sync - _setSublayerCheckbox: function (checked, checkNode) { + + // toggles visibility of all sub layers + _setFolderCheckbox: function (checked, checkNode, noPublish) { + var i = this.icons, + dataChecked = (checked) ? 'checked' : 'unchecked', + slNodes = this._getSubLayerNodes(); checkNode = checkNode || this.checkNode; - var i = this.icons; - if (checked) { + + if (this.control.controlOptions.ignoreDynamicGroupVisibility) { + array.forEach(slNodes, lang.hitch(this, function (node) { + // child is folder + if (domAttr.get(node, 'data-layer-folder')) { + var folderControl = this._getFolderControl(node); + if (folderControl) { + folderControl._setFolderCheckbox(checked, node, true); + } + // child is sub layer + } else { + domAttr.set(node, 'data-checked', dataChecked); + if (checked) { + domClass.replace(node, i.checked, i.unchecked); + } else { + domClass.replace(node, i.unchecked, i.checked); + } + } + })); + } else { + domAttr.set(checkNode, 'data-checked', dataChecked); + if (checked) { + domClass.replace(checkNode, i.checked, i.unchecked); + } else { + domClass.replace(checkNode, i.unchecked, i.checked); + } + } + + if (!noPublish) { + this.control._setVisibleLayers(); + } + }, + + _hasAnyVisibleLayer: function () { + var slNodes = this._getSubLayerNodes(); + return array.some(slNodes, lang.hitch(this, function (node) { + if (domAttr.get(node, 'data-layer-folder')) { + var folderControl = this._getFolderControl(node); + if (folderControl) { + return folderControl._hasAnyVisibleLayer(); + } + return true; + } + return (domAttr.get(node, 'data-checked') === 'checked'); + })); + }, + + _hasAnyInvisibleLayer: function () { + var slNodes = this._getSubLayerNodes(); + return array.some(slNodes, lang.hitch(this, function (node) { + if (domAttr.get(node, 'data-layer-folder')) { + var folderControl = this._getFolderControl(node); + if (folderControl) { + return folderControl._hasAnyInvisibleLayer(); + } + return true; + } + return (domAttr.get(node, 'data-checked') !== 'checked'); + })); + }, + + _getSubLayerNodes: function () { + var layerIds = this.control.controlOptions.layerIds || []; + var subLayerInfos = []; + if (this.control.controlOptions.subLayerInfos && !this.control.controlOptions.includeUnspecifiedLayers) { + subLayerInfos = array.map(this.control.controlOptions.subLayerInfos, function (sli) { + return sli.id; + }); + } + + var subLayerNodes = query('.' + this.control.layer.id + '-layerControlSublayerCheck', this.domNode); + return array.filter(subLayerNodes, lang.hitch(this, function (node) { + var subLayerID = parseInt(domAttr.get(node, 'data-sublayer-id'), 10); + // is the sublayer contained in this folder + if (array.indexOf(this.sublayerInfo.subLayerIds, subLayerID) < 0) { + return false; + // is the sublayer included in layer's layerIds (if they are defined) + } else if (layerIds.length && array.indexOf(layerIds, subLayerID) < 0) { + return false; + // is the sublayer included in layer's subLayerInfos (if they are defined) + } else if (subLayerInfos.length && array.indexOf(subLayerInfos, subLayerID) < 0) { + return false; + } + return true; + })); + }, + + _getSubLayerControls: function () { + var parentLayerId = this.sublayerInfo.id; + return array.filter(this.control._sublayerControls, function (control) { + return (control.parentLayerId === parentLayerId); + }); + }, + + _getFolderControls: function () { + var parentLayerId = this.sublayerInfo.id; + return array.filter(this.control._folderControls, function (control) { + return (control.parentLayerId === parentLayerId); + }); + }, + + _getFolderControl: function (node) { + var subLayerID = parseInt(domAttr.get(node, 'data-sublayer-id'), 10); + var controls = array.filter(this.control._folderControls, function (control) { + return (control.sublayerInfo.id === subLayerID); + }); + if (controls.length) { + return controls[0]; + } + return null; + }, + + // set visibility of folder (group layer) based on the visibility + // of children sub-layers and folders + _checkFolderVisibility: function () { + var checkNode = this.checkNode, + i = this.icons; + + var hasVisible = this._hasAnyVisibleLayer(); + var hasHidden = this._hasAnyInvisibleLayer(); + + domClass.remove(checkNode, i.checked); + domClass.remove(checkNode, i.unchecked); + domClass.remove(checkNode, i.indeterminate); + + // indeterminate - both visible and invisible layers in group + if (hasVisible && hasHidden) { + domAttr.set(checkNode, 'data-checked', 'indeterminate'); + domClass.add(checkNode, i.indeterminate); + } else if (hasVisible) { domAttr.set(checkNode, 'data-checked', 'checked'); - domClass.replace(checkNode, i.checked, i.unchecked); + domClass.add(checkNode, i.checked); } else { domAttr.set(checkNode, 'data-checked', 'unchecked'); - domClass.replace(checkNode, i.unchecked, i.checked); + domClass.add(checkNode, i.unchecked); } }, + // check scales and add/remove disabled classes from checkbox _checkboxScaleRange: function () { var node = this.checkNode, @@ -122,6 +248,28 @@ define([ domClass.add(node, 'layerControlCheckIconOutScale'); } }, + + + _checkHideControl: function () { + // Should the control be visible or hidden (depends on subLayerInfos)? + if (this.control.controlOptions.subLayerInfos && !this.control.controlOptions.includeUnspecifiedLayers) { + var subLayerInfos = array.map(this.control.controlOptions.subLayerInfos, function (sli) { + return sli.id; + }); + if (array.indexOf(subLayerInfos, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } + } + // Should the control be visible or hidden? + if (this.control.controlOptions.layerIds && array.indexOf(this.control.controlOptions.layerIds, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } + }, + + _isVisible: function () { + return (domAttr.get(this.checkNode, 'data-checked') === 'checked'); + }, + destroy: function () { this.inherited(arguments); this._handlers.forEach(function (h) { diff --git a/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js b/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js index 51c9dd271..172d980c6 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js @@ -32,10 +32,11 @@ define([ TemplatedMixin, sublayerTemplate, i18n - ) { +) { var _DynamicSublayer = declare([WidgetBase, TemplatedMixin], { control: null, sublayerInfo: null, + parentLayerId: null, menu: null, icons: null, // ^args @@ -43,6 +44,7 @@ define([ i18n: i18n, _expandClickHandler: null, _handlers: [], + postCreate: function () { this.inherited(arguments); // Should the control be visible or hidden (depends on subLayerInfos)? @@ -61,11 +63,11 @@ define([ var checkNode = this.checkNode; domAttr.set(checkNode, 'data-sublayer-id', this.sublayerInfo.id); domClass.add(checkNode, this.control.layer.id + '-layerControlSublayerCheck'); - if (array.indexOf(this.control.layer.visibleLayers, this.sublayerInfo.id) !== -1) { - this._setSublayerCheckbox(true, checkNode); - } else { - this._setSublayerCheckbox(false, checkNode); - } + + this.parentLayerId = this.sublayerInfo.parentLayerId; + var layerViz = (array.indexOf(this.control.layer.visibleLayers, this.sublayerInfo.id) !== -1); + this._setSublayerCheckbox(layerViz, checkNode); + this._handlers.push(on(checkNode, 'click', lang.hitch(this, function (event) { // prevent click event from bubbling @@ -87,6 +89,7 @@ define([ this._checkboxScaleRange(); this._handlers.push(this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange'))); } + //set up menu if (this.control.controlOptions.subLayerMenu && this.control.controlOptions.subLayerMenu.length) { @@ -101,6 +104,7 @@ define([ domClass.add(this.menuClickNode, 'hidden'); } }, + _addMenuItem: function (menuItem) { //create the menu item var item = new MenuItem(menuItem); @@ -115,6 +119,7 @@ define([ this.menu.addChild(item); }, // add on event to expandClickNode + _expandClick: function () { var i = this.icons; this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, function () { @@ -136,6 +141,7 @@ define([ })); this._handlers.push(this._expandClickHandler); }, + // set checkbox based on layer so it's always in sync _setSublayerCheckbox: function (checked, checkNode) { checkNode = checkNode || this.checkNode; @@ -148,6 +154,7 @@ define([ domClass.replace(checkNode, i.unchecked, i.checked); } }, + // check scales and add/remove disabled classes from checkbox _checkboxScaleRange: function () { var node = this.checkNode, @@ -159,6 +166,11 @@ define([ domClass.add(node, 'layerControlCheckIconOutScale'); } }, + + _isVisible: function () { + return (domAttr.get(this.checkNode, 'data-checked') === 'checked'); + }, + destroy: function () { this.inherited(arguments); this._handlers.forEach(function (h) { diff --git a/viewer/js/gis/dijit/LayerControl/css/LayerControl.css b/viewer/js/gis/dijit/LayerControl/css/LayerControl.css index e253768fa..1cd7b2f4a 100644 --- a/viewer/js/gis/dijit/LayerControl/css/LayerControl.css +++ b/viewer/js/gis/dijit/LayerControl/css/LayerControl.css @@ -88,16 +88,16 @@ color: #666; } +.layerControlDijit .layerControlTableExpand .layerControlIcon-Folder { + color: #F4D57A; +} + .layerControlDijit .layerControlTableCheck .fa-border { border-color: #333; border-radius: 3px; padding: 0.15em 0.1875em 0.1125em; } -.layerControlDijit .layerControlTableCheck .layerControlIcon-Folder { - color: #333; -} - .layerControlDijit .layerControlTableCheck .layerControlIcon-Checked { color: #090; } diff --git a/viewer/js/viewer/_MapMixin.js b/viewer/js/viewer/_MapMixin.js index 3d26795b4..e3496da5c 100644 --- a/viewer/js/viewer/_MapMixin.js +++ b/viewer/js/viewer/_MapMixin.js @@ -29,6 +29,8 @@ define([ }, startup: function () { + // ignore visibility of group layers in dynamic layers? + this.ignoreDynamicGroupVisibility = (this.config.ignoreDynamicGroupVisibility === false) ? false : true; this.inherited(arguments); this.layoutDeferred.then(lang.hitch(this, 'initMapAsync')); }, @@ -149,7 +151,7 @@ define([ }, _initLayer: function (layer, Layer) { - var l; + var l = null; if (layer.url) { l = new Layer(layer.url, layer.options); } else { @@ -175,11 +177,14 @@ define([ } //LayerControl LayerInfos array + var layerControlOptions = lang.mixin({ + ignoreDynamicGroupVisibility: this.ignoreDynamicGroupVisibility + }, layer.layerControlLayerInfos); this.layerControlLayerInfos.unshift({ //unshift instead of push to keep layer ordering in LayerControl intact layer: l, type: layer.type, title: layer.title, - controlOptions: layer.layerControlLayerInfos + controlOptions: layerControlOptions }); if (layer.type === 'feature') { @@ -194,10 +199,15 @@ define([ } } + if (layer.type === 'dynamic' && this.ignoreDynamicGroupVisibility) { + on(l, 'load', lang.hitch(this, 'removeGroupLayers')); + } + if (layer.type === 'dynamic' || layer.type === 'feature') { var idOptions = { layer: l, - title: layer.title + title: layer.title, + ignoreDynamicGroupVisibility: this.ignoreDynamicGroupVisibility }; if (layer.identifyLayerInfos) { lang.mixin(idOptions, layer.identifyLayerInfos); @@ -207,6 +217,26 @@ define([ } } }, + + removeGroupLayers: function (res) { + var visibleLayers = [], groupRemoved = false, layer = res.layer, + originalVisibleLayers = layer.visibleLayers || layer._defaultVisibleLayers; + array.forEach(originalVisibleLayers, function (subLayerId) { + var subLayerInfo = array.filter(layer.layerInfos, function (sli) { + return sli.id === subLayerId; + })[0]; + if (subLayerInfo && subLayerInfo.subLayerIds === null) { + visibleLayers.push(subLayerId); + } else { + groupRemoved = true; + } + }); + + if (visibleLayers.length > 0 && groupRemoved) { + layer.setVisibleLayers(visibleLayers); + } + }, + initMapComplete: function (warnings) { if (warnings && warnings.length > 0) { this.handleError({