diff --git a/scss/_logger.scss b/scss/_logger.scss new file mode 100644 index 000000000..bc2da384a --- /dev/null +++ b/scss/_logger.scss @@ -0,0 +1,57 @@ +.logger-toast { + border-radius: 0.5em; + box-shadow: 0 0 8px #888; + padding: 1em; + right: 0; + left: 0; + margin-right: auto; + margin-left: auto; + text-align: center; + position: fixed; + z-index: 999; + display: inline-block; + max-width: 90%; + bottom: 2.5rem; +} + +.logger-primary { + fill: #084298; + color: #084298; + background-color: #cfe2ff; + border-color: #b6d4fe; +} + +.logger-success { + fill: #0f5132; + color: #0f5132; + background-color: #d1e7dd; + border-color: #badbcc; +} + +.logger-info { + fill: #055160; + color: #055160; + background-color: #cff4fc; + border-color: #b6effb; +} + +.logger-warning { + fill: #664d03; + color: #664d03; + background-color: #fff3cd; + border-color: #ffecb5; +} + +.logger-danger { + fill: #842029; + color: #842029; + background-color: #f8d7da; + border-color: #f5c2c7; +} + +.logger-light { + fill: #636464; + color: #636464; + background-color: #fefefe; + border-color: #fdfdfe; +} \ No newline at end of file diff --git a/scss/origo.scss b/scss/origo.scss index adef8d848..3b2003b57 100644 --- a/scss/origo.scss +++ b/scss/origo.scss @@ -49,6 +49,7 @@ @import 'scalepicker'; @import 'embedded-overlay'; @import 'spinner'; + @import 'logger'; } html, diff --git a/src/components/logger.js b/src/components/logger.js new file mode 100644 index 000000000..4b603de2b --- /dev/null +++ b/src/components/logger.js @@ -0,0 +1,109 @@ +import { Icon, Component, Modal } from '../ui'; + +let viewer; +let defaults = { + toast: { + status: 'light', + title: 'Meddelande', + duration: 5000 + }, + modal: { + status: 'light', + title: 'Meddelande', + duration: 0 + } +}; + +function getClass(status) { + let cls; + if (status === 'primary') { + cls = 'logger-primary'; + } else if (status === 'success') { + cls = 'logger-success'; + } else if (status === 'info') { + cls = 'logger-info'; + } else if (status === 'warning') { + cls = 'logger-warning'; + } else if (status === 'danger') { + cls = 'logger-danger'; + } else { + cls = 'logger-light'; + } + return cls; +} + +const createModal = function createModal(options) { + const modalSettings = { ...defaults.modal, ...options }; + const { + title = '', + message = '', + duration, + status + } = modalSettings; + const contentCls = getClass(status); + + let modal = Modal({ + title, + content: message, + target: viewer.getId(), + contentCls + }); + + if (duration && duration > 0) { + setTimeout(() => { + modal.closeModal(); + modal = null; + }, duration); + } +}; + +const createToast = function createToast(options = {}) { + const toastSettings = { ...defaults.toast, ...options }; + const { + status, + duration, + icon, + title = '', + message = '' + } = toastSettings; + + const contentCls = getClass(status); + const toast = document.createElement('div'); + const parentElement = document.getElementById(viewer.getId()); + parentElement.appendChild(toast); + toast.classList.add('logger-toast'); + toast.classList.add(contentCls); + + const content = ` +
+ + ${icon ? Icon({ icon, cls: `${contentCls} icon-medium`, style: 'vertical-align:bottom' }).render() : ''} + + ${title} +
+ ${message} + `; + toast.innerHTML = content; + + setTimeout(() => { + toast.parentNode.removeChild(toast); + }, duration > 0 ? duration : 5000); +}; + +const Logger = function Logger(options = {}) { + defaults = { ...defaults, ...options }; + return Component({ + name: 'logger', + createModal, + createToast, + onAdd(evt) { + viewer = evt.target; + this.render(); + }, + render() { + this.dispatch('render'); + } + }); +}; + +export default Logger; diff --git a/src/controls/legend.js b/src/controls/legend.js index 925e01569..2d0c48732 100644 --- a/src/controls/legend.js +++ b/src/controls/legend.js @@ -196,8 +196,7 @@ const Legend = function Legend(options = {}) { }, style: { 'vertical-align': 'bottom', - 'margin-bottom': '13px', - 'padding-right': '6px' + margin: '0.45rem 0.5rem' }, icon: '#ic_close_fullscreen_24px', iconStyle: { @@ -213,8 +212,7 @@ const Legend = function Legend(options = {}) { }, style: { 'vertical-align': 'bottom', - 'margin-bottom': '13px', - 'padding-right': '6px' + margin: '0.45rem 0.5rem' }, icon: '#ic_open_in_full_24px', iconStyle: { @@ -666,8 +664,7 @@ const Legend = function Legend(options = {}) { cls: 'icon-smaller small round grey-lightest', style: { 'vertical-align': 'bottom', - 'margin-bottom': '8.5px', - 'margin-top': '-2px' + margin: '0.2rem 0' }, icon: '#ic_close_24px', state: closeButtonState, @@ -699,7 +696,7 @@ const Legend = function Legend(options = {}) { style: { display: 'inline', 'text-align': 'right', - 'margin-right': '6px' + 'margin-right': '0.1rem' }, components: legendControlCmps }); @@ -712,7 +709,7 @@ const Legend = function Legend(options = {}) { 'background-color': '#fff', 'border-top': '1px solid #dbdbdb', 'border-radius': '0.5rem', - 'padding-bottom': '6px' + 'line-height': '0' }, components: baselayerCmps }); diff --git a/src/controls/legend/visibleOverlays.js b/src/controls/legend/visibleOverlays.js index 60bf4a733..15e4b3f50 100644 --- a/src/controls/legend/visibleOverlays.js +++ b/src/controls/legend/visibleOverlays.js @@ -50,7 +50,7 @@ const Overlays = function Overlays(options) { mainComponent: groupContainer, secondaryComponent: layerProps, cls: 'right flex width-100', - style: { width: '100%' }, + style: { width: '100%', display: 'flex' }, legendSlideNav: false, viewer }); diff --git a/src/getfeatureinfo.js b/src/getfeatureinfo.js index 503d533e1..9d02b00b3 100644 --- a/src/getfeatureinfo.js +++ b/src/getfeatureinfo.js @@ -319,23 +319,27 @@ function getFeatureInfoRequests({ return requests; } -function getFeaturesFromRemote(requestOptions, viewer, textHtmlHandler) { +async function getFeaturesFromRemote(requestOptions, viewer, textHtmlHandler) { const requestResult = []; - const requestPromises = getFeatureInfoRequests(requestOptions, viewer, textHtmlHandler).map((request) => request.fn.then((features) => { - const layer = viewer.getLayer(request.layer); - const groupLayers = viewer.getGroupLayers(); - const map = viewer.getMap(); - if (features) { - features.forEach((feature) => { + const requests = getFeatureInfoRequests(requestOptions, viewer, textHtmlHandler); + const featureInfoPromises = requests.map((request) => request.fn); + const featureInfoPromisesResults = await Promise.allSettled(featureInfoPromises); + + featureInfoPromisesResults.forEach((result, i) => { + const layer = viewer.getLayer(requests[i].layer); + if (result.status === 'fulfilled' && result.value) { + const groupLayers = viewer.getGroupLayers(); + const map = viewer.getMap(); + result.value.forEach((feature) => { const si = createSelectedItem(feature, layer, map, groupLayers); requestResult.push(si); }); - return requestResult; + } else { + console.warn(`GetFeatureInfo request failed for layer: ${layer.get('name')}`); } + }); - return false; - })); - return Promise.all([...requestPromises]).then(() => requestResult).catch(error => console.log(error)); + return requestResult; } function getFeaturesAtPixel({ diff --git a/src/ui/modal.js b/src/ui/modal.js index 6ab2a3952..54bf41049 100644 --- a/src/ui/modal.js +++ b/src/ui/modal.js @@ -25,6 +25,7 @@ export default function Modal(options = {}) { contentElement, contentCmp, cls = '', + contentCls = '', isStatic = options.static, target, closeIcon = '#ic_close_24px', @@ -139,7 +140,7 @@ export default function Modal(options = {}) { } return `
${screenEl.render()} -
+
${headerEl.render()} ${contentEl.render()}
diff --git a/src/viewer.js b/src/viewer.js index 49b331477..4dc16a4f8 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -18,6 +18,7 @@ import flattenGroups from './utils/flattengroups'; import getcenter from './geometry/getcenter'; import isEmbedded from './utils/isembedded'; import generateUUID from './utils/generateuuid'; +import Logger from './components/logger'; import permalink from './permalink/permalink'; import Stylewindow from './style/stylewindow'; @@ -54,6 +55,7 @@ const Viewer = function Viewer(targetOption, options = {}) { source = {}, clusterOptions = {}, tileGridOptions = {}, + loggerOptions = {}, url, palette } = options; @@ -105,6 +107,7 @@ const Viewer = function Viewer(targetOption, options = {}) { const footer = Footer({ data: footerData }); + const logger = Logger(loggerOptions); const centerMarker = CenterMarker(); let mapSize; @@ -527,6 +530,10 @@ const Viewer = function Viewer(targetOption, options = {}) { return urlParams; }; + const getLogger = function getLogger() { + return logger; + }; + /** * Internal helper used when urlParams.feature is set and the popup should be displayed. * @param {any} feature @@ -588,6 +595,7 @@ const Viewer = function Viewer(targetOption, options = {}) { this.addComponent(selectionmanager); this.addComponent(featureinfo); this.addComponent(centerMarker); + this.addComponent(logger); this.addControls(); @@ -718,7 +726,8 @@ const Viewer = function Viewer(targetOption, options = {}) { getEmbedded, permalink, generateUUID, - centerMarker + centerMarker, + getLogger }); };