function()

in kahuna/public/js/edits/image-editor.js [46:444]


    function($rootScope,
             $scope,
             $timeout,
             editsService,
             editsApi,
             imageService,
             labelService,
             imageAccessor,
             collections,
             mediaApi,
             storage) {

  var ctrl = this;
  ctrl.canUndelete = false;
  ctrl.isDeleted = false;

  ctrl.displayMetadataTemplates = window._clientConfig.metadataTemplates !== undefined && window._clientConfig.metadataTemplates.length > 0;

  ctrl.$onInit = () => {
    mediaApi.getSession().then(session => {
        if (ctrl.image.data.softDeletedMetadata !== undefined && (session.user.permissions.canDelete || session.user.email === ctrl.image.data.uploadedBy)) { ctrl.canUndelete = true; }
        if (ctrl.image.data.softDeletedMetadata !== undefined) { ctrl.isDeleted = true; }
    });

    editsService.canUserEdit(ctrl.image).then(editable => {
        ctrl.userCanEdit = editable;
    });
    ctrl.batchApplyUsageRights = batchApplyUsageRights;
    editsApi.getUsageRightsCategories()
        .then(cats => ctrl.categories = cats)
        .finally(() => updateUsageRightsCategory());
    ctrl.error = false;
    ctrl.saved = false;
    ctrl.saving = false;
    ctrl.showUsageRights = false;
    ctrl.status = ctrl.image.data.valid ? 'ready' : 'invalid';
    ctrl.usageRights = imageService(ctrl.image).usageRights;
    ctrl.invalidReasons = ctrl.image.data.invalidReasons;
    ctrl.systemName = window._clientConfig.systemName;
    ctrl.descriptionOption = overwrite.key;

    ctrl.undelete = undelete;

    ctrl.imageAsArray = [ctrl.image];

    const updateImages = (images, metadataFieldName, valueFn) => {
      images.map((image) => {
        editsService.batchUpdateMetadataField(
          [image],
          metadataFieldName,
          valueFn(image),
          ctrl.descriptionOption
        );
      });
      return Promise.resolve(ctrl.imageAsArray);
    };

    const removeXFromImages = (metadataFieldName, accessor) => (images, removedX, fieldName) => {
      if (fieldName && fieldName !== metadataFieldName) {
        return Promise.resolve(ctrl.imageAsArray);
      }

      var removedArr = Array.isArray(removedX) ? removedX : [removedX];
      return updateImages(
        images,
        metadataFieldName,
        (image) => accessor(image)?.filter((x) => !removedArr.includes(x)) || []
      );
    };

    const addXToImages = (metadataFieldName, accessor) => (images, addedX, fieldName, removedElements = []) => {
      if (fieldName && fieldName !== metadataFieldName) {
        return Promise.resolve(ctrl.imageAsArray);
      }

      return updateImages(
        images,
        metadataFieldName,
        (image) => {
          const currentXInImage = accessor(image);
          let tempElements = currentXInImage ? [...currentXInImage, ...addedX] : [...addedX];
          tempElements = tempElements.filter(e => !removedElements.includes(e));
          return tempElements;
        }
      );
    };

    //-labels-
    function addLabelToImagesFn(images, addedX, fieldName, removedElements = []) {
      if (fieldName && fieldName !== "labels") {
        return Promise.resolve(ctrl.imageAsArray);
      }

      if (removedElements.length > 0) {
          removedElements.forEach(element => labelService.batchRemove(images, element));
      }
      return labelService.batchAdd(images, addedX);
    }

    function  removeLabelFromImagesFn(images, removedX, fieldName) {
      if (fieldName && fieldName !== "labels") {
        return Promise.resolve(ctrl.imageAsArray);
      }
      return labelService.batchRemove(images, removedX);
    }

    ctrl.addLabelToImages = addLabelToImagesFn;
    ctrl.removeLabelFromImages = removeLabelFromImagesFn;
    ctrl.labelAccessor = (image) => imageAccessor.readLabels(image).map(label => label.data);

    //-keywords-
    ctrl.keywordAccessor = (image) => imageAccessor.readMetadata(image).keywords;
    ctrl.addKeywordToImages = addXToImages('keywords', ctrl.keywordAccessor);
    ctrl.removeKeywordFromImages = removeXFromImages('keywords', ctrl.keywordAccessor);

    //TODO put collections in their own directive
    ctrl.addCollection = false;
    ctrl.addToCollection = addToCollection;
    ctrl.batchApplyCollections = batchApplyCollections;
    ctrl.collectionError = false;
    ctrl.confirmDelete = false;
    ctrl.getCollectionStyle = getCollectionStyle;
    ctrl.openCollectionTree = openCollectionTree;
    ctrl.removeImageFromCollection = removeImageFromCollection;
    ctrl.selectionMode = true;

    // TODO: Find a way to broadcast more selectively
    const batchApplyUsageRightsEvent = 'events:batch-apply:usage-rights';
    const batchApplyCollectionsEvent = 'events:batch-apply:collections';
    const batchRemoveCollectionsEvent = 'events:batch-remove:collections';

    const metadata = ctrl.image.data.userMetadata.data.metadata;
    const usageRights =  ctrl.image.data.userMetadata.data.usageRights;

    const offMetadataUpdateStart =
        editsService.on(metadata, 'update-start', () => ctrl.saving = true);

    const offMetadataUpdateEnd =
        editsService.on(metadata, 'update-end', onSave);

    const offMetadataUpdateError =
        editsService.on(metadata, 'update-error', onError);

    const offUsageRightsUpdateStart =
        editsService.on(usageRights, 'update-start', () => ctrl.saving = true);

    const offUsageRightsUpdateEnd =
        editsService.on(usageRights, 'update-end', onSave);

    const offUsageRightsUpdateError =
        editsService.on(usageRights, 'update-error', onError);

    $scope.$on('$destroy', () => {
        offMetadataUpdateStart();
        offMetadataUpdateEnd();
        offMetadataUpdateError();
        offUsageRightsUpdateStart();
        offUsageRightsUpdateEnd();
        offUsageRightsUpdateError();
    });

    ctrl.onMetadataTemplateApplying = (leases) => {
      if (angular.isDefined(leases)) {
        ctrl.leasesUpdatingByTemplate = true;
      }
    };

    ctrl.onMetadataTemplateApplied = () => {
      $scope.$broadcast('events:metadata-template:template-applied', {});

      ctrl.collectionUpdatedByTemplate = false;
      ctrl.leasesUpdatedByTemplate = false;
      ctrl.leasesUpdatingByTemplate = false;
      ctrl.showUsageRights = false;
      ctrl.usageRightsUpdatedByTemplate = false;
    };

    ctrl.onMetadataTemplateCancelled = (metadata, usageRights) => {
      $scope.$broadcast('events:metadata-template:template-cancelled', { metadata });

      ctrl.collectionUpdatedByTemplate = false;
      ctrl.leasesUpdatedByTemplate = false;
      ctrl.usageRights.data = usageRights;
      ctrl.showUsageRights = false;
      ctrl.usageRightsUpdatedByTemplate = false;
    };

    ctrl.onMetadataTemplateSelected = (metadata, usageRights, collection, leasesWithConfig) => {
      $scope.$broadcast('events:metadata-template:template-selected', { metadata });

      ctrl.collectionUpdatedByTemplate = false;
      ctrl.leasesUpdatedByTemplate = false;
      ctrl.showUsageRights = false;
      ctrl.usageRightsUpdatedByTemplate = false;
      ctrl.usageRights.data = usageRights;

      if (angular.isDefined(leasesWithConfig)) {
        const leasesFromTemplate = leasesWithConfig.leases.map(lease => {
          return {...lease, fromTemplate: true};
        });
        ctrl.updatedLeases = [...leasesFromTemplate, ...(leasesWithConfig.replace ? [] : ctrl.image.data.leases.data.leases)];
        ctrl.leasesUpdatedByTemplate = true;
      }

      if (angular.isDefined(collection)) {
        if (ctrl.image.data.collections.filter(r => r.data.path.toString() === collection.data.fullPath.toString()).length === 0) {
          ctrl.updatedCollections = [
            {description: collection.data.data.description, fromTemplate: true},
            ...ctrl.image.data.collections.map(resource => resource.data)
          ];

          ctrl.collectionUpdatedByTemplate = true;
        }
      }

      if (ctrl.image.data.usageRights === undefined ||
        ctrl.image.data.usageRights.category !== usageRights.category) {
        ctrl.showUsageRights = true;
      }

      const originalUsageRights = ctrl.image.data.usageRights ? ctrl.image.data.usageRights : {};
      if (angular.equals(usageRights, originalUsageRights) === false) {
        ctrl.usageRightsUpdatedByTemplate = true;
      }
    };

    if (Boolean(ctrl.withBatch)) {
        $scope.$on(batchApplyUsageRightsEvent, (e, { data }) => {
            const image = ctrl.image;
            const resource = image.data.userMetadata.data.usageRights;
            editsService.update(resource, data, image);
            batchSetLeasesFromUsageRights(image, data.category);
        });
    }

    if (Boolean(ctrl.withBatch)) {
        $scope.$on(batchApplyCollectionsEvent, (e, { collections }) => {
            collections.forEach( ctrl.addToCollection );
        });

        $scope.$on(batchRemoveCollectionsEvent, () => {
            const collectionsOnImage = ctrl.image.data.collections;
            collectionsOnImage.forEach( ctrl.removeImageFromCollection );
        });
    }

    function onSave() {
        return ctrl.image.get().then(newImage => {
            ctrl.image = newImage;
            ctrl.imageAsArray = [newImage];
            ctrl.usageRights = imageService(ctrl.image).usageRights;
            updateUsageRightsCategory();
            ctrl.status = ctrl.image.data.valid ? 'ready' : 'invalid';
            ctrl.saving = false;

            ctrl.error = false;
            ctrl.saved = true;
            $timeout(() => ctrl.saved = false, 1000);
        }).
        // TODO: we could retry here again, but re-saving does that, and given
        // it's auto-save, it should be fine.
        then(() => onError);
    }

    function onError() {
        ctrl.saving = false;
        ctrl.error = true;
    }

    function updateUsageRightsCategory() {
        let category = ctrl.categories.find(cat => cat.value === ctrl.usageRights.data.category);
        ctrl.usageRightsCategory = category && category.name;
        ctrl.showUsageRights = ctrl.usageRightsCategory === undefined;
    }

    function batchSetLeasesFromUsageRights(image, rightsCat) {
      const category = ctrl.categories.find(cat => cat.value === rightsCat);
      if (!category || image.data.usageRights.category === rightsCat) {
        return;
      }
      if (category.leases.length === 0) {
        // possibility of removal only
        if (!image.data.usageRights.category) {
          return;
        }
        const removeLeases = removeCategoryLeases(ctrl.categories, image, image.data.usageRights.category);
        if (removeLeases.length > 0) {
          $rootScope.$broadcast('events:rights-category:delete-leases', {
            catLeases: removeLeases,
            batch: false
          });
        }
        return;
      }
      const catLeases = createCategoryLeases(category.leases, image);
      if (catLeases.length === 0) {
        // possibility of remove only of leases due to missing date info on image
        if (!image.data.usageRights.category) {
          return;
        }
        const removeLeases = removeCategoryLeases(ctrl.categories, image, image.data.usageRights.category);
        if (removeLeases.length > 0) {
          $rootScope.$broadcast('events:rights-category:delete-leases', {
            catLeases: removeLeases,
            batch: false
          });
        }
        return;
      }
      $rootScope.$broadcast('events:rights-category:add-leases', {
        catLeases: catLeases,
        batch: false
      });
    }

    function batchApplyUsageRights() {
      $rootScope.$broadcast(batchApplyUsageRightsEvent, {
          data: ctrl.usageRights.data
      });

      //-rights category derived leases-
      const mtchingRightsCats = ctrl.categories.filter(c => c.value == ctrl.usageRights.data.category);
      if (mtchingRightsCats.length > 0) {
        const rightsCat = mtchingRightsCats[0];
        if (rightsCat.leases.length > 0) {
          const catLeases = createCategoryLeases(rightsCat.leases, ctrl.image);
          if (catLeases.length > 0) {
            $rootScope.$broadcast('events:rights-category:add-leases', {
              catLeases: catLeases,
              batch: true
            });
          }
        }
      }
    }

    function openCollectionTree() {
        ctrl.addCollection = true;

        collections.getCollections().then(collections => {
            ctrl.collections = collections.data.children;
            // this will trigger the remember-scroll-top directive to return
            // users to their previous position on the collections panel
            // once the tree has been rendered
            $timeout(() => {
                $scope.$broadcast('gr:remember-scroll-top:apply');
            });
        }, () => {
            // TODO: More informative error handling
            // TODO: Stop error propagating to global error handler
            ctrl.error = true;
        }).catch(() => ctrl.collectionError = true);

    }

    function addToCollection(collection) {
        collections.addCollectionToImage(ctrl.image, collection);
        //this isn't needed when called from batch apply
        ctrl.addCollection = false;
    }

    function removeImageFromCollection(collection) {
        collections.removeImageFromCollection(collection, ctrl.image);
    }

    function batchApplyCollections() {
        const collectionsOnImage = ctrl.image.data.collections.map(collection =>
                collection.data.path);

        if (collectionsOnImage.length > 0) {
            $rootScope.$broadcast(batchApplyCollectionsEvent, { collections: collectionsOnImage } );
        } else {
            ctrl.confirmDelete = true;

            $timeout(() => {
                ctrl.confirmDelete = false;
            }, 5000);
        }

        ctrl.batchRemoveCollections = () => {
            $rootScope.$broadcast(batchRemoveCollectionsEvent);
        };

    }

    function getCollectionStyle(collection) {
        return collection.data.cssColour && `background-color: ${collection.data.cssColour}`;
    }

    function undelete() {
        const imageId = ctrl.image.data.id;
        mediaApi.undelete(imageId).then(
            ctrl.canUndelete = ctrl.isDeleted = false
        );
    }

    ctrl.srefNonfree = () => storage.getJs("isNonFree", true) ? true : undefined;
  };
}]);