function()

in kahuna/public/js/crop/controller.js [29:226]


  function(
    $scope,
    $rootScope,
    $stateParams,
    $state,
    mediaApi,
    mediaCropper,
    image,
    optimisedImageUri,
    keyboardShortcut,
    defaultCrop,
    cropSettings,
    square,
    freeform,
    pollUntilCropCreated) {

      const ctrl = this;
      const imageId = $stateParams.imageId;

    cropSettings.set($stateParams);
      const allCropOptions = cropSettings.getCropOptions();

      const storageCropType = cropSettings.getCropType();
      const storageDefaultCropType = cropSettings.getDefaultCropType();

    ctrl.cropOptions = allCropOptions
        .filter(option => (!storageCropType || storageCropType === option.key) && !option.isHidden )
        .map(option => Object.assign(option, {
          value: option.ratioString ? `${option.key} (${option.ratioString})` : option.key,
          minimalValue: option.ratioString || option.key,
          tooltip: `${option.key} [${option.key.charAt(0)}]`,
          disabled: storageCropType && storageCropType !== option.key
        }));

      ctrl.cropType = storageCropType || storageDefaultCropType || defaultCrop.key;

      ctrl.image = image;
      ctrl.optimisedImageUri = optimisedImageUri;

      ctrl.cropping = false;

      const originalDimensions = image.data.source.dimensions;
      ctrl.originalWidth  = originalDimensions.width;
      ctrl.originalHeight = originalDimensions.height;

      ctrl.maxInputX = () =>
        ctrl.originalWidth - ctrl.cropWidth();

      ctrl.maxInputY = () =>
        ctrl.originalHeight - ctrl.cropHeight();

      ctrl.coords = {
        x1: ctrl.inputX,
        y1: ctrl.inputY,
        // fill the image with the selection
        x2: ctrl.originalWidth,
        y2: ctrl.originalHeight
      };

      // If we have a square crop, remove any jitter introduced by client lib by using only one side
      if (ctrl.cropType === square.key) {
        const sideLength = () => Math.round(ctrl.coords.x2 - ctrl.coords.x1);
        ctrl.cropWidth = sideLength;
        ctrl.cropHeight = sideLength;
      } else {
        ctrl.cropWidth = () => Math.round(ctrl.coords.x2 - ctrl.coords.x1);
        ctrl.cropHeight = () => Math.round(ctrl.coords.y2 - ctrl.coords.y1);
      }


      ctrl.cropX = () => Math.round(ctrl.coords.x1);
      ctrl.cropY = () => Math.round(ctrl.coords.y1);

      ctrl.inputX = parseInt(ctrl.cropX());
      ctrl.inputY = parseInt(ctrl.cropY());

      ctrl.inputWidth = parseInt(ctrl.cropWidth());
      ctrl.inputHeight = parseInt(ctrl.cropHeight());

      ctrl.broadcastHeightChange = function (){
        $scope.$broadcast('user-height-change', ctrl.inputHeight);
      };
      ctrl.broadcastWidthChange = function (){
        $scope.$broadcast('user-width-change', ctrl.inputWidth);
      };
      ctrl.broadcastXChange = function (){
        $scope.$broadcast('user-x-change', ctrl.inputX);
      };
      ctrl.broadcastYChange = function (){
        $scope.$broadcast('user-y-change', ctrl.inputY);
      };

      //make the view match the ctrl value
      $scope.$watch(function(){ return ctrl.cropWidth(); }, function(){
        ctrl.inputWidth = ctrl.cropWidth();
      });
      $scope.$watch(function(){ return ctrl.cropHeight(); }, function(){
        ctrl.inputHeight = ctrl.cropHeight();
      });
      $scope.$watch(function(){ return ctrl.cropX(); }, function(){
        ctrl.inputX = ctrl.cropX();
      });
      $scope.$watch(function(){ return ctrl.cropY(); }, function(){
        ctrl.inputY = ctrl.cropY();
      });

      ctrl.cropSizeWarning = () => ctrl.cropWidth() < 1000;

      function crop() {
        // TODO: show crop
        const coords = {
          x: Math.round(ctrl.coords.x1),
          y: Math.round(ctrl.coords.y1),
          width:  ctrl.cropWidth(),
          height: ctrl.cropHeight()
        };

        const ratioString = ctrl.cropOptions.find(_ => _.key === ctrl.cropType).ratioString;

        ctrl.cropping = true;

        mediaCropper.createCrop(ctrl.image, coords, ratioString)
        .then(crop => {
           // Global notification of action
           $rootScope.$emit('events:crop-created', {
             image: ctrl.image,
             crop: crop
           });
           return crop.data.id;
        })
        .then(cropId => pollUntilCropCreated(ctrl.image, cropId).then(() => {
            $state.go('image', {
                imageId: imageId,
                crop: cropId
            });
        }))
        .finally(() => {
          ctrl.cropping = false;
        });
      }

      ctrl.callCrop = function() {
        //prevents return keypress on the crop button posting crop twice
        if (!ctrl.cropping) {
          crop();
        }
      };

      $scope.$watch('ctrl.cropType', (newCropType, oldCropType) => {
        const isCropTypeDisabled = ctrl.cropOptions.find(_ => _.key === newCropType).disabled;

        const maybeCropRatioIfStandard = cropOptions.find(_ => _.key === ctrl.cropType)?.ratioString;
        ctrl.shouldShowVerticalWarningGutters =
          window._clientConfig.staffPhotographerOrganisation === "GNM"
          && maybeCropRatioIfStandard === "5:3";

        ctrl.shouldShowCircularGuideline =
          window._clientConfig.staffPhotographerOrganisation === "GNM"
          // update this array to apply circular guideline to further ratios (e.g. 5:4)
          && ["square"].includes(ctrl.cropType.toLowerCase());

        ctrl.isSquareCrop = ctrl.cropType.toLowerCase() === "square";

        if (isCropTypeDisabled) {
          ctrl.cropType = oldCropType;
        } else {
          if (newCropType === freeform.key) {
            ctrl.coords = {
              x1: ctrl.inputX,
              y1: ctrl.inputY,
              // fill the image with the selection
              x2: ctrl.originalWidth,
              y2: ctrl.originalHeight
            };
          }
        }
      });

      keyboardShortcut.bindTo($scope)
        .add({
          combo: 'esc',
          description: 'Cancel crop and return to image',
          callback: () => $state.go('image', {imageId: ctrl.image.data.id})
        })
        .add({
          combo: 'enter',
          description: 'Create crop',
          callback: () => ctrl.callCrop()
        });

      cropSettings.getCropOptions().forEach(option => {
        keyboardShortcut.bindTo($scope).add({
          combo: option.key.charAt(0),
          description: `Start ${option.key} crop`,
          callback: () => ctrl.cropType = option.key
        });
      });
    }]);