UNPKG

koco-xyz

Version:

Dialogs for displaying, choosing, and editing images provided in scoop idiom.

337 lines (263 loc) 9.86 kB
import template from 'text!./cloudinary-image-editor.html'; import ko from 'knockout'; import _ from 'lodash'; import imageUtilities from 'image-utilities'; import koMappingUtilities from 'mapping-utilities'; import KoDisposer from 'disposer'; var CloudinaryImagePicker = function(params /*, componentInfo*/ ) { var self = this; self.defaultWidthTransformation = 300; self.koDisposer = new KoDisposer(); //TODO: Load from server (API) self.dimensionConfigsForKnownRatios = [{ ratio: '4:3', dimensions: [ '80x60', '100x75', '180x135', '300x225' ], defaultWidthTransformation: 300 }, { ratio: '16:9', dimensions: [ '64x36', '98x55', '112x63', '135x76', '160x90', '205x115', '240x135', '300x169', '310x174', '352x198', '420x236', '480x270', '635x357' ], defaultWidthTransformation: 635 }]; self.observableSelectedImage = params.selectedImage; self.selectedImage = koMappingUtilities.toJS(params.selectedImage); self.selectedConcreteImage = koMappingUtilities.toJS(params.selectedConcreteImage); var ratios = getRatios(self.selectedImage); self.ratios = ko.observableArray(ratios); var ratioId; var widthTransformation = null; if (self.selectedConcreteImage) { ratioId = self.selectedConcreteImage.dimensionRatio; widthTransformation = imageUtilities.getWidthTransformationFromCloudinaryUrl(self.selectedConcreteImage.mediaLink.href); } else { ratioId = ratios[0].id; } self.ratio = ko.observable(ratioId); var dimensionConfigs = getDimensionConfigsForCurrentRatio(ratioId, self.dimensionConfigsForKnownRatios); self.selectedConcreteImage = getTransformedConcreteImage(self, params, dimensionConfigs, widthTransformation); params.selectedConcreteImage(self.selectedConcreteImage); self.widthObservable = function(initialValue) { var _actual = ko.observable(initialValue); var result = ko.pureComputed({ read: function() { return _actual(); }, write: function(newValue) { var parsed = parseFloat(newValue); var previous = _actual(); if (isNaN(parsed) || parsed < 0 || parsed > self.sourceConcreteImg.width) { //_actual.valueHasMutated(); _actual.notifySubscribers(previous); //self.width.valueHasMutated(); } else { _actual(parsed); } } }).extend({ notify: 'always' }); result.valueHasMutated = function() { _actual.valueHasMutated(); }; self.koDisposer.add(result); return result; }; self.width = self.widthObservable(self.selectedConcreteImage.width); self.height = ko.observable(self.selectedConcreteImage.height); self.dimensions = ko.observableArray(); self.dimension = ko.observable(); var ratioHasChanged = true; var ignoreRatioModification = false; var ignoreDimensionModification = false; updateDimensionsInfo(self, dimensionConfigs); self.koDisposer.add(self.dimension.subscribe(function() { if (ignoreDimensionModification) { ignoreDimensionModification = false; } else { var selectedDimension = self.dimension(); var dimension = getDimensionFromString(selectedDimension, 'x'); if (dimension) { self.width(dimension.width); } } })); self.koDisposer.add(self.width.subscribe(function() { var width = self.width(); ratioId = self.ratio(); dimensionConfigs = getDimensionConfigsForCurrentRatio(ratioId, self.dimensionConfigsForKnownRatios); self.selectedConcreteImage = getTransformedConcreteImage(self, params, dimensionConfigs, width); self.height(self.selectedConcreteImage.height); ignoreDimensionModification = true; updateDimensionsInfo(self, dimensionConfigs); params.selectedConcreteImage(self.selectedConcreteImage); })); self.koDisposer.add(params.$raw.selectedImage.subscribe(function() { self.selectedImage = koMappingUtilities.toJS(params.selectedImage); var currentRatio = self.ratio(); ratios = getRatios(self.selectedImage); if (_.any(ratios, function(rat) { return rat.id == currentRatio; })) { ratioHasChanged = false; self.ratios(ratios); self.ratio.valueHasMutated(); } else { ignoreRatioModification = true; self.ratios(ratios); self.ratio(ratios[0].id); } })); self.koDisposer.add(self.ratio.subscribe(function() { if (ignoreRatioModification) { ignoreRatioModification = false; } else { ratioId = self.ratio(); if (ratioHasChanged) { dimensionConfigs = getDimensionConfigsForCurrentRatio(ratioId, self.dimensionConfigsForKnownRatios); self.selectedConcreteImage = getTransformedConcreteImage(self, params, dimensionConfigs); if (self.width() == self.selectedConcreteImage.width) { self.width.valueHasMutated(); } else { self.width(self.selectedConcreteImage.width); } } else { ratioHasChanged = true; self.width.valueHasMutated(); } } })); return self; }; function updateDimensionsInfo(self, dimensionConfigs) { var dimensions = dimensionConfigs.dimensions; var dimensionId = getDimensionIdFromWidthAndHeight(dimensions, self.selectedConcreteImage.width, self.selectedConcreteImage.height); if (dimensionId == 'custom') { dimensions.push({ id: 'custom', name: 'dimension personnalisée' }); } self.dimensions(dimensions); self.dimension(dimensionId); } function getTransformedConcreteImage(self, args, dimensionConfigs, widthTransformation) { self.sourceConcreteImg = imageUtilities.getConcreteImage(self.selectedImage, { preferedRatio: dimensionConfigs.ratio, defaultToClosestDimension: false }); if (!widthTransformation) { widthTransformation = dimensionConfigs.defaultWidthTransformation || self.defaultWidthTransformation; } var href = imageUtilities.updateCloudinaryUrlWidthTransformation(self.sourceConcreteImg.mediaLink.href, widthTransformation); var height = getHeightFromWidthAndRatio(widthTransformation, dimensionConfigs.ratio); return { dimensionRatio: dimensionConfigs.ratio, mediaLink: { href: href }, width: widthTransformation, height: height }; } function getDimensionIdFromWidthAndHeight(dimensions, width, height) { if (dimensions.length) { var dimId = width + 'x' + height; var dimension = _.find(dimensions, function(dim) { return dim.id == dimId; }); if (dimension) { return dimension.id; } else { return 'custom'; } } return ''; } function getRatios(conceptualImage) { var ratios = []; if (conceptualImage && conceptualImage.concreteImages && conceptualImage.concreteImages.length) { for (var i = 0; i < conceptualImage.concreteImages.length; i++) { var concreteImage = conceptualImage.concreteImages[i]; ratios.push({ name: concreteImage.dimensionRatio, id: concreteImage.dimensionRatio }); } } return ratios; } function getDimensionConfigsForCurrentRatio(ratio, dimensionConfigsForKnownRatios) { var dimensionConfigsForCurrentRatio = _.find(dimensionConfigsForKnownRatios, function(dimensionConfigsForKnownRatio) { return dimensionConfigsForKnownRatio.ratio == ratio; }); var dimensions = []; var defaultWidthTransformation = ''; if (dimensionConfigsForCurrentRatio) { dimensions = dimensionConfigsForCurrentRatio.dimensions; defaultWidthTransformation = dimensionConfigsForCurrentRatio.defaultWidthTransformation; } var result = { dimensions: _.map(dimensions, function(dimension) { return { id: dimension, name: dimension }; }), defaultWidthTransformation: defaultWidthTransformation, ratio: ratio }; //result.dimensions.push({ id: 'custom', name: 'dimension personnalisée' }); return result; } function getHeightFromWidthAndRatio(width, ratio) { var dimension = getDimensionFromString(ratio, ':'); if (dimension) { var height = width * dimension.height / dimension.width; return Math.round(height); } return null; } function getDimensionFromString(string, separator) { if (!string || string == 'custom') { return null; } var x = string.split(separator); if (x.length && x[0] && x[1]) { return { width: parseInt(x[0]), height: parseInt(x[1]) }; } return null; } CloudinaryImagePicker.prototype.dispose = function() { var self = this; self.koDisposer.dispose(); }; export default { viewModel: { createViewModel: function(params, componentInfo) { return new CloudinaryImagePicker(params, componentInfo); } }, template: template };