<commit_before>/**
 * @author Dmytro Zemlianskyi from Ubrainians for imCode
 * 23.04.19
 */
define(
    'imcms-temporal-data-tab-builder',
    [
        'imcms-super-admin-tab', 'imcms-bem-builder', 'imcms-i18n-texts', 'imcms-temporal-data-rest-api',
        'imcms-components-builder'
    ],
    function (SuperAdminTab, BEM, texts, temporalDataApi, components) {

        texts = texts.superAdmin.temporalContent;

        function buildReindexRow() {
            function buildReindexTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.rebuildIndex, {});

            }

            function buildInitReindexActionButton() {
                let $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => {
                        temporalDataApi.rebuildDocumentIndex();
                    }
                });

                return components.buttons.buttonsContainer('<div>', [$button]);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildReindexTitleMessage(),
                    'action-button': buildInitReindexActionButton(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildPublicDocumentCacheRow() {
            function buildPublicDocumentCacheTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deletePublicDocCache, {});

            }

            function buildInitDeletePublicDocumentActionButton() {
                let $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => {
                        temporalDataApi.deletePublicDocumentCache();
                    }
                });

                return components.buttons.buttonsContainer('<div>', [$button]);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildPublicDocumentCacheTitleMessage(),
                    'action-button': buildInitDeletePublicDocumentActionButton(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildStaticContentRow() {
            function buildStaticContenTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deleteStaticCache, {});

            }

            function buildInitDeleteStaticContentActionButton() {
                let $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => {
                        temporalDataApi.deleteStaticContentCache();
                    }
                });

                return components.buttons.buttonsContainer('<div>', [$button]);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildStaticContenTitleMessage(),
                    'action-button': buildInitDeleteStaticContentActionButton(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildOtherContentRow() {
            function buildOtherContenTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deleteOtherCache, {});

            }

            function buildInitDeleteOtherContentActionButton() {
                let $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => {
                        temporalDataApi.deleteOtherContentCache();
                    }
                });

                return components.buttons.buttonsContainer('<div>', [$button]);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildOtherContenTitleMessage(),
                    'action-button': buildInitDeleteOtherContentActionButton(),
                }
            }).buildBlockStructure('<div>');
        }

        return new SuperAdminTab(texts.name, [
            buildReindexRow(),
            buildPublicDocumentCacheRow(),
            buildStaticContentRow(),
            buildOtherContentRow(),
        ]);
    }
);
<commit_msg>Issue IMCMS-452: Status in Cache tab - Add status animations; - Refactor code;<commit_after>/**
 * @author Dmytro Zemlianskyi from Ubrainians for imCode
 * 23.04.19
 */
define(
    'imcms-temporal-data-tab-builder',
    [
        'imcms-super-admin-tab', 'imcms-bem-builder', 'imcms-i18n-texts', 'imcms-temporal-data-rest-api',
        'imcms-components-builder', 'jquery'
    ],
    function (SuperAdminTab, BEM, texts, temporalDataApi, components, $) {

        texts = texts.superAdmin.temporalContent;

        function buildActions($button, $loading, $success) {
            return new BEM({
                block: 'actions',
                elements: {
                    'button': $button,
                    'loading': $loading,
                    'success': $success,
                },
            }).buildBlockStructure('<div>');
        }

        function buildLoadingAnimation() {
            return $('<div>', {
                class: 'loading-animation',
                style: 'display: none',
            });
        }

        function buildSuccessAnimation() {
            return $('<div>', {
                class: 'success-animation',
                style: 'display: none',
            });
        }

        function animateRequest(request, $loading, $success) {
            $success.hide();
            $loading.show();
            request().done(() => {
                $loading.hide();
                $success.show();
            });
        }

        function buildReindexRow() {
            function buildReindexTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.rebuildIndex, {});

            }

            function buildReindexActions() {
                const $loading = buildLoadingAnimation();
                const $success = buildSuccessAnimation();

                const $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => animateRequest(temporalDataApi.rebuildDocumentIndex, $loading, $success),
                });

                return buildActions($button, $loading, $success);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildReindexTitleMessage(),
                    'actions': buildReindexActions(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildPublicDocumentCacheRow() {
            function buildPublicDocumentCacheTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deletePublicDocCache, {});
            }

            function buildPublicDocumentActions() {
                const $loading = buildLoadingAnimation();
                const $success = buildSuccessAnimation();

                const $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => animateRequest(temporalDataApi.deletePublicDocumentCache, $loading, $success),
                });

                return buildActions($button, $loading, $success);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildPublicDocumentCacheTitleMessage(),
                    'actions': buildPublicDocumentActions(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildStaticContentRow() {
            function buildStaticContenTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deleteStaticCache, {});
            }

            function buildInitDeleteStaticContentActions() {
                const $loading = buildLoadingAnimation();
                const $success = buildSuccessAnimation();

                const $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => animateRequest(temporalDataApi.deleteStaticContentCache, $loading, $success),
                });

                return buildActions($button, $loading, $success);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildStaticContenTitleMessage(),
                    'actions': buildInitDeleteStaticContentActions(),
                }
            }).buildBlockStructure('<div>');
        }

        function buildOtherContentRow() {
            function buildOtherContentTitleMessage() {
                return components.texts.titleText('<div>', texts.actions.deleteOtherCache, {});
            }

            function buildInitDeleteOtherContentActions() {
                const $loading = buildLoadingAnimation();
                const $success = buildSuccessAnimation();

                const $button = components.buttons.warningButton({
                    'class': 'imcms-buttons imcms-form__field',
                    text: texts.init,
                    click: () => animateRequest(temporalDataApi.deleteOtherContentCache, $loading, $success),
                });

                return buildActions($button, $loading, $success);
            }

            return new BEM({
                block: 'imcms-content-action-row',
                elements: {
                    'action-title': buildOtherContentTitleMessage(),
                    'actions': buildInitDeleteOtherContentActions(),
                }
            }).buildBlockStructure('<div>');
        }

        return new SuperAdminTab(texts.name, [
            buildReindexRow(),
            buildPublicDocumentCacheRow(),
            buildStaticContentRow(),
            buildOtherContentRow(),
        ]);
    }
);
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 *
 * @function
 * @private
 * @experimental
 */
sap.ui.define(function () {
	"use strict";

	return function (aTags, sRelativePath, sAttributePrefix) {
		var defaultDataConfig = {
			"DataRequestUrl": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.URL}",
				"type": "string",
				"path": sRelativePath + "data/request/url"
			},
			"DataRequestMode": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.MODE}",
				"type": "enum",
				"enum": [
					"no-cors",
					"same-origin",
					"cors"
				],
				"defaultValue": "cors",
				"path": sRelativePath + "data/request/mode",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestMethod": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.METHOD}",
				"type": "enum",
				"enum": [
					"GET",
					"POST"
				],
				"defaultValue": "GET",
				"path": sRelativePath + "data/request/method",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestParameters": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.PARAMETERS}",
				"type": "map",
				"path": sRelativePath + "data/request/parameters",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestHeaders": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.HEADERS}",
				"type": "map",
				"path": sRelativePath + "data/request/headers",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestWithCredentials": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.WITHCREDENTIALS}",
				"type": "boolean",
				"defaultValue": false,
				"path": sRelativePath + "data/request/withCredentials",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataJson": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.JSON}",
				"type": "json",
				"path": sRelativePath + "data/json"
			},
			"DataPath": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.PATH}",
				"type": "string",
				"path": sRelativePath + "data/path"
			},
			"DataServiceName": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.SERVICE.NAME}",
				"type": "string",
				"path": sRelativePath + "data/service/name",
				"visible": false // Currently undocumented
			},
			"DataServiceParameters": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.SERVICE.PARAMETERS}",
				"type": "map",
				"path": sRelativePath + "data/service/parameters",
				"visible": false // Currently undocumented
			},
			"DataUpdateInterval": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.UPDATEINTERVAL}",
				"type": "number",
				"path": sRelativePath + "data/updateInterval"
			}
		};

		var oGeneratedDataConfig = {};
		Object.keys(defaultDataConfig).forEach(function (sKey) {
			oGeneratedDataConfig[sAttributePrefix + sKey] = defaultDataConfig[sKey];
		});
		return oGeneratedDataConfig;
	};
});
<commit_msg>[INTERNAL] sap.ui.integration: Fix visibility of JSON Data property<commit_after>/*!
 * ${copyright}
 *
 * @function
 * @private
 * @experimental
 */
sap.ui.define(function () {
	"use strict";

	return function (aTags, sRelativePath, sAttributePrefix) {
		var defaultDataConfig = {
			"DataRequestUrl": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.URL}",
				"type": "string",
				"path": sRelativePath + "data/request/url"
			},
			"DataRequestMode": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.MODE}",
				"type": "enum",
				"enum": [
					"no-cors",
					"same-origin",
					"cors"
				],
				"defaultValue": "cors",
				"path": sRelativePath + "data/request/mode",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestMethod": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.METHOD}",
				"type": "enum",
				"enum": [
					"GET",
					"POST"
				],
				"defaultValue": "GET",
				"path": sRelativePath + "data/request/method",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestParameters": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.PARAMETERS}",
				"type": "map",
				"path": sRelativePath + "data/request/parameters",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestHeaders": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.HEADERS}",
				"type": "map",
				"path": sRelativePath + "data/request/headers",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataRequestWithCredentials": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.REQUEST.WITHCREDENTIALS}",
				"type": "boolean",
				"defaultValue": false,
				"path": sRelativePath + "data/request/withCredentials",
				"visible": "{= !!${context>" + sRelativePath + "data/request/url} }"
			},
			"DataJson": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.JSON}",
				"type": "json",
				"path": sRelativePath + "data/json",
				"visible": "{= !${context>" + sRelativePath + "data/request/url} }"
			},
			"DataPath": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.PATH}",
				"type": "string",
				"path": sRelativePath + "data/path"
			},
			"DataServiceName": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.SERVICE.NAME}",
				"type": "string",
				"path": sRelativePath + "data/service/name",
				"visible": false // Currently undocumented
			},
			"DataServiceParameters": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.SERVICE.PARAMETERS}",
				"type": "map",
				"path": sRelativePath + "data/service/parameters",
				"visible": false // Currently undocumented
			},
			"DataUpdateInterval": {
				"tags": aTags.concat(["data"]),
				"label": "{i18n>CARD_EDITOR.DATA.UPDATEINTERVAL}",
				"type": "number",
				"path": sRelativePath + "data/updateInterval"
			}
		};

		var oGeneratedDataConfig = {};
		Object.keys(defaultDataConfig).forEach(function (sKey) {
			oGeneratedDataConfig[sAttributePrefix + sKey] = defaultDataConfig[sKey];
		});
		return oGeneratedDataConfig;
	};
});
<|endoftext|>


<commit_before>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017 Waltz open source project
 * See README.md for more information
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from "lodash";
import {CORE_API} from "../../../common/services/core-api-utils";
import {mkApplicationSelectionOptions} from "../../../common/selector-utils";
import {entityLifecycleStatus} from '../../../common/services/enums/entity-lifecycle-status';

import template from "./logical-flows-boingy-graph.html";

const bindings = {
    filters: "<",
    parentEntityRef: "<"
};

const defaultFilterOptions = {
    type: "ALL",
    scope: "INTRA"
};

const defaultOptions = {
    graphTweakers: {
        node : {
            enter: (selection) => console.log("default graphTweaker.node.entry, selection: ", selection),
        },
        link : {
            enter: (selection) => selection.attr("stroke", "red")
        }
    }
};

const initialState = {
    applications: [],
    flows: [],
    decorators: [],
    selectedNode: null,
    isolatedNode: null,
    usedDataTypes: [],
    filterOptions: defaultFilterOptions,
    options: defaultOptions,
    optionsVisible: false,
    visibility: {
        boingyEverShown: false,
        ignoreLimits: false,
        summaries: false,
        loadingFlows: false,
        loadingStats: false
    }
};

function calculateEntities(flows = []) {
    return _.chain(flows)
        .flatMap(f => [f.source, f.target])
        .uniqBy("id")
        .value();
}

function mkScopeFilterFn(appIds = [], scope = "INTRA") {
    return (f) => {
        switch (scope) {
            case "INTRA":
                return _.includes(appIds, f.target.id) && _.includes(appIds, f.source.id);
            case "ALL":
                return true;
            case "INBOUND":
                return _.includes(appIds, f.target.id);
            case "OUTBOUND":
                return _.includes(appIds, f.source.id);
        }
    };
}

function mkTypeFilterFn(decorators = []) {
    const flowIds = _.chain(decorators)
        .map("dataFlowId")
        .uniq()
        .value();
    return f => _.includes(flowIds, f.id);
}

function mkIsolatedNodeFilterFn(isolatedNode) {
    return isolatedNode
        ? f => f.source.id === isolatedNode.id || f.target.id === isolatedNode.id
        : () => true;
}

function buildFlowFilter(filterOptions = defaultFilterOptions,
                         isolatedNode,
                         appIds = [],
                         flowDecorators = []) {

    const scope = _.chain(filterOptions)
        .map(d => d.scope)
        .first()
        .value();

    const typeFilterFn = mkTypeFilterFn(flowDecorators);
    const scopeFilterFn = mkScopeFilterFn(appIds, scope);
    const isolatedNodeFilterFn = mkIsolatedNodeFilterFn(isolatedNode);
    return f => typeFilterFn(f) && scopeFilterFn(f) && isolatedNodeFilterFn(f);
}

function buildDecoratorFilter(options = defaultFilterOptions) {
    const datatypeIds = _.map(options, option => Number(option.type));
    return d => {
        const isDataType = d.decoratorEntity.kind === "DATA_TYPE";
        const matchesDataType = options.type === "ALL" || _.includes(datatypeIds, d.decoratorEntity.id);
        return isDataType && matchesDataType;
    };
}

function calculateFlowData(allFlows = [],
                           applications = [],
                           allDecorators = [],
                           filterOptions = defaultFilterOptions,
                           isolatedNode) {
    // note order is important.  We need to find decorators first
    const decoratorFilterFn = buildDecoratorFilter(filterOptions);
    const decorators = _.filter(allDecorators, decoratorFilterFn);

    const appIds = _.map(applications, "id");
    const flowFilterFn = buildFlowFilter(filterOptions, isolatedNode, appIds, decorators);
    const flows = _.filter(allFlows, flowFilterFn);

    const entities = calculateEntities(flows);

    return {flows, entities, decorators};
}

function getDataTypeIds(allDataTypes = [], decorators = []) {
    const dataTypesById = _.keyBy(allDataTypes, "id");
    return _.chain(decorators)
        .filter(dc => dc.decoratorEntity.kind === "DATA_TYPE")
        .map("decoratorEntity.id")
        .uniq()
        .map(dtId => dataTypesById[dtId])
        .orderBy("name")
        .value();
}

function prepareGraphTweakers(logicalFlowUtilityService,
                              applications = [],
                              decorators = [],
                              nodeSelectFn = (d) => console.log("dftg: no nodeSelectFn given", d))
{
    const appIds = _.map(applications, "id");
    const tweakers = logicalFlowUtilityService.buildGraphTweakers(appIds, decorators);

    const dfltNodeEnter = tweakers.node.enter;
    const nodeEnter = selection => selection
        .on("click.node-select", nodeSelectFn)
        .call(dfltNodeEnter);

    tweakers.node.enter = nodeEnter;
    return tweakers;
}

function controller($scope,
                    $q,
                    serviceBroker,
                    logicalFlowUtilityService) {

    const vm = _.defaultsDeep(this, initialState);

    function unpinAll() {
        _.forEach(
            vm.filteredFlowData.entities,
            d => { d.fx = null; d.fy = null; });
    }

    const loadDetail = () => {
        vm.visibility.loadingFlows = true;

        const flowPromise = serviceBroker
            .loadViewData(
                CORE_API.LogicalFlowStore.findBySelector,
                [ vm.selector ])
            .then(r => vm.flows = r.data);

        const decoratorPromise = serviceBroker
            .loadViewData(
                CORE_API.LogicalFlowDecoratorStore.findBySelector,
                [ vm.selector ])
            .then(r => {
                vm.decorators = r.data;
                vm.usedDataTypes = getDataTypeIds(vm.allDataTypes, vm.decorators);
            });

        const appsPromise = serviceBroker
            .loadViewData(
                CORE_API.ApplicationStore.findBySelector,
                [ vm.selector ])
            .then(r => vm.applications = r.data);

        return $q
            .all([flowPromise, decoratorPromise, appsPromise])
            .then(() => {
                vm.filterChanged();
                vm.visibility.loadingFlows = false;
            });
    };

    vm.filterChanged = (filterOptions = vm.filterOptions) => {

        const children = _.chain(vm.allDataTypes)
            .filter(d => d.parentId === Number(filterOptions.type))
            .map(d => { return {
                type: d.id,
                scope: filterOptions.scope
            }})
            .value();

        vm.filterOptions = _.concat(filterOptions, children);

        if (! (vm.flows && vm.decorators)) return;

        vm.filteredFlowData = calculateFlowData(
            vm.flows,
            vm.applications,
            vm.decorators,
            vm.filterOptions,
            vm.isolatedNode);

        vm.graphTweakers = prepareGraphTweakers(
            logicalFlowUtilityService,
            vm.applications,
            vm.filteredFlowData.decorators,
            node => $scope.$applyAsync(() => vm.selectedNode = node));
    };

    vm.isolate = (node) => {
        unpinAll();
        vm.isolatedNode = node;
        vm.filterChanged();
    };

    vm.dismissSelectedNode = () => {
        unpinAll();
        vm.isolatedNode = null;
        vm.selectedNode = null;
        vm.filterChanged();
    };

    vm.refocusNode = node => {
        vm.selectedNode = node;
        vm.isolate(node);
    };

    vm.$onChanges = (c) => {
        if (vm.parentEntityRef) {
            vm.selector = mkApplicationSelectionOptions(
                vm.parentEntityRef,
                undefined,
                [entityLifecycleStatus.ACTIVE.key],
                vm.filters);
            loadDetail();
        }
    };

    vm.$onInit = () => {
        serviceBroker
            .loadAppData(CORE_API.DataTypeStore.findAll)
            .then(r => vm.allDataTypes = r.data);
    };

}

controller.$inject = [
    "$scope",
    "$q",
    "ServiceBroker",
    "LogicalFlowUtilityService"
];

const component = {
    controller,
    bindings,
    template
};

export default {
    component,
    id: "waltzLogicalFlowsBoingyGraph"
};
<commit_msg>Logical flow boingy graph should display flows for child datatypes<commit_after>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017 Waltz open source project
 * See README.md for more information
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from "lodash";
import {CORE_API} from "../../../common/services/core-api-utils";
import {mkApplicationSelectionOptions} from "../../../common/selector-utils";
import {entityLifecycleStatus} from '../../../common/services/enums/entity-lifecycle-status';

import template from "./logical-flows-boingy-graph.html";
import {buildHierarchies, findNode, flattenChildren} from "../../../common/hierarchy-utils";

const bindings = {
    filters: "<",
    parentEntityRef: "<"
};

const defaultFilterOptions = {
    type: "ALL",
    scope: "INTRA"
};

const defaultOptions = {
    graphTweakers: {
        node : {
            enter: (selection) => console.log("default graphTweaker.node.entry, selection: ", selection),
        },
        link : {
            enter: (selection) => selection.attr("stroke", "red")
        }
    }
};

const initialState = {
    applications: [],
    flows: [],
    decorators: [],
    selectedNode: null,
    isolatedNode: null,
    usedDataTypes: [],
    filterOptions: defaultFilterOptions,
    options: defaultOptions,
    optionsVisible: false,
    visibility: {
        boingyEverShown: false,
        ignoreLimits: false,
        summaries: false,
        loadingFlows: false,
        loadingStats: false
    }
};

function calculateEntities(flows = []) {
    return _.chain(flows)
        .flatMap(f => [f.source, f.target])
        .uniqBy("id")
        .value();
}

function mkScopeFilterFn(appIds = [], scope = "INTRA") {
    return (f) => {
        switch (scope) {
            case "INTRA":
                return _.includes(appIds, f.target.id) && _.includes(appIds, f.source.id);
            case "ALL":
                return true;
            case "INBOUND":
                return _.includes(appIds, f.target.id);
            case "OUTBOUND":
                return _.includes(appIds, f.source.id);
        }
    };
}

function mkTypeFilterFn(decorators = []) {
    const flowIds = _.chain(decorators)
        .map("dataFlowId")
        .uniq()
        .value();
    return f => _.includes(flowIds, f.id);
}

function mkIsolatedNodeFilterFn(isolatedNode) {
    return isolatedNode
        ? f => f.source.id === isolatedNode.id || f.target.id === isolatedNode.id
        : () => true;
}

function buildFlowFilter(filterOptions = defaultFilterOptions,
                         isolatedNode,
                         appIds = [],
                         flowDecorators = []) {

    const scope = _.chain(filterOptions)
        .map(d => d.scope)
        .first()
        .value();

    const typeFilterFn = mkTypeFilterFn(flowDecorators);
    const scopeFilterFn = mkScopeFilterFn(appIds, scope);
    const isolatedNodeFilterFn = mkIsolatedNodeFilterFn(isolatedNode);
    return f => typeFilterFn(f) && scopeFilterFn(f) && isolatedNodeFilterFn(f);
}

function buildDecoratorFilter(options = defaultFilterOptions) {
    const datatypeIds = _.map(options, option => (option.type === "ALL") ? "ALL" : Number(option.type));
    return d => {
        const isDataType = d.decoratorEntity.kind === "DATA_TYPE";
        const matchesDataType = _.includes(datatypeIds, "ALL") || _.includes(datatypeIds, d.decoratorEntity.id);
        return isDataType && matchesDataType;
    };
}

function calculateFlowData(allFlows = [],
                           applications = [],
                           allDecorators = [],
                           filterOptions = defaultFilterOptions,
                           isolatedNode) {
    // note order is important.  We need to find decorators first
    const decoratorFilterFn = buildDecoratorFilter(filterOptions);
    const decorators = _.filter(allDecorators, decoratorFilterFn);

    const appIds = _.map(applications, "id");
    const flowFilterFn = buildFlowFilter(filterOptions, isolatedNode, appIds, decorators);
    const flows = _.filter(allFlows, flowFilterFn);

    const entities = calculateEntities(flows);

    return {flows, entities, decorators};
}

function getDataTypeIds(allDataTypes = [], decorators = []) {
    const dataTypesById = _.keyBy(allDataTypes, "id");
    return _.chain(decorators)
        .filter(dc => dc.decoratorEntity.kind === "DATA_TYPE")
        .map("decoratorEntity.id")
        .uniq()
        .map(dtId => dataTypesById[dtId])
        .orderBy("name")
        .value();
}

function prepareGraphTweakers(logicalFlowUtilityService,
                              applications = [],
                              decorators = [],
                              nodeSelectFn = (d) => console.log("dftg: no nodeSelectFn given", d))
{
    const appIds = _.map(applications, "id");
    const tweakers = logicalFlowUtilityService.buildGraphTweakers(appIds, decorators);

    const dfltNodeEnter = tweakers.node.enter;
    const nodeEnter = selection => selection
        .on("click.node-select", nodeSelectFn)
        .call(dfltNodeEnter);

    tweakers.node.enter = nodeEnter;
    return tweakers;
}

function controller($scope,
                    $q,
                    serviceBroker,
                    logicalFlowUtilityService) {

    const vm = _.defaultsDeep(this, initialState);

    function unpinAll() {
        _.forEach(
            vm.filteredFlowData.entities,
            d => { d.fx = null; d.fy = null; });
    }

    const loadDetail = () => {
        vm.visibility.loadingFlows = true;

        const flowPromise = serviceBroker
            .loadViewData(
                CORE_API.LogicalFlowStore.findBySelector,
                [ vm.selector ])
            .then(r => vm.flows = r.data);

        const decoratorPromise = serviceBroker
            .loadViewData(
                CORE_API.LogicalFlowDecoratorStore.findBySelector,
                [ vm.selector ])
            .then(r => {
                vm.decorators = r.data;
                vm.usedDataTypes = getDataTypeIds(vm.allDataTypes, vm.decorators);
            });

        const appsPromise = serviceBroker
            .loadViewData(
                CORE_API.ApplicationStore.findBySelector,
                [ vm.selector ])
            .then(r => vm.applications = r.data);

        return $q
            .all([flowPromise, decoratorPromise, appsPromise])
            .then(() => {
                vm.filterChanged();
                vm.visibility.loadingFlows = false;
            });
    };

    vm.filterChanged = (filterOptions = vm.filterOptions) => {

        const dataTypes = buildHierarchies(vm.allDataTypes, true);
        const node = findNode(dataTypes, Number(filterOptions.type));

        const children = (node)
            ? _.map(flattenChildren(node),
                    d => { return {
                        type: d.id,
                        scope: filterOptions.scope
                    }})
            : [];

        vm.filterOptions = _.concat(filterOptions, children);

        if (! (vm.flows && vm.decorators)) return;

        vm.filteredFlowData = calculateFlowData(
            vm.flows,
            vm.applications,
            vm.decorators,
            vm.filterOptions,
            vm.isolatedNode);

        vm.graphTweakers = prepareGraphTweakers(
            logicalFlowUtilityService,
            vm.applications,
            vm.filteredFlowData.decorators,
            node => $scope.$applyAsync(() => vm.selectedNode = node));
    };

    vm.isolate = (node) => {
        unpinAll();
        vm.isolatedNode = node;
        vm.filterChanged();
    };

    vm.dismissSelectedNode = () => {
        unpinAll();
        vm.isolatedNode = null;
        vm.selectedNode = null;
        vm.filterChanged();
    };

    vm.refocusNode = node => {
        vm.selectedNode = node;
        vm.isolate(node);
    };

    vm.$onChanges = (c) => {
        if (vm.parentEntityRef) {
            vm.selector = mkApplicationSelectionOptions(
                vm.parentEntityRef,
                undefined,
                [entityLifecycleStatus.ACTIVE.key],
                vm.filters);
            loadDetail();
        }
    };

    vm.$onInit = () => {
        serviceBroker
            .loadAppData(CORE_API.DataTypeStore.findAll)
            .then(r => vm.allDataTypes = r.data);
    };

}

controller.$inject = [
    "$scope",
    "$q",
    "ServiceBroker",
    "LogicalFlowUtilityService"
];

const component = {
    controller,
    bindings,
    template
};

export default {
    component,
    id: "waltzLogicalFlowsBoingyGraph"
};
<|endoftext|>


<commit_before>Ext.define('devilry_subjectadmin.view.createnewassignment.Form', {
    extend: 'Ext.form.Panel',
    alias: 'widget.createnewassignmentform',
    requires: [
        'Ext.form.field.ComboBox',
        'Ext.form.field.Text',
        'Ext.form.field.Hidden',
        'Ext.toolbar.Toolbar',
        'devilry_extjsextras.form.DateTimeField',
        'devilry_extjsextras.CreateButton',
        'devilry_extjsextras.AlertMessageList',
        'devilry_subjectadmin.utils.UrlLookup',
        'devilry_subjectadmin.utils.BaseNodeHelp',
        'devilry_subjectadmin.view.createnewassignment.SelectSingleAssignment'
    ],

    /**
     * @cfg period_id
     */

    initComponent: function() {
        var cssclasses = 'devilry_subjectadmin_createnewassignmentform';
        if(this.cls) {
            cssclasses += ' ' + this.cls;
        }
        this.cls = cssclasses;
        var sideheading_attrs = 'class="muted" style="margin:0; padding:0; font-weight:normal; font-size:18px;"';
        var sideheading_width = 170;

        Ext.apply(this, {
            border: false,
            layout: 'anchor',
            fieldDefaults: {
                labelAlign: 'top',
                labelStyle: 'font-weight: bold'
            },
            items: [{
                xtype: 'alertmessagelist'
            }, {
                xtype: 'container',
                layout: 'card',
                itemId: 'cardPanel',
                items: [{
                    xtype: 'panel',
                    itemId: 'pageOne',
                    cls: 'page1',
                    bodyPadding: 20,
                    items: [{

                        // Long name
                        xtype: 'container',
                        layout: 'column',
                        items: [{
                            columnWidth: 1,
                            name: "long_name",
                            fieldLabel: gettext('Long name'),
                            xtype: 'textfield',
                            cls: 'hugefield',
                            emptyText: pgettext('createnewassignment', 'Example: Obligatory assignment one'),
                            allowBlank: false,
                            //fieldStyle: 'height:auto; font-size:20px; line-height:normal;',
                            padding: '0 20 0 0'
                        }, {
                            name: "short_name",
                            width: 300,
                            fieldLabel: gettext('Short name'),
                            xtype: 'textfield',
                            allowBlank: false,
                            emptyText: pgettext('createnewassignment', 'Example: oblig-1')
                        }]
                    }, {
                        xtype: 'box',
                        cls: 'bootstrap',
                        margin: '0 0 0 0',
                        html: [
                            '
',
                                devilry_subjectadmin.utils.BaseNodeHelp.getShortAndLongNameHelp(),
                            '
'
                        ].join('')

                    }, {
                        xtype: 'container',
                        margin: '20 0 0 0',
                        layout: 'column',
                        items: [{
                            // How do students add deliveries
                            xtype: 'container',
                            columnWidth: 1,
                            padding: '0 40 20 0',
                            items: [{
                                xtype: 'radiogroup',
                                fieldLabel: gettext('How do students add deliveries?'),
                                vertical: true,
                                itemId: 'deliveryTypesRadioGroup',
                                cls: 'delivery_types-radiogroup',
                                columns: 1,
                                items: [{
                                    boxLabel: gettext('Using Devilry'),
                                    name: 'delivery_types',
                                    cls: 'deliveryTypesElectronic',
                                    inputValue: 0,
                                    checked: true
                                }, {
                                    boxLabel: gettext('Not using Devilry'),
                                    name: 'delivery_types',
                                    cls: 'deliveryTypesNonElectronic',
                                    inputValue: 1
                                }]
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 3',
                                html: [
                                    '
',
                                        gettext('If you only use Devilry to give feedback, and students deliver paper copies or through an alternative channel (oral presentation, email, ...), choose Not using Devilry.'),
                                    '
'
                                ].join('')
                            }]

                        }, {
                            // First deadline
                            xtype: 'container',
                            //columnWidth: 0.5,
                            width: 300,
                            items: [{
                                xtype: 'devilry_extjsextras-datetimefield',
                                cls: 'firstDeadlineField',
                                itemId: 'firstDeadlineField',
                                name: 'first_deadline',
                                allowBlank: false,
                                width: 300,
                                fieldLabel: gettext('Submission date')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                itemId: 'firstDeadlineHelp',
                                margin: '0 0 0 0',
                                html: [
                                    '
',
                                        gettext('Students must submit their delivery before this time.'),
                                    '
'
                                ].join('')
                            }]
                        }]

                    }, {
                        xtype: 'panel',
                        cls: 'devilry_discussionview_container',

                        items: [{
                            xtype: 'panel',
                            id: 'advancedOptionsPanel',
                            title: [
                                '
',
                                    '',
                                        gettext('Advanced options'),
                                    '',
                                    ' (',
                                        gettext('click to expand'),
                                    ')',
                                '
'
                            ].join(''),
                            collapsible: true,
                            collapsed: true,
                            animCollapse: false,
                            titleCollapse: true,
                            bodyPadding: 20,
                            defaults: {
                                margin: '20 0 0 0'
                            },
                            items: [{
                                // Anonymous?
                                xtype: 'checkboxfield',
                                margin: '0 0 0 0',
                                name: 'anonymous',
                                cls: 'anonymousField',
                                labelAlign: 'left',
                                boxLabel: gettext('Anonymous?')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 0',
                                html: [
                                    '
',
                                        gettext('For exams, this should normally be checked. If an assignment is anonymous, examiners see candidate-id instead of any personal information about the students.'),
                                    '
'
                                ].join('')

                                // Publishing time
                            }, {
                                xtype: 'devilry_extjsextras-datetimefield',
                                width: 300,
                                fieldLabel: gettext('Publishing time'),
                                name: "publishing_time",
                                cls: 'publishingTimeField'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 0',
                                itemId: 'publishingTimeHelp',
                                html: [
                                    '
',
                                        gettext('Choose a time when students will be able to start adding deliveries on the assignment. The default is now. Note that students must be registered on the assignment as well before they can add any deliveries.'),
                                    '
'
                                ].join('')
                            }]
                        }]
                    }],

                    fbar: [{
                        xtype: 'button',
                        itemId: 'nextButton',
                        cls: 'createnewassignmentform_nextbutton',
                        text: gettext('Next'),
                        scale: 'large',
                        formBind: true, //only enabled once the form is valid
                        disabled: true
                    }]
                }, {
                    xtype: 'panel',
                    itemId: 'pageTwo',
                    cls: 'page2',
                    bodyPadding: 20,
                    items: [{

                        // Setup students
                        xtype: 'container',
                        itemId: 'setupStudentsContainer',
                        layout: 'column',
                        items: [{
                            margin: 0,
                            xtype: 'box',
                            width: sideheading_width,
                            cls: 'bootstrap',
                            tpl: [
                                '
',
                                    gettext('Students?'),
                                '
'
                            ],
                            data: {
                                sideheading_attrs: sideheading_attrs
                            }
                        }, {
                            xtype: 'radiogroup',
                            columnWidth: 1,
                            itemId: 'studentsSetupRadiogroup',
                            vertical: true,
                            columns: 1,
                            margin: 0,
                            items: [{
                                boxLabel: interpolate(gettext('Add all students registered on the %(period_term)s.'), {
                                    period_term: gettext('period')
                                }, true),
                                checked: true,
                                margin: 0,
                                name: 'setupstudents_mode',
                                itemId: 'setupStudentsAllRelatedRadio',
                                cls: 'extrastronglabel setupStudentsAllRelatedRadio',
                                inputValue: 'allrelated'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                tpl: [
                                    '
',
                                        gettext('You may want to view and edit students.'),
                                    '
'
                                ],
                                data: {
                                    period_term: gettext('period'),
                                    relatedstudents_link: Ext.String.format('href="{0}" target="_blank"',
                                        devilry_subjectadmin.utils.UrlLookup.manageRelatedStudents(this.period_id))
                                }

                            }, {
                                boxLabel: gettext('Copy from another assignment.'),
                                margin: '10 0 0 0',
                                name: 'setupstudents_mode',
                                itemId: 'setupStudentsCopyFromAssignmentRadio',
                                cls: 'extrastronglabel setupStudentsCopyFromAssignmentRadio',
                                hidden: true,
                                inputValue: 'copyfromassignment'
                            }, {
                                xtype: 'container',
                                itemId: 'selectAssignmentToCopyStudentsFrom',
                                layout: 'column',
                                hidden: true,
                                margin: '5 0 0 17',
                                items: [{
                                    xtype: 'selectsingleassignment',
                                    name: 'copyfromassignment_id',
                                    cls: 'copyFromAssignmentIdField',
                                    width: 300
                                }, {
                                    xtype: 'checkboxfield',
                                    name: 'only_copy_passing_groups',
                                    cls: 'onlyCopyPassingGroupsField',
                                    columnWidth: 1,
                                    margin: '0 0 0 10',
                                    checked: false,
                                    boxLabel: gettext('Only copy groups with passing grade?')
                                }]

                            }, {
                                boxLabel: gettext('Do not add students at this time.'),
                                margin: '10 0 0 0',
                                name: 'setupstudents_mode',
                                cls: 'extrastronglabel setupStudentsDoNotSetupRadio',
                                inputValue: 'do_not_setup'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                html: [
                                    '
',
                                        gettext('If you choose not to add students at this time, you will have to add them manually to the assignment later. If you plan for students to work in project groups, you should still add them to the assignment now. You can organize them in project groups at any time, even after they have made deliveries.'),
                                    '
'
                                ].join('')
                            }]
                        }]

                        // Autosetup examiners
                    }, {
                        xtype: 'container',
                        itemId: 'setupExaminersContainer',
                        cls: 'setupExaminersContainer',
                        margin: '10 0 0 0',
                        layout: 'column',
                        items: [{
                            margin: 0,
                            xtype: 'box',
                            cls: 'bootstrap',
                            width: sideheading_width,
                            padding: '0 30 0 0',
                            tpl: [
                                '
',
                                    gettext('Examiners?'),
                                '
',
                                '
',
                                    '',
                                        gettext('The people that provide feedback to students'),
                                    '',
                                '
'
                            ],
                            data: {
                                sideheading_attrs: sideheading_attrs
                            }
                        }, {
                            xtype: 'radiogroup',
                            columnWidth: 1,
                            itemId: 'examinersSetupRadiogroup',
                            vertical: true,
                            columns: 1,
                            margin: 0,
                            items: [{
                                margin: '0 0 0 0',
                                name: 'setupexaminers_mode',
                                checked: true,
                                cls: 'extrastronglabel setupExaminersByTagsRadio',
                                inputValue: 'bytags',
                                itemId: 'setupExaminersByTagsRadio',
                                boxLabel: gettext('Setup examiners by tags.')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                itemId: 'setupExaminersByTagsHelp',
                                tpl: [
                                    '
',
                                        gettext('Add examiners to students that have at least one tag in common with the examiner.'),
                                        ' ',
                                        gettext('E.g.: If you tag two examiners and 20 students with group1, those two examiners will be set up to correct those 20 students.'),
                                        ' ',
                                        gettext('You may want to view and edit tags for students and examiners.'),
                                    '
'
                                ],
                                data: {
                                    relatedstudents_link: Ext.String.format('href="{0}" target="_blank"',
                                        devilry_subjectadmin.utils.UrlLookup.manageRelatedStudents(this.period_id)),
                                        relatedexaminers_link: Ext.String.format('href="{0}" target="_blank"',
                                            devilry_subjectadmin.utils.UrlLookup.manageRelatedExaminers(this.period_id))
                                }

                            }, {
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                hidden: true,
                                itemId: 'setupExaminersCopyFromAssignmentRadio',
                                cls: 'extrastronglabel setupExaminersCopyFromAssignmentRadio',
                                inputValue: 'copyfromassignment',
                                boxLabel: 'X' // Set by the controller

                            }, {
                                boxLabel: gettext('Make me examiner for all students.'),
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                cls: 'extrastronglabel setupExaminersMakeAuthuserExaminer',
                                inputValue: 'make_authenticated_user_examiner'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                html: [
                                    '
',
                                        gettext('I.E.: you plan to provide feedback to all students yourself.'),
                                    '
'
                                ].join('')

                            }, {
                                boxLabel: gettext('Do not setup examiners at this time.'),
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                cls: 'extrastronglabel setupExaminersDoNotSetupRadio',
                                inputValue: 'do_not_setup'
                            }]
                        }]
                    }],
                    fbar: [{
                        xtype: 'button',
                        itemId: 'backButton',
                        text: gettext('Back'),
                        scale: 'medium'
                    }, '->', {
                        xtype: 'createbutton',
                        minWidth: 200,
                        text: gettext('Create assignment'),
                        itemId: 'createButton',
                        scale: 'large',
                        formBind: true, //only enabled once the form is valid
                        disabled: true
                    }]
                }]
            }]
        });
        this.callParent(arguments);
    }
});
<commit_msg>devilry_subjectadmin...createnewassignment.Form: Space over Examiners.<commit_after>Ext.define('devilry_subjectadmin.view.createnewassignment.Form', {
    extend: 'Ext.form.Panel',
    alias: 'widget.createnewassignmentform',
    requires: [
        'Ext.form.field.ComboBox',
        'Ext.form.field.Text',
        'Ext.form.field.Hidden',
        'Ext.toolbar.Toolbar',
        'devilry_extjsextras.form.DateTimeField',
        'devilry_extjsextras.CreateButton',
        'devilry_extjsextras.AlertMessageList',
        'devilry_subjectadmin.utils.UrlLookup',
        'devilry_subjectadmin.utils.BaseNodeHelp',
        'devilry_subjectadmin.view.createnewassignment.SelectSingleAssignment'
    ],

    /**
     * @cfg period_id
     */

    initComponent: function() {
        var cssclasses = 'devilry_subjectadmin_createnewassignmentform';
        if(this.cls) {
            cssclasses += ' ' + this.cls;
        }
        this.cls = cssclasses;
        var sideheading_attrs = 'class="muted" style="margin:0; padding:0; font-weight:normal; font-size:18px;"';
        var sideheading_width = 170;

        Ext.apply(this, {
            border: false,
            layout: 'anchor',
            fieldDefaults: {
                labelAlign: 'top',
                labelStyle: 'font-weight: bold'
            },
            items: [{
                xtype: 'alertmessagelist'
            }, {
                xtype: 'container',
                layout: 'card',
                itemId: 'cardPanel',
                items: [{
                    xtype: 'panel',
                    itemId: 'pageOne',
                    cls: 'page1',
                    bodyPadding: 20,
                    items: [{

                        // Long name
                        xtype: 'container',
                        layout: 'column',
                        items: [{
                            columnWidth: 1,
                            name: "long_name",
                            fieldLabel: gettext('Long name'),
                            xtype: 'textfield',
                            cls: 'hugefield',
                            emptyText: pgettext('createnewassignment', 'Example: Obligatory assignment one'),
                            allowBlank: false,
                            //fieldStyle: 'height:auto; font-size:20px; line-height:normal;',
                            padding: '0 20 0 0'
                        }, {
                            name: "short_name",
                            width: 300,
                            fieldLabel: gettext('Short name'),
                            xtype: 'textfield',
                            allowBlank: false,
                            emptyText: pgettext('createnewassignment', 'Example: oblig-1')
                        }]
                    }, {
                        xtype: 'box',
                        cls: 'bootstrap',
                        margin: '0 0 0 0',
                        html: [
                            '
',
                                devilry_subjectadmin.utils.BaseNodeHelp.getShortAndLongNameHelp(),
                            '
'
                        ].join('')

                    }, {
                        xtype: 'container',
                        margin: '20 0 0 0',
                        layout: 'column',
                        items: [{
                            // How do students add deliveries
                            xtype: 'container',
                            columnWidth: 1,
                            padding: '0 40 20 0',
                            items: [{
                                xtype: 'radiogroup',
                                fieldLabel: gettext('How do students add deliveries?'),
                                vertical: true,
                                itemId: 'deliveryTypesRadioGroup',
                                cls: 'delivery_types-radiogroup',
                                columns: 1,
                                items: [{
                                    boxLabel: gettext('Using Devilry'),
                                    name: 'delivery_types',
                                    cls: 'deliveryTypesElectronic',
                                    inputValue: 0,
                                    checked: true
                                }, {
                                    boxLabel: gettext('Not using Devilry'),
                                    name: 'delivery_types',
                                    cls: 'deliveryTypesNonElectronic',
                                    inputValue: 1
                                }]
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 3',
                                html: [
                                    '
',
                                        gettext('If you only use Devilry to give feedback, and students deliver paper copies or through an alternative channel (oral presentation, email, ...), choose Not using Devilry.'),
                                    '
'
                                ].join('')
                            }]

                        }, {
                            // First deadline
                            xtype: 'container',
                            //columnWidth: 0.5,
                            width: 300,
                            items: [{
                                xtype: 'devilry_extjsextras-datetimefield',
                                cls: 'firstDeadlineField',
                                itemId: 'firstDeadlineField',
                                name: 'first_deadline',
                                allowBlank: false,
                                width: 300,
                                fieldLabel: gettext('Submission date')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                itemId: 'firstDeadlineHelp',
                                margin: '0 0 0 0',
                                html: [
                                    '
',
                                        gettext('Students must submit their delivery before this time.'),
                                    '
'
                                ].join('')
                            }]
                        }]

                    }, {
                        xtype: 'panel',
                        cls: 'devilry_discussionview_container',

                        items: [{
                            xtype: 'panel',
                            id: 'advancedOptionsPanel',
                            title: [
                                '
',
                                    '',
                                        gettext('Advanced options'),
                                    '',
                                    ' (',
                                        gettext('click to expand'),
                                    ')',
                                '
'
                            ].join(''),
                            collapsible: true,
                            collapsed: true,
                            animCollapse: false,
                            titleCollapse: true,
                            bodyPadding: 20,
                            defaults: {
                                margin: '20 0 0 0'
                            },
                            items: [{
                                // Anonymous?
                                xtype: 'checkboxfield',
                                margin: '0 0 0 0',
                                name: 'anonymous',
                                cls: 'anonymousField',
                                labelAlign: 'left',
                                boxLabel: gettext('Anonymous?')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 0',
                                html: [
                                    '
',
                                        gettext('For exams, this should normally be checked. If an assignment is anonymous, examiners see candidate-id instead of any personal information about the students.'),
                                    '
'
                                ].join('')

                                // Publishing time
                            }, {
                                xtype: 'devilry_extjsextras-datetimefield',
                                width: 300,
                                fieldLabel: gettext('Publishing time'),
                                name: "publishing_time",
                                cls: 'publishingTimeField'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                margin: '0 0 0 0',
                                itemId: 'publishingTimeHelp',
                                html: [
                                    '
',
                                        gettext('Choose a time when students will be able to start adding deliveries on the assignment. The default is now. Note that students must be registered on the assignment as well before they can add any deliveries.'),
                                    '
'
                                ].join('')
                            }]
                        }]
                    }],

                    fbar: [{
                        xtype: 'button',
                        itemId: 'nextButton',
                        cls: 'createnewassignmentform_nextbutton',
                        text: gettext('Next'),
                        scale: 'large',
                        formBind: true, //only enabled once the form is valid
                        disabled: true
                    }]
                }, {
                    xtype: 'panel',
                    itemId: 'pageTwo',
                    cls: 'page2',
                    bodyPadding: 20,
                    items: [{

                        // Setup students
                        xtype: 'container',
                        itemId: 'setupStudentsContainer',
                        layout: 'column',
                        items: [{
                            margin: 0,
                            xtype: 'box',
                            width: sideheading_width,
                            cls: 'bootstrap',
                            tpl: [
                                '
',
                                    gettext('Students?'),
                                '
'
                            ],
                            data: {
                                sideheading_attrs: sideheading_attrs
                            }
                        }, {
                            xtype: 'radiogroup',
                            columnWidth: 1,
                            itemId: 'studentsSetupRadiogroup',
                            vertical: true,
                            columns: 1,
                            margin: 0,
                            items: [{
                                boxLabel: interpolate(gettext('Add all students registered on the %(period_term)s.'), {
                                    period_term: gettext('period')
                                }, true),
                                checked: true,
                                margin: 0,
                                name: 'setupstudents_mode',
                                itemId: 'setupStudentsAllRelatedRadio',
                                cls: 'extrastronglabel setupStudentsAllRelatedRadio',
                                inputValue: 'allrelated'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                tpl: [
                                    '
',
                                        gettext('You may want to view and edit students.'),
                                    '
'
                                ],
                                data: {
                                    period_term: gettext('period'),
                                    relatedstudents_link: Ext.String.format('href="{0}" target="_blank"',
                                        devilry_subjectadmin.utils.UrlLookup.manageRelatedStudents(this.period_id))
                                }

                            }, {
                                boxLabel: gettext('Copy from another assignment.'),
                                margin: '10 0 0 0',
                                name: 'setupstudents_mode',
                                itemId: 'setupStudentsCopyFromAssignmentRadio',
                                cls: 'extrastronglabel setupStudentsCopyFromAssignmentRadio',
                                hidden: true,
                                inputValue: 'copyfromassignment'
                            }, {
                                xtype: 'container',
                                itemId: 'selectAssignmentToCopyStudentsFrom',
                                layout: 'column',
                                hidden: true,
                                margin: '5 0 0 17',
                                items: [{
                                    xtype: 'selectsingleassignment',
                                    name: 'copyfromassignment_id',
                                    cls: 'copyFromAssignmentIdField',
                                    width: 300
                                }, {
                                    xtype: 'checkboxfield',
                                    name: 'only_copy_passing_groups',
                                    cls: 'onlyCopyPassingGroupsField',
                                    columnWidth: 1,
                                    margin: '0 0 0 10',
                                    checked: false,
                                    boxLabel: gettext('Only copy groups with passing grade?')
                                }]

                            }, {
                                boxLabel: gettext('Do not add students at this time.'),
                                margin: '10 0 0 0',
                                name: 'setupstudents_mode',
                                cls: 'extrastronglabel setupStudentsDoNotSetupRadio',
                                inputValue: 'do_not_setup'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                html: [
                                    '
',
                                        gettext('If you choose not to add students at this time, you will have to add them manually to the assignment later. If you plan for students to work in project groups, you should still add them to the assignment now. You can organize them in project groups at any time, even after they have made deliveries.'),
                                    '
'
                                ].join('')
                            }]
                        }]

                        // Autosetup examiners
                    }, {
                        xtype: 'container',
                        itemId: 'setupExaminersContainer',
                        cls: 'setupExaminersContainer',
                        margin: '30 0 0 0',
                        layout: 'column',
                        items: [{
                            margin: 0,
                            xtype: 'box',
                            cls: 'bootstrap',
                            width: sideheading_width,
                            padding: '0 30 0 0',
                            tpl: [
                                '
',
                                    gettext('Examiners?'),
                                '
',
                                '
',
                                    '',
                                        gettext('The people that provide feedback to students'),
                                    '',
                                '
'
                            ],
                            data: {
                                sideheading_attrs: sideheading_attrs
                            }
                        }, {
                            xtype: 'radiogroup',
                            columnWidth: 1,
                            itemId: 'examinersSetupRadiogroup',
                            vertical: true,
                            columns: 1,
                            margin: 0,
                            items: [{
                                margin: '0 0 0 0',
                                name: 'setupexaminers_mode',
                                checked: true,
                                cls: 'extrastronglabel setupExaminersByTagsRadio',
                                inputValue: 'bytags',
                                itemId: 'setupExaminersByTagsRadio',
                                boxLabel: gettext('Setup examiners by tags.')
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                itemId: 'setupExaminersByTagsHelp',
                                tpl: [
                                    '
',
                                        gettext('Add examiners to students that have at least one tag in common with the examiner.'),
                                        ' ',
                                        gettext('E.g.: If you tag two examiners and 20 students with group1, those two examiners will be set up to correct those 20 students.'),
                                        ' ',
                                        gettext('You may want to view and edit tags for students and examiners.'),
                                    '
'
                                ],
                                data: {
                                    relatedstudents_link: Ext.String.format('href="{0}" target="_blank"',
                                        devilry_subjectadmin.utils.UrlLookup.manageRelatedStudents(this.period_id)),
                                        relatedexaminers_link: Ext.String.format('href="{0}" target="_blank"',
                                            devilry_subjectadmin.utils.UrlLookup.manageRelatedExaminers(this.period_id))
                                }

                            }, {
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                hidden: true,
                                itemId: 'setupExaminersCopyFromAssignmentRadio',
                                cls: 'extrastronglabel setupExaminersCopyFromAssignmentRadio',
                                inputValue: 'copyfromassignment',
                                boxLabel: 'X' // Set by the controller

                            }, {
                                boxLabel: gettext('Make me examiner for all students.'),
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                cls: 'extrastronglabel setupExaminersMakeAuthuserExaminer',
                                inputValue: 'make_authenticated_user_examiner'
                            }, {
                                xtype: 'box',
                                cls: 'bootstrap',
                                html: [
                                    '
',
                                        gettext('I.E.: you plan to provide feedback to all students yourself.'),
                                    '
'
                                ].join('')

                            }, {
                                boxLabel: gettext('Do not setup examiners at this time.'),
                                margin: '10 0 0 0',
                                name: 'setupexaminers_mode',
                                cls: 'extrastronglabel setupExaminersDoNotSetupRadio',
                                inputValue: 'do_not_setup'
                            }]
                        }]
                    }],
                    fbar: [{
                        xtype: 'button',
                        itemId: 'backButton',
                        text: gettext('Back'),
                        scale: 'medium'
                    }, '->', {
                        xtype: 'createbutton',
                        minWidth: 200,
                        text: gettext('Create assignment'),
                        itemId: 'createButton',
                        scale: 'large',
                        formBind: true, //only enabled once the form is valid
                        disabled: true
                    }]
                }]
            }]
        });
        this.callParent(arguments);
    }
});
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';

import Icon from 'components/icon';
import Slider from 'components/slider';
import Carousel from 'components/carousel';
import Dropdown from 'components/dropdown';
import Datepicker from 'components/datepicker';
import NoContent from 'components/no-content';
import RecentImageryThumbnail from 'pages/map/recent-imagery/components/recent-imagery-thumbnail';

import WEEKS from 'pages/map/data/weeks.json';
import draggerIcon from 'assets/icons/dragger.svg';
import closeIcon from 'assets/icons/close.svg';
import RecentImageryDrag from './recent-imagery-settings-drag';
import './recent-imagery-settings-styles.scss';

class RecentImagerySettings extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      thumbnailsDescription: null
    };
  }

  render() {
    const {
      selectedTile,
      tiles,
      settings: {
        styles,
        thumbsToShow,
        selectedTileIndex,
        date,
        weeks,
        clouds
      },
      isDragging,
      connectDragSource,
      setRecentImagerySettings,
      setRecentImageryShowSettings
    } = this.props;
    let opacity = 1;

    if (isDragging) {
      opacity = 0;
    }

    return connectDragSource(

        <Icon icon={draggerIcon} className="dragger-icon" />
        <button
          className="close-btn"
          onClick={() => setRecentImageryShowSettings(false)}
        >
          <Icon icon={closeIcon} className="close-icon" />
        </button>

          RECENT HI-RES SATELLITE IMAGERY

            ACQUISITION DATE

            <Dropdown
              theme="theme-dropdown-button"
              value={weeks}
              options={WEEKS}
              onChange={option =>
                setRecentImagerySettings({ weeks: option.value })
              }
            />

              before

            <Datepicker
              date={date ? moment(date) : moment()}
              handleOnDateChange={d =>
                setRecentImagerySettings({ date: d.format('YYYY-MM-DD') })
              }
              settings={{
                displayFormat: 'D MMM YYYY',
                numberOfMonths: 1,
                isOutsideRange: d => d.isAfter(moment()),
                hideKeyboardShortcutsPanel: true,
                noBorder: true
              }}
            />

            MAXIMUM CLOUD COVER PERCENTAGE

          <Slider
            className="theme-slider-green"
            settings={{
              defaultValue: clouds,
              marks: {
                0: '0%',
                25: '25%',
                50: '50%',
                75: '75%',
                100: '100%'
              },
              marksOnTop: true,
              step: 5,
              dots: true,
              tipFormatter: value => `${value}%`
            }}
            handleOnSliderChange={d => setRecentImagerySettings({ clouds: d })}
          />

          {tiles.length >= 2 && (

                {this.state.thumbnailsDescription || selectedTile.description}

              <Carousel
                settings={{
                  slidesToShow: thumbsToShow,
                  infinite: tiles.length > thumbsToShow,
                  centerMode: tiles.length > thumbsToShow,
                  centerPadding: '20px',
                  draggable: false,
                  dots: false,
                  arrows: tiles.length > thumbsToShow,
                  responsive: [
                    {
                      breakpoint: 620,
                      settings: {
                        slidesToShow: thumbsToShow - 2
                      }
                    }
                  ]
                }}
              >
                {tiles.map((tile, i) => (
                  <div key={`recent-imagery-thumb-${tile.id}`}>
                    <RecentImageryThumbnail
                      id={i}
                      tile={tile}
                      selected={selectedTileIndex === i}
                      handleClick={() => {
                        setRecentImagerySettings({ selectedTileIndex: i });
                      }}
                      handleMouseEnter={() => {
                        this.setState({
                          thumbnailsDescription: tile.description
                        });
                      }}
                      handleMouseLeave={() => {
                        this.setState({ thumbnailsDescription: null });
                      }}
                    />

                ))}
              </Carousel>

          )}
          {tiles.length < 2 && (
            <NoContent
              className="c-recent-imagery-settings__empty-thumbnails"
              message="We can't find additional images for the selection"
            />
          )}

    );
  }
}

RecentImagerySettings.propTypes = {
  selectedTile: PropTypes.object.isRequired,
  tiles: PropTypes.array.isRequired,
  settings: PropTypes.object.isRequired,
  isDragging: PropTypes.bool.isRequired,
  connectDragSource: PropTypes.func.isRequired,
  setRecentImagerySettings: PropTypes.func.isRequired,
  setRecentImageryShowSettings: PropTypes.func.isRequired
};

export default RecentImageryDrag(RecentImagerySettings);
<commit_msg>adding readOnly prop on the datepicker<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';

import Icon from 'components/icon';
import Slider from 'components/slider';
import Carousel from 'components/carousel';
import Dropdown from 'components/dropdown';
import Datepicker from 'components/datepicker';
import NoContent from 'components/no-content';
import RecentImageryThumbnail from 'pages/map/recent-imagery/components/recent-imagery-thumbnail';

import WEEKS from 'pages/map/data/weeks.json';
import draggerIcon from 'assets/icons/dragger.svg';
import closeIcon from 'assets/icons/close.svg';
import RecentImageryDrag from './recent-imagery-settings-drag';
import './recent-imagery-settings-styles.scss';

class RecentImagerySettings extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      thumbnailsDescription: null
    };
  }

  render() {
    const {
      selectedTile,
      tiles,
      settings: {
        styles,
        thumbsToShow,
        selectedTileIndex,
        date,
        weeks,
        clouds
      },
      isDragging,
      connectDragSource,
      setRecentImagerySettings,
      setRecentImageryShowSettings
    } = this.props;
    let opacity = 1;

    if (isDragging) {
      opacity = 0;
    }

    return connectDragSource(

        <Icon icon={draggerIcon} className="dragger-icon" />
        <button
          className="close-btn"
          onClick={() => setRecentImageryShowSettings(false)}
        >
          <Icon icon={closeIcon} className="close-icon" />
        </button>

          RECENT HI-RES SATELLITE IMAGERY

            ACQUISITION DATE

            <Dropdown
              theme="theme-dropdown-button"
              value={weeks}
              options={WEEKS}
              onChange={option =>
                setRecentImagerySettings({ weeks: option.value })
              }
            />

              before

            <Datepicker
              date={date ? moment(date) : moment()}
              handleOnDateChange={d =>
                setRecentImagerySettings({ date: d.format('YYYY-MM-DD') })
              }
              settings={{
                displayFormat: 'D MMM YYYY',
                numberOfMonths: 1,
                isOutsideRange: d => d.isAfter(moment()),
                hideKeyboardShortcutsPanel: true,
                noBorder: true,
                readOnly: true
              }}
            />

            MAXIMUM CLOUD COVER PERCENTAGE

          <Slider
            className="theme-slider-green"
            settings={{
              defaultValue: clouds,
              marks: {
                0: '0%',
                25: '25%',
                50: '50%',
                75: '75%',
                100: '100%'
              },
              marksOnTop: true,
              step: 5,
              dots: true,
              tipFormatter: value => `${value}%`
            }}
            handleOnSliderChange={d => setRecentImagerySettings({ clouds: d })}
          />

          {tiles.length >= 2 && (

                {this.state.thumbnailsDescription || selectedTile.description}

              <Carousel
                settings={{
                  slidesToShow: thumbsToShow,
                  infinite: tiles.length > thumbsToShow,
                  centerMode: tiles.length > thumbsToShow,
                  centerPadding: '20px',
                  draggable: false,
                  dots: false,
                  arrows: tiles.length > thumbsToShow,
                  responsive: [
                    {
                      breakpoint: 620,
                      settings: {
                        slidesToShow: thumbsToShow - 2
                      }
                    }
                  ]
                }}
              >
                {tiles.map((tile, i) => (
                  <div key={`recent-imagery-thumb-${tile.id}`}>
                    <RecentImageryThumbnail
                      id={i}
                      tile={tile}
                      selected={selectedTileIndex === i}
                      handleClick={() => {
                        setRecentImagerySettings({ selectedTileIndex: i });
                      }}
                      handleMouseEnter={() => {
                        this.setState({
                          thumbnailsDescription: tile.description
                        });
                      }}
                      handleMouseLeave={() => {
                        this.setState({ thumbnailsDescription: null });
                      }}
                    />

                ))}
              </Carousel>

          )}
          {tiles.length < 2 && (
            <NoContent
              className="c-recent-imagery-settings__empty-thumbnails"
              message="We can't find additional images for the selection"
            />
          )}

    );
  }
}

RecentImagerySettings.propTypes = {
  selectedTile: PropTypes.object.isRequired,
  tiles: PropTypes.array.isRequired,
  settings: PropTypes.object.isRequired,
  isDragging: PropTypes.bool.isRequired,
  connectDragSource: PropTypes.func.isRequired,
  setRecentImagerySettings: PropTypes.func.isRequired,
  setRecentImageryShowSettings: PropTypes.func.isRequired
};

export default RecentImageryDrag(RecentImagerySettings);
<|endoftext|>


<commit_before>/*
 * This file is part of Geomajas, a component framework for building
 * rich Internet applications (RIA) with sophisticated capabilities for the
 * display, analysis and management of geographic information.
 * It is a building block that allows developers to add maps
 * and other geographic data capabilities to their web applications.
 *
 * Copyright 2008-2010 Geosparc, http://www.geosparc.com, Belgium
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

dojo.provide("geomajas.gfx.painter.FeaturePainter");
dojo.require("geomajas._base");
dojo.require("geomajas.gfx.Painter");

dojo.declare("FeaturePainter", Painter, {

	/**
	 * @class Painter implementation for features. This painter always paints
	 * in worldspace!
	 * @author Jan De Moerloose & Pieter De Graef
	 *
	 * @constructor
	 * @extends Painter
	 */
	constructor : function (mapWidget, mapView) {
		this.mapWidget = mapWidget;
		this.transform = new WorldViewTransformation(mapView);
	},

	/**
	 * The actual painting function. Currently paints selected features only.
	 * @param feature A Paintable object.
	 * @param graphics A GraphicsContext object, responsible for actual drawing.
	 */
	paint : function (feature, graphics) {
		var geometry = feature.getGeometry();

		// selected features only
		if(!feature.isSelected()){
			return;
		}

		var id = feature.getSelectionId();
		// no updates, delete first to update !!! => PDG: why is this??? speed perhaps...
//		if(graphics.getElementById(id)){
//			return;
//		}

		log.info("FeaturePainter : painting feature "+feature.getId());
		// Style is shared reference, so we have to clone it before we can change it !
		var style = feature.getStyle().clone();

		if(geometry.declaredClass == geomajas.GeometryTypes.POLYGON){
			style.copyFrom(this.mapWidget.getPolygonSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.LINESTRING){
			style.copyFrom(this.mapWidget.getLineSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.POINT){
			style.copyFrom(this.mapWidget.getPointSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.MULTIPOLYGON){
			style.copyFrom(this.mapWidget.getPolygonSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.MULTILINESTRING){
			style.copyFrom(this.mapWidget.getLineSelectStyle());
		}

		var options = {
			id : id,
			style: style,
			worldspace : true
		};

		//if(feature.isClipped() && feature.getPath()){
			log.info("FeaturePainter : painting with (clipped) path");
			options.path = feature.getPath();
			if(geometry.declaredClass == geomajas.GeometryTypes.POLYGON){
				graphics.drawPolygon (null,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.LINESTRING) {
				graphics.drawLine (null,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTIPOLYGON) {
				graphics.drawPolygon (null,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTILINESTRING) {
				graphics.drawLine (null,options);
			} else if (geometry.type == geomajas.GeometryTypes.POINT) {
				graphics.drawSymbol (null,options);
			}
		/*} else {
			var viewGeometry = this.transform.worldGeometryToPan(geometry);
			if(geometry.declaredClass == geomajas.GeometryTypes.POLYGON){
				graphics.drawPolygon (viewGeometry,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.LINESTRING) {
				graphics.drawLine (viewGeometry,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTIPOLYGON) {
				graphics.drawPolygon (viewGeometry,options);
			} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTILINESTRING) {
				graphics.drawLine (viewGeometry,options);
			} else if (geometry.type == geomajas.GeometryTypes.POINT) {
				options.styleId = feature.getLayer().getLayerId() + "." + feature.styleId + ".style";
				graphics.drawSymbol (viewGeometry,options);
			}
		}*/
	},

	/**
	 * Deletes a features from the map. Also deletes the label.
	 */
	deleteShape : function (/*Feature*/feature, /*GraphicsContext*/graphics) {
		graphics.deleteShape(feature.getSelectionId());
	}
});<commit_msg>MAJ-811: restored non-clipped painter for all cases<commit_after>/*
 * This file is part of Geomajas, a component framework for building
 * rich Internet applications (RIA) with sophisticated capabilities for the
 * display, analysis and management of geographic information.
 * It is a building block that allows developers to add maps
 * and other geographic data capabilities to their web applications.
 *
 * Copyright 2008-2010 Geosparc, http://www.geosparc.com, Belgium
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

dojo.provide("geomajas.gfx.painter.FeaturePainter");
dojo.require("geomajas._base");
dojo.require("geomajas.gfx.Painter");

dojo.declare("FeaturePainter", Painter, {

	/**
	 * @class Painter implementation for features. This painter always paints
	 * in worldspace!
	 * @author Jan De Moerloose & Pieter De Graef
	 *
	 * @constructor
	 * @extends Painter
	 */
	constructor : function (mapWidget, mapView) {
		this.mapWidget = mapWidget;
		this.transform = new WorldViewTransformation(mapView);
	},

	/**
	 * The actual painting function. Currently paints selected features only.
	 * @param feature A Paintable object.
	 * @param graphics A GraphicsContext object, responsible for actual drawing.
	 */
	paint : function (feature, graphics) {
		var geometry = feature.getGeometry();

		// selected features only
		if(!feature.isSelected()){
			return;
		}

		var id = feature.getSelectionId();
		// no updates, delete first to update !!! => PDG: why is this??? speed perhaps...
//		if(graphics.getElementById(id)){
//			return;
//		}

		log.info("FeaturePainter : painting feature "+feature.getId());
		// Style is shared reference, so we have to clone it before we can change it !
		var style = feature.getStyle().clone();

		if(geometry.declaredClass == geomajas.GeometryTypes.POLYGON){
			style.copyFrom(this.mapWidget.getPolygonSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.LINESTRING){
			style.copyFrom(this.mapWidget.getLineSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.POINT){
			style.copyFrom(this.mapWidget.getPointSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.MULTIPOLYGON){
			style.copyFrom(this.mapWidget.getPolygonSelectStyle());
		}
		if(geometry.declaredClass == geomajas.GeometryTypes.MULTILINESTRING){
			style.copyFrom(this.mapWidget.getLineSelectStyle());
		}

		var options = {
			id : id,
			style: style,
			worldspace : true
		};

		// clipped and normal drawing is the same now ?
		var viewGeometry = this.transform.worldGeometryToPan(geometry);
		if(geometry.declaredClass == geomajas.GeometryTypes.POLYGON){
			graphics.drawPolygon (viewGeometry,options);
		} else if (geometry.declaredClass == geomajas.GeometryTypes.LINESTRING) {
			graphics.drawLine (viewGeometry,options);
		} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTIPOLYGON) {
			graphics.drawPolygon (viewGeometry,options);
		} else if (geometry.declaredClass == geomajas.GeometryTypes.MULTILINESTRING) {
			graphics.drawLine (viewGeometry,options);
		} else if (geometry.type == geomajas.GeometryTypes.POINT) {
			options.styleId = feature.getLayer().getLayerId() + "." + feature.styleId + ".style";
			graphics.drawSymbol (viewGeometry,options);
		}
	},

	/**
	 * Deletes a features from the map. Also deletes the label.
	 */
	deleteShape : function (/*Feature*/feature, /*GraphicsContext*/graphics) {
		graphics.deleteShape(feature.getSelectionId());
	}
});<|endoftext|>