Daniel@0: "use strict"; Daniel@0: Daniel@0: App.module("RepresentationModule", function(RepresentationModule, App, Backbone, Marionette, $, _, Logger) { Daniel@0: Daniel@0: RepresentationModule.addInitializer(function(options){ Daniel@0: Daniel@0: RepresentationModule.registerMaster({ Daniel@0: id: "entity.collection.pair", Daniel@0: inherit: "entity._pair", Daniel@0: Daniel@0: Daniel@0: // ================================================================= Daniel@0: // config grid header Daniel@0: Daniel@0: _generateHeaderLabel1: function(entityHeaderView) { Daniel@0: return _.str.sprintf("collection comparison (%s)", this.getConfigParameterValueOrDefaultValue(entityHeaderView.options.config, "comparisonMode")); Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: _generateHeaderLabel2: function(viewHeader) { Daniel@0: var configOnTheLeft = viewHeader.dynamicDerivedConfigData.attributes.collectionConfigOnTheLeft; Daniel@0: var configOnTheRight = viewHeader.dynamicDerivedConfigData.attributes.collectionConfigOnTheRight; Daniel@0: Daniel@0: var labelParts = []; Daniel@0: Daniel@0: if (configOnTheLeft) { Daniel@0: labelParts.push(this._generateCollectionConfigTitle(configOnTheLeft)); Daniel@0: } else { Daniel@0: labelParts.push("×"); Daniel@0: } Daniel@0: Daniel@0: labelParts.push("   ↔   "); Daniel@0: Daniel@0: if (configOnTheRight) { Daniel@0: labelParts.push(this._generateCollectionConfigTitle(configOnTheRight)); Daniel@0: } else { Daniel@0: labelParts.push("×"); Daniel@0: } Daniel@0: Daniel@0: return labelParts.join(""); Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: // ================================================================= Daniel@0: // dynamic derived config data Daniel@0: Daniel@0: __optionsOfDynamicDerivedConfigData: { Daniel@0: attributesToExcludeFromHash: ["collectionConfigOnTheLeft", "collectionConfigOnTheRight"], Daniel@0: customHashSuffixGenerator: function (attributes) { Daniel@0: return (attributes.collectionConfigOnTheLeft ? attributes.collectionConfigOnTheLeft. getClientId() : "x") Daniel@0: + (attributes.collectionConfigOnTheRight ? attributes.collectionConfigOnTheRight.getClientId() : "x"); Daniel@0: // return (attributes.collectionConfigOnTheLeft ? attributes.collectionConfigOnTheLeft. getHashForParameters() : "x") Daniel@0: // + (attributes.collectionConfigOnTheRight ? attributes.collectionConfigOnTheRight.getHashForParameters() : "x"); Daniel@0: } Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: __updateMethodOfDynamicDerivedConfigData: function (force) { Daniel@0: this._doUpdate(force); Daniel@0: if (this.attributes.collectionConfigOnTheLeft && this.attributes.dynamicDefinitionForCollectionOnTheLeft) { Daniel@0: return; Daniel@0: } Daniel@0: if (this.attributes.collectionConfigOnTheRight && this.attributes.dynamicDefinitionForCollectionOnTheRight) { Daniel@0: return; Daniel@0: } Daniel@0: var _this = this; Daniel@0: var interval = setInterval(function() { Daniel@0: _this._doUpdate(force); Daniel@0: if (_this.attributes.collectionConfigOnTheLeft && !_this.attributes.dynamicDefinitionForCollectionOnTheLeft) { Daniel@0: return; Daniel@0: } Daniel@0: if (_this.attributes.collectionConfigOnTheRight && !_this.attributes.dynamicDefinitionForCollectionOnTheRight) { Daniel@0: return; Daniel@0: } Daniel@0: clearInterval(interval); Daniel@0: }, 50); Daniel@0: }, Daniel@0: Daniel@0: __doUpdateMethodOfDynamicDerivedConfigData: function (force) { Daniel@0: var entityConfig = this.options.entityConfig; Daniel@0: var configGrid = this.options.configGrid; Daniel@0: Daniel@0: // do nothing with orphans (configs just before they are deleted) Daniel@0: if (!entityConfig.getDimension()) { Daniel@0: return; Daniel@0: } Daniel@0: Daniel@0: // find the nearest collections on the left and on the right Daniel@0: var newCollectionConfigOnTheLeft = entityConfig; Daniel@0: var newCollectionConfigOnTheRight = entityConfig; Daniel@0: Daniel@0: do { Daniel@0: newCollectionConfigOnTheLeft = configGrid.getPrevEntityNeighbour(newCollectionConfigOnTheLeft); Daniel@0: } while (newCollectionConfigOnTheLeft && newCollectionConfigOnTheLeft.getParameterValue("kind") == "pair"); Daniel@0: Daniel@0: do { Daniel@0: newCollectionConfigOnTheRight = configGrid.getNextEntityNeighbour(newCollectionConfigOnTheRight); Daniel@0: } while (newCollectionConfigOnTheRight && newCollectionConfigOnTheRight.getParameterValue("kind") == "pair"); Daniel@0: Daniel@0: var newDynamicDerivedConfigDataOnTheLeft = App.dynamicDerivedConfigDataProvider.get(newCollectionConfigOnTheLeft); Daniel@0: var newDynamicDerivedConfigDataOnTheRight = App.dynamicDerivedConfigDataProvider.get(newCollectionConfigOnTheRight); Daniel@0: Daniel@0: var newDynamicDefinitionForCollectionOnTheLeft = newDynamicDerivedConfigDataOnTheLeft ? newDynamicDerivedConfigDataOnTheLeft .attributes.dynamicDefinitionForCollection : null; Daniel@0: var newDynamicDefinitionForCollectionOnTheRight = newDynamicDerivedConfigDataOnTheRight ? newDynamicDerivedConfigDataOnTheRight.attributes.dynamicDefinitionForCollection : null; Daniel@0: Daniel@0: var attributesToSet = {}; Daniel@0: Daniel@0: var arrayOfShortcuts = [ Daniel@0: [newCollectionConfigOnTheLeft, "collectionConfigOnTheLeft", "change:parameters", this.triggerChange], Daniel@0: [newCollectionConfigOnTheRight, "collectionConfigOnTheRight", "change:parameters", this.triggerChange], Daniel@0: [newDynamicDefinitionForCollectionOnTheLeft, "dynamicDefinitionForCollectionOnTheLeft", "change", this.triggerChange], Daniel@0: [newDynamicDefinitionForCollectionOnTheRight, "dynamicDefinitionForCollectionOnTheRight", "change", this.triggerChange], Daniel@0: ]; Daniel@0: Daniel@0: for (var i = arrayOfShortcuts.length - 1; i >= 0; --i) { Daniel@0: var shortcuts = arrayOfShortcuts[i]; Daniel@0: var oldAttributeValue = this.attributes[shortcuts[1]]; Daniel@0: var newAttributeValue = shortcuts[0]; Daniel@0: if (newAttributeValue != oldAttributeValue) { Daniel@0: attributesToSet[shortcuts[1]] = newAttributeValue; Daniel@0: if (oldAttributeValue) { Daniel@0: this.stopListening(oldAttributeValue, shortcuts[2]); Daniel@0: } Daniel@0: if (newAttributeValue) { Daniel@0: this.listenTo(newAttributeValue, shortcuts[2], shortcuts[3]); Daniel@0: } Daniel@0: } Daniel@0: } Daniel@0: this.set(attributesToSet); Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: __triggerChangeMethodOfDynamicDerivedConfigData: function() { Daniel@0: this.dropCachedHash(); Daniel@0: this.trigger("change"); Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: generateDynamicDerivedConfigData: function(entityConfig, configGrid) { Daniel@0: var optionsOfThisDynamicDerivedConfigData = _.clone(this.__optionsOfDynamicDerivedConfigData); Daniel@0: optionsOfThisDynamicDerivedConfigData.entityConfig = entityConfig; Daniel@0: optionsOfThisDynamicDerivedConfigData.configGrid = configGrid; Daniel@0: Daniel@0: var dynamicDerivedConfigData = new RepresentationModule.DynamicDerivedConfigData({ Daniel@0: collectionConfigOnTheLeft: null, Daniel@0: collectionConfigOnTheRight: null, Daniel@0: dynamicDefinitionForCollectionOnTheLeft: null, Daniel@0: dynamicDefinitionForCollectionOnTheRight: null Daniel@0: }, optionsOfThisDynamicDerivedConfigData); Daniel@0: Daniel@0: dynamicDerivedConfigData.update = this.__updateMethodOfDynamicDerivedConfigData; Daniel@0: dynamicDerivedConfigData._doUpdate = this.__doUpdateMethodOfDynamicDerivedConfigData; Daniel@0: dynamicDerivedConfigData.triggerChange = this.__triggerChangeMethodOfDynamicDerivedConfigData; Daniel@0: Daniel@0: dynamicDerivedConfigData.listenTo(configGrid, "change_layout", dynamicDerivedConfigData.update); Daniel@0: dynamicDerivedConfigData.update(); Daniel@0: Daniel@0: return dynamicDerivedConfigData; Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: // ================================================================= Daniel@0: // dynamic derived vis instance data Daniel@0: Daniel@0: Daniel@0: // ----------------------------------------------------------------- Daniel@0: // dynamic derived vis instance data - base Daniel@0: Daniel@0: __optionsOfDynamicDerivedVisInstanceDataForBase: { Daniel@0: attributesToExcludeFromHash: ["apiResponseOnTheLeft", "apiResponseOnTheRight"], Daniel@0: customHashSuffixGenerator: function (attributes) { Daniel@0: if (attributes.apiResponseOnTheLeft) { Daniel@0: return JSON.stringify(attributes.apiResponseOnTheLeft.errors); Daniel@0: } else { Daniel@0: return typeof attributes.apiResponseOnTheLeft; Daniel@0: } Daniel@0: if (attributes.apiResponseOnTheRight) { Daniel@0: return JSON.stringify(attributes.apiResponseOnTheRight.errors); Daniel@0: } else { Daniel@0: return typeof attributes.apiResponseOnTheRight; Daniel@0: } Daniel@0: } Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: __upateMethodOfDynamicDerivedVisInstanceDataForBase: function(force) { Daniel@0: var visInstanceView = this.options.visInstanceView; Daniel@0: var _this = this; Daniel@0: _.each(["Right", "Left"], function(side) { Daniel@0: var dynamicDefinitionForCollection = visInstanceView.dynamicDerivedConfigDataForEntity.attributes["dynamicDefinitionForCollectionOnThe" + side]; Daniel@0: if (!dynamicDefinitionForCollection) { // entity kind has changed (e.g. a grid was reset) Daniel@0: return; Daniel@0: } Daniel@0: Daniel@0: var collectionId = dynamicDefinitionForCollection.attributes.id; Daniel@0: var requestParams = _.clone(visInstanceView.dynamicDerivedConfigDataForView.attributes.basePerspectiveRequestParams); Daniel@0: Daniel@0: if (!requestParams || !collectionId) { Daniel@0: var attrs = {}; Daniel@0: attrs["apiRequestURIOnThe" + side] = undefined; Daniel@0: attrs["apiRequestParamsHashOnThe" + side] = undefined; Daniel@0: attrs["apiResponseOnThe" + side] = undefined; Daniel@0: _this.set(attrs); Daniel@0: return; Daniel@0: } Daniel@0: requestParams.cid = collectionId; Daniel@0: Daniel@0: var apiRequestParamsHash = JSON.stringify(requestParams); Daniel@0: Daniel@0: if (!force && apiRequestParamsHash == _this.attributes["apiRequestParamsHashOnThe" + side]) { Daniel@0: return; Daniel@0: } Daniel@0: Daniel@0: var apiRequestURI = App.DataModule.CliopatriaAPI.request("getCollectionPerspective", requestParams, function(data){ Daniel@0: if (JSON.stringify(requestParams) != _this.attributes["apiRequestParamsHashOnThe" + side]) { Daniel@0: return; Daniel@0: } Daniel@0: var attrs = {}; Daniel@0: attrs["apiRequestParamsHashOnThe" + side] = undefined; Daniel@0: attrs["apiResponseOnThe" + side] = data; Daniel@0: _this.set(attrs); Daniel@0: }); Daniel@0: Daniel@0: var attrs = {}; Daniel@0: attrs["apiRequestURIOnThe" + side] = apiRequestURI; Daniel@0: attrs["apiRequestParamsHashOnThe" + side] = apiRequestParamsHash; Daniel@0: attrs["apiResponseOnThe" + side] = null; Daniel@0: _this.set(attrs); Daniel@0: }); Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: generateDynamicDerivedVisInstanceDataForBase: function(visInstanceView) { Daniel@0: // An empty object if comparison is not supported Daniel@0: var viewMaster = visInstanceView._cachedViewMaster; Daniel@0: if (!viewMaster.options.visInstanceSupportedComparisonModes.length) { Daniel@0: return new RepresentationModule.DynamicDerivedVisInstanceData({}); Daniel@0: } Daniel@0: Daniel@0: var optionsForThisDynamicDerivedVisInstanceDataForBase = _.clone(this.__optionsOfDynamicDerivedVisInstanceDataForBase); Daniel@0: optionsForThisDynamicDerivedVisInstanceDataForBase.visInstanceView = visInstanceView; Daniel@0: Daniel@0: var dynamicDerivedVisInstanceDataForBase = new RepresentationModule.DynamicDerivedVisInstanceData({ Daniel@0: apiRequestURIOnTheLeft: undefined, Daniel@0: apiRequestParamsHashOnTheLeft: undefined, Daniel@0: apiResponseOnTheLeft: undefined, Daniel@0: apiRequestURIOnTheRight: undefined, Daniel@0: apiRequestParamsHashOnTheRight: undefined, Daniel@0: apiResponseOnTheRight: undefined Daniel@0: }, optionsForThisDynamicDerivedVisInstanceDataForBase); Daniel@0: Daniel@0: dynamicDerivedVisInstanceDataForBase.update = this.__upateMethodOfDynamicDerivedVisInstanceDataForBase; Daniel@0: Daniel@0: dynamicDerivedVisInstanceDataForBase.listenTo(visInstanceView.dynamicDerivedConfigDataForEntity, "change", dynamicDerivedVisInstanceDataForBase.update); Daniel@0: dynamicDerivedVisInstanceDataForBase.listenTo(visInstanceView.dynamicDerivedConfigDataForView, "change:basePerspectiveRequestParams", dynamicDerivedVisInstanceDataForBase.update); Daniel@0: Daniel@0: dynamicDerivedVisInstanceDataForBase.update(); Daniel@0: Daniel@0: return dynamicDerivedVisInstanceDataForBase; Daniel@0: }, Daniel@0: Daniel@0: Daniel@0: verifyAllDataForVisInstanceBase: function(visInstanceView) { Daniel@0: this._verifyThatViewIsNotEmptyOrUnknown(visInstanceView); Daniel@0: Daniel@0: // if (visInstanceView.options.entityConfig.getParameterValue("kind") Daniel@0: // && visInstanceView.options.viewConfig.getParameterValue("kind") == "key-relative-chord-seq") { Daniel@0: // throw new RepresentationModule.Error({type: "drawing", derivedDataToUpdate: "base"}); Daniel@0: // } Daniel@0: Daniel@0: var viewMaster = visInstanceView._cachedViewMaster; Daniel@0: if (!viewMaster.options.canHaveBase) { Daniel@0: return; Daniel@0: } Daniel@0: var supportedComparisonModes = viewMaster.options.visInstanceSupportedComparisonModes; Daniel@0: if (!supportedComparisonModes.length) { Daniel@0: throw new RepresentationModule.Error({type: "comparison_not-supported"}); Daniel@0: } Daniel@0: if (!_.contains(supportedComparisonModes, viewMaster._getVisInstanceViewComparisonMode(visInstanceView))) { Daniel@0: throw new RepresentationModule.Error({type: "comparison_wrong-type", supportedTypes: supportedComparisonModes}); Daniel@0: } Daniel@0: Daniel@0: var attributesOfDerivedConfigDataForEntityOnTheLeft = visInstanceView.dynamicDerivedConfigDataForEntity.attributes; Daniel@0: var attributesOfDerivedConfigDataForEntityOnTheRight = visInstanceView.dynamicDerivedConfigDataForEntity.attributes; Daniel@0: var dynamicDefinitionForCollectionOnTheLeft = attributesOfDerivedConfigDataForEntityOnTheLeft .dynamicDefinitionForCollectionOnTheLeft; Daniel@0: var dynamicDefinitionForCollectionOnTheRight = attributesOfDerivedConfigDataForEntityOnTheRight.dynamicDefinitionForCollectionOnTheRight; Daniel@0: var attributesOfCollectionOnTheLeft = dynamicDefinitionForCollectionOnTheLeft ? dynamicDefinitionForCollectionOnTheLeft.attributes : {}; Daniel@0: var attributesOfCollectionOnTheRight = dynamicDefinitionForCollectionOnTheRight ? dynamicDefinitionForCollectionOnTheRight.attributes : {}; Daniel@0: Daniel@0: if (attributesOfCollectionOnTheLeft.id === null || attributesOfCollectionOnTheRight.id === null) { Daniel@0: throw new RepresentationModule.Error({type: "data-preparing_entity-derived"}); Daniel@0: } Daniel@0: if (attributesOfCollectionOnTheLeft.id === false || attributesOfCollectionOnTheRight.id === false) { Daniel@0: var apiErrorsOnTheLeft = attributesOfCollectionOnTheLeft .errors || []; Daniel@0: var apiErrorsOnTheRight = attributesOfCollectionOnTheRight.errors || []; Daniel@0: apiErrors = apiErrorsOnTheLeft.concat(apiErrorsOnTheRight); Daniel@0: throw new RepresentationModule.Error({type: "api-error_entity-derived", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "entity"}); Daniel@0: } Daniel@0: if ((attributesOfCollectionOnTheLeft .id === "" || (attributesOfCollectionOnTheLeft .hasOwnProperty("id") && attributesOfCollectionOnTheLeft .id === undefined)) Daniel@0: || (attributesOfCollectionOnTheRight.id === "" || (attributesOfCollectionOnTheRight.hasOwnProperty("id") && attributesOfCollectionOnTheRight.id === undefined))) { Daniel@0: throw new RepresentationModule.Error({type: "collection_no-recordings"}); Daniel@0: } Daniel@0: if (attributesOfCollectionOnTheLeft.id === undefined || attributesOfCollectionOnTheRight.id === undefined) { Daniel@0: throw new RepresentationModule.Error({type: "pair_incomplete"}); Daniel@0: } Daniel@0: Daniel@0: var attribytesOfDerivedVisInstanceDataForBase = visInstanceView.dynamicDerivedVisInstanceDataForBase.attributes; Daniel@0: if (!attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft || !attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight) { Daniel@0: throw new RepresentationModule.Error({type: "data-preparing_base"}); Daniel@0: } Daniel@0: if (attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft.errors || attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight.errors) { Daniel@0: var apiErrorsOnTheLeft = attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft .errors || []; Daniel@0: var apiErrorsOnTheRight = attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight.errors || []; Daniel@0: var apiErrors = apiErrorsOnTheLeft.concat(apiErrorsOnTheRight); Daniel@0: Daniel@0: if (apiErrors[0]) { Daniel@0: var error0 = apiErrors[0]; Daniel@0: if (((error0.code == 11 || error0.code == 12) && !apiErrors[1]) || (apiErrors[1] && (apiErrors[1].code == 11 || apiErrors[1].code == 12))) { Daniel@0: throw new RepresentationModule.Error({type: "api-message_progress_base", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "base"}); Daniel@0: Daniel@0: // FIXME errors like this should probably go to Master.view.xxx Daniel@0: } else if ((error0.code == 20 && !apiErrors[1]) || (apiErrors[1] && (apiErrors[1].code == 20))) { Daniel@0: return; Daniel@0: } Daniel@0: Daniel@0: } Daniel@0: Daniel@0: throw new RepresentationModule.Error({type: "api-error_base", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "base"}); Daniel@0: } Daniel@0: }, Daniel@0: }); Daniel@0: }); Daniel@0: }, Logger);