diff --git a/app/index.html b/app/index.html index d55fe6d..3a85eed 100644 --- a/app/index.html +++ b/app/index.html @@ -85,12 +85,12 @@ padding: 20px 30px;" >
- - +
@@ -565,6 +565,7 @@

+ diff --git a/app/scripts/connectors/nodeConnector.js b/app/scripts/connectors/nodeConnector.js new file mode 100644 index 0000000..7ce5e48 --- /dev/null +++ b/app/scripts/connectors/nodeConnector.js @@ -0,0 +1,34 @@ +'use strict'; + +if (typeof $ === 'undefined') { + var $ = jQuery; +} +if (typeof $ === 'undefined') { + var $ = window.jQuery; +} + +window.Drupal.behaviors.myBehavior = { + attach: function (context, settings) { + // Using once() to apply the mcdaIFrameBehavior effect when you want to run just one function. + $(window, context).once('mcdaIFrameBehavior').each(function () { + console.log('onAttach'); + var connectCount = 0; + // for some unknown the reason angular directive controler of the embedded child iframe + // does not recieve the event when it's not fired from the onConnect method. + var mcdaApp = window.seamless(document.getElementById('mcda'), + {onConnect: function () { + // FIXME: for some unknown reasin, onConnect is called if no child fram has activiliy connected + // by invokinf seamless.connect() resulting in the onConnect function called twice! + if(connectCount === 1) { + var currentNodeId = window.location.pathname.split('/').pop(); + mcdaApp.send({ + nodeId: currentNodeId + }); + } else { + console.log('pre/re connection #:' + connectCount); + } + connectCount++; + }}); + }); + } +}; \ No newline at end of file diff --git a/app/scripts/controllers/drupalContextProviderDirectiveController.js b/app/scripts/controllers/drupalContextProviderDirectiveController.js index c9b97c8..8ac1ed3 100644 --- a/app/scripts/controllers/drupalContextProviderDirectiveController.js +++ b/app/scripts/controllers/drupalContextProviderDirectiveController.js @@ -10,8 +10,18 @@ angular.module( 'eu.myclimateservice.csis.scenario-analysis.services.drupalService', function ($scope, $timeout, Icmm, Worldstates, drupalService) { 'use strict'; - var showIndicatorFileLoadingError, showFileLoading, loadIndicatorObjects, loadIndicatorObject, onloadCfFile, onloadDsFile; + var showIndicatorFileLoadingError, showFileLoading, loadIndicatorObjects, loadIndicatorObject, onloadCfFile, onloadDsFile, onSeamlessEvent, onloadIccObjects; var restApi = drupalService.restApi; + + console.log('window.seamless.connect()'); + var parent = window.seamless.connect(); + // Receive a message, this only works when the parent window calls send(...) + // inside the onConnect() method, otherwise the event is not recieved (race condition?) + // strangley, the onConnect callback is called twice. See comment in nodeConncetor.js + parent.receive(function (data) { + console.log(' parent.receive:' + data); + onSeamlessEvent(data); + }); //initialize the bindings $scope.selectedWorldstates = []; @@ -126,7 +136,7 @@ angular.module( showIndicatorFileLoadingError = function (message) { $scope.fileLoadError = true; $scope.errorMessage = message; - $scope.$apply(); + //$scope.$apply(); }; showFileLoading = function () { @@ -140,13 +150,13 @@ angular.module( $scope.showCfFileLoadingError = function (message) { $scope.cfFileLoadError = true; $scope.cfFileLoadErrorMsg = 'Criteria functions not loaded. ' + message; - $scope.$apply(); + //$scope.$apply(); }; $scope.showDsFileLoadingError = function (message) { $scope.dsFileLoadError = true; $scope.dsFileLoadErrorMsg = 'Decision strategies not loaded. ' + message; - $scope.$apply(); + //$scope.$apply(); }; loadIndicatorObjects = function (indicatorObjects) { @@ -275,6 +285,126 @@ angular.module( showIndicatorFileLoadingError(err.toString()); } }; + + onloadIccObjects = function (file) { + return function (e) { + var fileObj, worldstateDummy, indicatorProp, indicator, origLoadedIndicators, indicatorGroup, + loadedIndicatorLength, indicatorMapLength, containsIndicator, msg; + try { + fileObj = JSON.parse(e.target.result); + /* + * + * accept two differnt kind of files. + * 1. A plain icc data object. + * In that case we apply a standard name to this object + * + * 2. A worldstate Dummy object that already has a name + */ + + if (fileObj.name && fileObj.iccdata) { + worldstateDummy = fileObj; + origLoadedIndicators = fileObj.iccdata; + worldstateDummy.iccdata = { + actualaccessinfo: JSON.stringify(worldstateDummy.iccdata) + }; + } else { + //generate a uniqe id... + origLoadedIndicators = fileObj; + worldstateDummy = { + name: 'Nonamed indicator data ' + '(filename: ' + file.name + ' )', + iccdata: { + actualaccessinfo: JSON.stringify(fileObj) + } + }; + } + var tmp; + if ($scope.worldstates && $scope.worldstates.length > 0) { + tmp = Worldstates.utils.stripIccData([$scope.worldstates[0]])[0].data; + } else { + tmp = origLoadedIndicators; + } + $scope.indicatorMap = {}; + for (indicatorGroup in tmp) { + if (tmp.hasOwnProperty(indicatorGroup)) { + for (indicatorProp in tmp[indicatorGroup]) { + if (tmp[indicatorGroup].hasOwnProperty(indicatorProp)) { + if (indicatorProp !== 'displayName' && indicatorProp !== 'iconResource') { + $scope.indicatorMap[indicatorProp] = tmp[indicatorGroup][indicatorProp]; + } + } + } + } + } + loadedIndicatorLength = 0; + indicatorMapLength = 0; + for (indicator in $scope.indicatorMap) { + if ($scope.indicatorMap.hasOwnProperty(indicator)) { + containsIndicator = false; + indicatorMapLength++; + for (indicatorGroup in origLoadedIndicators) { + if (origLoadedIndicators.hasOwnProperty(indicatorGroup)) { + for (indicatorProp in origLoadedIndicators[indicatorGroup]) { + if (origLoadedIndicators[indicatorGroup].hasOwnProperty(indicatorProp)) { + if (indicatorProp !== 'displayName' && indicatorProp !== 'iconResource') { + if ($scope.indicatorMap[indicator].displayName === origLoadedIndicators[indicatorGroup][indicatorProp].displayName) { + loadedIndicatorLength++; + containsIndicator = true; + break; + } + } + } + } + } + } + if (!containsIndicator) { + msg = 'Could not load indicator file ' + file.name + '. It contains no indicator data for ' + indicator; + console.error(msg); + showIndicatorFileLoadingError(msg); + return; + } + } + } + if (loadedIndicatorLength !== indicatorMapLength) { + msg = 'indicator data in file ' + file.name + ' has more indicators defined that the first loaded indicator set.'; + console.error(msg); + showIndicatorFileLoadingError(msg); + return; + } + + // we need an id to distinct the icc objects. eg. the ranking table use this id + // to keep track of the indicator objects + if (!worldstateDummy.id) { + worldstateDummy.id = Math.floor((Math.random() * 1000000) + 1); + } + + // an excellent example on technical debt and accidental complexity: + // instead of adressing the root cause of the problem, we + // introduce additional inadequateness and ambiguity + Icmm.convertToCorrectIccDataFormat(worldstateDummy); + + if ($scope.worldstates) { + $scope.worldstates.push(worldstateDummy); + $scope.editable.push(false); + } else { + $scope.editable.push(false); + $scope.worldstates = [worldstateDummy]; + } + $scope.showDummyListItem = false; + $scope.noIndicatorsLoaded = false; + // when indicator objects are added we want them to be selected by default + $scope.selectedWorldstates.splice(0, $scope.selectedWorldstates.length); + $scope.worldstates.forEach(function (object, index) { + $scope.toggleSelection(index); + }); + + $scope.$apply(); + + } catch (err) { + // show an error in the gui... + showIndicatorFileLoadingError(err.toString()); + } + }; + }; onloadCfFile = function (theFile) { return function (e) { @@ -391,32 +521,43 @@ angular.module( } }; }; + + onSeamlessEvent = function(eventData) { + console.log('load study from node id: ' + eventData.nodeId); + + restApi.getStudy(eventData.nodeId).then(function (study) { + var indicatorArray = drupalService.studyHelper.getIndicatorArray(study); + loadIndicatorObjects(indicatorArray); + }, function (error) { + console.log(error.data.message); + showIndicatorFileLoadingError(error.data.message.toString()); + }); + }; /* * When the newFile property has changed the User want's to add a new list of files. */ $scope.$watch('iccObjects', function (newVal, oldVal) { - /*var i, file, reader; - if (!angular.equals(newVal, oldVal) && newVal) { - showFileLoading(); - - for (i = 0; i < $scope.iccObjects.length; i++) { - - file = $scope.iccObjects[i]; - - reader = new FileReader(); - reader.onload = onloadIccObjects(file); - try { - //we assume that the file is utf-8 encoded - reader.readAsText(file); - } catch (err) { - // show an error in the gui... - showIndicatorFileLoadingError(err.toString()); - } - - } - - }*/ + var i, file, reader; + if (!angular.equals(newVal, oldVal) && newVal) { + showFileLoading(); + + for (i = 0; i < $scope.iccObjects.length; i++) { + + file = $scope.iccObjects[i]; + + reader = new FileReader(); + reader.onload = onloadIccObjects(file); + try { + //we assume that the file is utf-8 encoded + reader.readAsText(file); + } catch (err) { + // show an error in the gui... + showIndicatorFileLoadingError(err.toString()); + } + + } + } }, true); $scope.$watch('cfConfigFile', function () { @@ -466,17 +607,14 @@ angular.module( }, true); + - $timeout(function () { - restApi.getStudy(1).then(function (study) { - var indicatorArray = drupalService.studyHelper.getIndicatorArray(study); - loadIndicatorObjects(indicatorArray); - }, function (error) { - console.log(error.data.message); - showIndicatorFileLoadingError(error.data.message.toString()); - }); - }, 1000); + // TODO: get study / EU-GL Step Entity id from Drpal API, e.g. + // via request parameter passed to iFrame or via seamless.js parent.receive callback +// $timeout(function () { +// onSeamlessEvent({nodeId:2}) +// }, 1000); } diff --git a/app/scripts/controllers/mainController.js b/app/scripts/controllers/mainController.js index fbe64ef..6dd7a62 100644 --- a/app/scripts/controllers/mainController.js +++ b/app/scripts/controllers/mainController.js @@ -24,13 +24,13 @@ angular.module( function ($window, $scope, $resource, $http, $timeout, $q, IcmmPersistanceService, FilesPersistanceService, drupalService, ngDialog) { 'use strict'; - var parent = window.seamless.connect(); - // Receive a message - parent.receive(function (data, event) { - - // Print out the data that was received. - console.log('child recieved: ' + data + event); - }); +// var parent = window.seamless.connect(); +// // Receive a message +// parent.receive(function (data, event) { +// +// // Print out the data that was received. +// console.log('child recieved: ' + data.nodeId); +// }); var restApi = drupalService.restApi; @@ -234,14 +234,6 @@ angular.module( $scope.icmmLastViewed = true; - - if (!parent || parent === null) { - parent = window.seamless.connect(); - } - // Send a message - parent.send({ - myparam: 'child -> parent' - }); }; $scope.switchToFilesTab = function () { diff --git a/app/scripts/directives/drupalBasedAnalysisContextProvider.js b/app/scripts/directives/drupalBasedAnalysisContextProvider.js new file mode 100644 index 0000000..cf82376 --- /dev/null +++ b/app/scripts/directives/drupalBasedAnalysisContextProvider.js @@ -0,0 +1,26 @@ +angular.module( + 'eu.myclimateservice.csis.scenario-analysis.directives' + ).directive( + 'drupalContextProvider', + [ + function () { + 'use strict'; + + var scope; + + scope = { + 'worldstates': '=', + 'selectedWorldstates': '=', + 'decisionStrategies': '=', + 'criteriaFunctions': '=' + }; + + return { + scope: scope, + restrict: 'E', + templateUrl: 'templates/drupalContextProviderTemplate.html', + controller: 'eu.myclimateservice.csis.scenario-analysis.controllers.drupalContextProviderDirectiveController' + }; + } + ] + ); \ No newline at end of file diff --git a/app/scripts/directives/fileBasedAnalysisContextProvider.js b/app/scripts/directives/fileBasedAnalysisContextProvider.js index c32bf1a..ca9f7b3 100644 --- a/app/scripts/directives/fileBasedAnalysisContextProvider.js +++ b/app/scripts/directives/fileBasedAnalysisContextProvider.js @@ -12,15 +12,14 @@ angular.module( 'worldstates': '=', 'selectedWorldstates': '=', 'decisionStrategies': '=', - 'criteriaFunctions': '=', + 'criteriaFunctions': '=' }; return { scope: scope, restrict: 'E', templateUrl: 'templates/fileContextProviderTemplate.html', - //controller: 'eu.myclimateservice.csis.scenario-analysis.controllers.FileContextProviderDirectiveController' - controller: 'eu.myclimateservice.csis.scenario-analysis.controllers.drupalContextProviderDirectiveController' + controller: 'eu.myclimateservice.csis.scenario-analysis.controllers.FileContextProviderDirectiveController' }; } ] diff --git a/app/scripts/services/drupalDecisionStrategies.js b/app/scripts/services/drupalDecisionStrategies.js deleted file mode 100644 index 56edb05..0000000 --- a/app/scripts/services/drupalDecisionStrategies.js +++ /dev/null @@ -1,93 +0,0 @@ -angular.module( - 'eu.myclimateservice.csis.scenario-analysis.services' - ).factory( - 'eu.myclimateservice.csis.scenario-analysis.services.DecisionStrategies', - [ - '$resource', - 'eu.myclimateservice.csis.scenario-analysis.services.configurationService', - function ($resource, configurationService) { - 'use strict'; - var decisionStrategy, transformResponse, decisionStrategyFacade, createResource; - transformResponse = function (studyJsonString) { - var study; - if (studyJsonString) { - study = JSON.parse(studyJsonString); - - return JSON.parse(study.decisionStrategies); - } - return null; - - }; - - - - createResource = function () { - var r; - - r = $resource(configurationService.$this.drupalRestApi.host + '/' + configurationService.getDomain() + '.decisionstrategies/1', { - decisionStrategyId: '@id', - deduplicate: false, - omitNullValues: 'false' - }, { - 'query': { - method: 'GET', - isArray: true, - params: { - level: '1', - omitNullValues: 'true' - }, - transformResponse: transformResponse - }, - 'update': { - method: 'PUT', - transformRequest: function (data) { - var transformedData, study; - study = { - $self: '/CRISMA.decisionstrategies/1', - id: 1, - decisionStrategies: angular.toJson(data) - }; - transformedData = JSON.stringify(study, function (k, v) { - // we have to take care of angular properties by ourselves - if (k.substring(0, 1) === '$' && !(k === '$self' || k === '$ref')) { - return undefined; - } - - return v; - }); - return transformedData; - } - } - }); - - r.getId = function () { - return Icmm.getNextId(configurationService.getIcmmApi() + '/' + configurationService.getDomain(), '.decisionstrategies'); - }; - - return r; - }; - - decisionStrategy = createResource(); - decisionStrategyFacade = { - 'get': function () { - return decisionStrategy.get.apply(this, arguments); - }, - 'query': function () { - return decisionStrategy.query.apply(this, arguments); - }, - 'update': function () { - return decisionStrategy.update.apply(this, arguments); - }, - 'getId': function () { - return decisionStrategy.getId.apply(this, arguments); - } - }; - - configurationService.addApiListener(function () { - decisionStrategy = createResource(); - }); - - return decisionStrategyFacade; - } - ] - ); diff --git a/app/templates/drupalContextProviderTemplate.html b/app/templates/drupalContextProviderTemplate.html new file mode 100644 index 0000000..1868209 --- /dev/null +++ b/app/templates/drupalContextProviderTemplate.html @@ -0,0 +1,161 @@ +
+
+
+ HTML 5 File APi is not available in your Browser. Please use a Browser that supports this. + see also http://caniuse.com/#search=file%20api +
+
+
+
+
+
+
+ +
+
    + +
  • +
  • +
  • + + + {{ws.name}} + + +
    + + + +
    +
  • +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ {{errorMessage}} +
+
+
+
+
+ +
+
+
+
+ + Choose a file + + +
+
+
+ + No indicator files selected +
+
+ + {{cfFileLoadErrorMsg}} +
+
+ Loaded File: {{loadedCfFile}} +
+
+
+
+
+ +
+ +
+
+
+ + Choose a file + + +
+
+
+ + No indicator files selected +
+
+ + {{dsFileLoadErrorMsg}} +
+
+ Loaded File: {{loadedDsfFile}} +
+
+
+
+
\ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index e91665c..289b3d1 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -81,13 +81,14 @@ basePath: '', 'target/dist/scripts/services/icmmCriteriaFunctions.js', 'target/dist/scripts/services/icmmDecisionStrategies.js', 'target/dist/scripts/services/drupalService.js', - 'target/dist/scripts/services/drupalContextProviderDirectiveController.js', + 'target/dist/scripts/controllers/drupalContextProviderDirectiveController.js', 'target/dist/bower_components/angular-mocks/angular-mocks.js', 'app/templates/criteriaEmphasesTemplate.html', 'app/templates/criteriaFunctionManagerTemplate.html', 'app/templates/criteriaRadarPopupTemplate.html', 'app/templates/decisionStrategyManagerTemplate.html', 'app/templates/decisionStrategyTemplate.html', + 'app/templates/drupalContextProviderTemplate.html', 'app/templates/fileContextProviderTemplate.html', 'app/templates/icmmContextProviderTemplate.html', 'app/templates/indicatorBandItemTemplate.html',