Fixes: Deal with invariant property value syncing, componentizes umb-image-gravity, gets the image cropper syncing data correctly, ensures resizing for image cropper is done when variants change.
This commit is contained in:
@@ -32,6 +32,9 @@
|
||||
"rightIsOpen": false
|
||||
};
|
||||
|
||||
$scope.initVariant = initVariant;
|
||||
$scope.splitViewChanged = splitViewChanged;
|
||||
|
||||
function init(content) {
|
||||
|
||||
if (infiniteMode) {
|
||||
@@ -61,6 +64,12 @@
|
||||
setActiveCulture();
|
||||
}
|
||||
|
||||
/** This is called when the split view changes based on the umb-variant-content */
|
||||
function splitViewChanged() {
|
||||
//send an event downwards
|
||||
$scope.$broadcast("editors.content.splitViewChanged", { editors: $scope.editors });
|
||||
}
|
||||
|
||||
/**
|
||||
* The content item(s) are loaded into an array and this will set the active content item based on the current culture (query string).
|
||||
* If the content item is invariant, then only one item exists in the array.
|
||||
@@ -556,8 +565,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.initVariant = initVariant;
|
||||
|
||||
/* publish method used in infinite editing */
|
||||
$scope.publishAndClose = function (content) {
|
||||
$scope.publishAndCloseButtonState = "busy";
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
$timeout(function () {
|
||||
editor.collapsed = false;
|
||||
editor.loading = false;
|
||||
scope.onSplitViewChanged();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
@@ -97,6 +98,7 @@
|
||||
return e === scope.editor;
|
||||
});
|
||||
scope.editors.splice(index, 1);
|
||||
scope.onSplitViewChanged();
|
||||
}, 400);
|
||||
};
|
||||
|
||||
@@ -110,13 +112,16 @@
|
||||
|
||||
},
|
||||
scope: {
|
||||
//TODO: This should be turned into a proper component
|
||||
|
||||
page: "=",
|
||||
content: "=",
|
||||
editor: "=",
|
||||
editors: "=",
|
||||
//TODO: I don't like having this callback defined and would like to make this directive a bit less
|
||||
// coupled but right now don't have time
|
||||
initVariant: "&"
|
||||
initVariant: "&",
|
||||
onSplitViewChanged: "&"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ angular.module("umbraco.directives")
|
||||
});
|
||||
|
||||
//ie hack
|
||||
if(window.navigator.userAgent.indexOf("MSIE ")){
|
||||
if(window.navigator.userAgent.indexOf("MSIE ") >= 0){
|
||||
var ranger = element.find("input");
|
||||
ranger.bind("change",function(){
|
||||
scope.$apply(function(){
|
||||
|
||||
@@ -1,139 +1,197 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbImageGravity
|
||||
* @restrict E
|
||||
* @function
|
||||
* @description
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbImageGravity', function ($timeout, localizationService, $log) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/imaging/umb-image-gravity.html',
|
||||
scope: {
|
||||
src: '=',
|
||||
center: "=",
|
||||
onImageLoaded: "&?"
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
//Internal values for keeping track of the dot and the size of the editor
|
||||
scope.dimensions = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
function umbImageGravityController($scope, $element, $timeout) {
|
||||
|
||||
scope.loaded = false;
|
||||
var vm = this;
|
||||
|
||||
//elements
|
||||
var $viewport = element.find(".viewport");
|
||||
var $image = element.find("img");
|
||||
var $overlay = element.find(".overlay");
|
||||
//Internal values for keeping track of the dot and the size of the editor
|
||||
vm.dimensions = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
|
||||
scope.style = function () {
|
||||
if(scope.dimensions.width <= 0){
|
||||
setDimensions();
|
||||
}
|
||||
var htmlImage = null; //DOM element reference
|
||||
var htmlOverlay = null; //DOM element reference
|
||||
var draggable = null;
|
||||
|
||||
return {
|
||||
'top': scope.dimensions.top + 'px',
|
||||
'left': scope.dimensions.left + 'px'
|
||||
};
|
||||
};
|
||||
vm.loaded = false;
|
||||
vm.$onInit = onInit;
|
||||
vm.$onChanges = onChanges;
|
||||
vm.$postLink = postLink;
|
||||
vm.$onDestroy = onDestroy;
|
||||
vm.style = style;
|
||||
vm.setFocalPoint = setFocalPoint;
|
||||
|
||||
scope.setFocalPoint = function(event) {
|
||||
/** Sets the css style for the Dot */
|
||||
function style() {
|
||||
|
||||
scope.$emit("imageFocalPointStart");
|
||||
if (vm.dimensions.width <= 0) {
|
||||
//this initializes the dimensions since when the image element first loads
|
||||
//there will be zero dimensions
|
||||
setDimensions();
|
||||
}
|
||||
|
||||
var offsetX = event.offsetX - 10;
|
||||
var offsetY = event.offsetY - 10;
|
||||
return {
|
||||
'top': vm.dimensions.top + 'px',
|
||||
'left': vm.dimensions.left + 'px'
|
||||
};
|
||||
};
|
||||
|
||||
calculateGravity(offsetX, offsetY);
|
||||
function setFocalPoint (event) {
|
||||
|
||||
lazyEndEvent();
|
||||
$scope.$emit("imageFocalPointStart");
|
||||
|
||||
};
|
||||
var offsetX = event.offsetX - 10;
|
||||
var offsetY = event.offsetY - 10;
|
||||
|
||||
var setDimensions = function(){
|
||||
scope.dimensions.width = $image.width();
|
||||
scope.dimensions.height = $image.height();
|
||||
calculateGravity(offsetX, offsetY);
|
||||
|
||||
if(scope.center){
|
||||
scope.dimensions.left = scope.center.left * scope.dimensions.width -10;
|
||||
scope.dimensions.top = scope.center.top * scope.dimensions.height -10;
|
||||
}else{
|
||||
scope.center = { left: 0.5, top: 0.5 };
|
||||
}
|
||||
};
|
||||
lazyEndEvent();
|
||||
|
||||
var calculateGravity = function(offsetX, offsetY){
|
||||
scope.dimensions.left = offsetX;
|
||||
scope.dimensions.top = offsetY;
|
||||
};
|
||||
|
||||
scope.center.left = (scope.dimensions.left+10) / scope.dimensions.width;
|
||||
scope.center.top = (scope.dimensions.top+10) / scope.dimensions.height;
|
||||
};
|
||||
/** Initializes the component */
|
||||
function onInit() {
|
||||
if (!vm.center) {
|
||||
vm.center = { left: 0.5, top: 0.5 };
|
||||
}
|
||||
}
|
||||
|
||||
var lazyEndEvent = _.debounce(function(){
|
||||
scope.$apply(function(){
|
||||
scope.$emit("imageFocalPointStop");
|
||||
});
|
||||
}, 2000);
|
||||
/** Called when the component has linked everything and the DOM is available */
|
||||
function postLink() {
|
||||
//elements
|
||||
htmlImage = $element.find("img");
|
||||
htmlOverlay = $element.find(".overlay");
|
||||
|
||||
|
||||
//Drag and drop positioning, using jquery ui draggable
|
||||
//TODO ensure that the point doesnt go outside the box
|
||||
$overlay.draggable({
|
||||
containment: "parent",
|
||||
start: function(){
|
||||
scope.$apply(function(){
|
||||
scope.$emit("imageFocalPointStart");
|
||||
});
|
||||
},
|
||||
stop: function() {
|
||||
scope.$apply(function(){
|
||||
var offsetX = $overlay[0].offsetLeft;
|
||||
var offsetY = $overlay[0].offsetTop;
|
||||
calculateGravity(offsetX, offsetY);
|
||||
});
|
||||
|
||||
lazyEndEvent();
|
||||
}
|
||||
});
|
||||
|
||||
//// INIT /////
|
||||
$image.load(function() {
|
||||
$timeout(function() {
|
||||
setDimensions();
|
||||
scope.loaded = true;
|
||||
if (scope.onImageLoaded) {
|
||||
scope.onImageLoaded();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(window).on('resize.umbImageGravity', function(){
|
||||
scope.$apply(function(){
|
||||
$timeout(function(){
|
||||
setDimensions();
|
||||
});
|
||||
// Make sure we can find the offset values for the overlay(dot) before calculating
|
||||
// fixes issue with resize event when printing the page (ex. hitting ctrl+p inside the rte)
|
||||
if($overlay.is(':visible')) {
|
||||
var offsetX = $overlay[0].offsetLeft;
|
||||
var offsetY = $overlay[0].offsetTop;
|
||||
calculateGravity(offsetX, offsetY);
|
||||
}
|
||||
});
|
||||
//Drag and drop positioning, using jquery ui draggable
|
||||
draggable = htmlOverlay.draggable({
|
||||
containment: "parent",
|
||||
start: function () {
|
||||
$scope.$apply(function () {
|
||||
$scope.$emit("imageFocalPointStart");
|
||||
});
|
||||
},
|
||||
stop: function () {
|
||||
$scope.$apply(function () {
|
||||
var offsetX = htmlOverlay[0].offsetLeft;
|
||||
var offsetY = htmlOverlay[0].offsetTop;
|
||||
calculateGravity(offsetX, offsetY);
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
$(window).off('.umbImageGravity');
|
||||
});
|
||||
lazyEndEvent();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
$(window).on('resize.umbImageGravity', function () {
|
||||
$scope.$apply(function () {
|
||||
resized();
|
||||
});
|
||||
});
|
||||
|
||||
//if any ancestor directive emits this event, we need to resize
|
||||
$scope.$on("editors.content.splitViewChanged", function () {
|
||||
$timeout(resized, 200);
|
||||
});
|
||||
|
||||
//listen for the image DOM element loading
|
||||
htmlImage.on("load", function () {
|
||||
$timeout(function () {
|
||||
setDimensions();
|
||||
vm.loaded = true;
|
||||
if (vm.onImageLoaded) {
|
||||
vm.onImageLoaded();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function onDestroy() {
|
||||
$(window).off('resize.umbImageGravity');
|
||||
if (htmlOverlay) {
|
||||
//TODO: This should be destroyed but this will throw an exception:
|
||||
// "cannot call methods on draggable prior to initialization; attempted to call method 'destroy'"
|
||||
// I've tried lots of things and cannot get this to work, we weren't destroying before so hopefully
|
||||
// there's no mem leaks?
|
||||
//htmlOverlay.draggable("destroy");
|
||||
}
|
||||
if (htmlImage) {
|
||||
htmlImage.off("load");
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when we need to resize based on window or DOM dimensions to re-center the focal point */
|
||||
function resized() {
|
||||
$timeout(function () {
|
||||
setDimensions();
|
||||
});
|
||||
// Make sure we can find the offset values for the overlay(dot) before calculating
|
||||
// fixes issue with resize event when printing the page (ex. hitting ctrl+p inside the rte)
|
||||
if (htmlOverlay.is(':visible')) {
|
||||
var offsetX = htmlOverlay[0].offsetLeft;
|
||||
var offsetY = htmlOverlay[0].offsetTop;
|
||||
calculateGravity(offsetX, offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
/** Watches the one way binding changes */
|
||||
function onChanges(changes) {
|
||||
if (changes.center && !changes.center.isFirstChange() && !angular.equals(changes.center.currentValue, changes.center.previousValue)) {
|
||||
//when center changes update the dimensions
|
||||
setDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the width/height/left/top dimentions based on the image size and the "center" value */
|
||||
function setDimensions() {
|
||||
if (htmlImage) {
|
||||
vm.dimensions.width = htmlImage.width();
|
||||
vm.dimensions.height = htmlImage.height();
|
||||
vm.dimensions.left = vm.center.left * vm.dimensions.width - 10;
|
||||
vm.dimensions.top = vm.center.top * vm.dimensions.height - 10;
|
||||
}
|
||||
return vm.dimensions.width;
|
||||
};
|
||||
|
||||
/**
|
||||
* based on the offset selected calculates the "center" value and calls the callback
|
||||
* @param {any} offsetX
|
||||
* @param {any} offsetY
|
||||
*/
|
||||
function calculateGravity(offsetX, offsetY) {
|
||||
|
||||
vm.onValueChanged({
|
||||
left: (offsetX + 10) / vm.dimensions.width,
|
||||
top: (offsetY + 10) / vm.dimensions.height
|
||||
});
|
||||
|
||||
//vm.center.left = (offsetX + 10) / scope.dimensions.width;
|
||||
//vm.center.top = (offsetY + 10) / scope.dimensions.height;
|
||||
};
|
||||
|
||||
var lazyEndEvent = _.debounce(function () {
|
||||
$scope.$apply(function () {
|
||||
$scope.$emit("imageFocalPointStop");
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
var umbImageGravityComponent = {
|
||||
templateUrl: 'views/components/imaging/umb-image-gravity.html',
|
||||
bindings: {
|
||||
src: "<",
|
||||
center: "<",
|
||||
onImageLoaded: "&?",
|
||||
onValueChanged: "&"
|
||||
},
|
||||
controllerAs: 'vm',
|
||||
controller: umbImageGravityController
|
||||
};
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.component('umbImageGravity', umbImageGravityComponent);
|
||||
|
||||
})();
|
||||
|
||||
@@ -276,7 +276,7 @@
|
||||
controller: umbPropertyFileUploadController
|
||||
};
|
||||
|
||||
angular.module("umbraco")
|
||||
angular.module("umbraco.directives")
|
||||
.component('umbPropertyFileUpload', umbPropertyFileUploadComponent);
|
||||
|
||||
})();
|
||||
|
||||
@@ -345,12 +345,15 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
|
||||
getBlueprintById: function (id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetBlueprintById",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve data for content id ' + id);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetBlueprintById",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve data for content id ' + id)
|
||||
.then(function(result) {
|
||||
return $q.when(umbDataFormatter.formatContentGetData(result));
|
||||
});
|
||||
},
|
||||
|
||||
getNotifySettingsById: function (id) {
|
||||
@@ -405,12 +408,19 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
});
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetByIds",
|
||||
idQuery)),
|
||||
'Failed to retrieve data for content with multiple ids');
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetByIds",
|
||||
idQuery)),
|
||||
'Failed to retrieve data for content with multiple ids')
|
||||
.then(function (result) {
|
||||
//each item needs to be re-formatted
|
||||
_.each(result, function(r) {
|
||||
umbDataFormatter.formatContentGetData(r)
|
||||
});
|
||||
return $q.when(result);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -449,23 +459,29 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
getScaffold: function (parentId, alias) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmpty",
|
||||
[{ contentTypeAlias: alias }, { parentId: parentId }])),
|
||||
'Failed to retrieve data for empty content item type ' + alias);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmpty",
|
||||
[{ contentTypeAlias: alias }, { parentId: parentId }])),
|
||||
'Failed to retrieve data for empty content item type ' + alias)
|
||||
.then(function(result) {
|
||||
return $q.when(umbDataFormatter.formatContentGetData(result));
|
||||
});
|
||||
},
|
||||
|
||||
getBlueprintScaffold: function (parentId, blueprintId) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmpty",
|
||||
[{ blueprintId: blueprintId }, { parentId: parentId }])),
|
||||
'Failed to retrieve blueprint for id ' + blueprintId);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmpty",
|
||||
[{ blueprintId: blueprintId }, { parentId: parentId }])),
|
||||
'Failed to retrieve blueprint for id ' + blueprintId)
|
||||
.then(function(result) {
|
||||
return $q.when(umbDataFormatter.formatContentGetData(result));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -248,6 +248,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
|
||||
formHelper.showNotifications(response.data);
|
||||
|
||||
//TODO: We need to pass the result through umbDataFormatter.formatContentGetData!
|
||||
|
||||
//the data returned is the up-to-date data so the UI will refresh
|
||||
return $q.resolve(response.data);
|
||||
}, function (response) {
|
||||
|
||||
@@ -570,7 +570,7 @@ ul.color-picker li {
|
||||
.imagecropper .umb-cropper__container {
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
max-width: 100%;
|
||||
max-width: 100%;
|
||||
border: 1px solid @gray-10;
|
||||
|
||||
@media (min-width: 769px) {
|
||||
@@ -583,7 +583,7 @@ ul.color-picker li {
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
z-index: @zindexCropperOverlay + 1;
|
||||
}
|
||||
|
||||
.umb-close-cropper:hover {
|
||||
|
||||
@@ -177,4 +177,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
content="content"
|
||||
editor="editor"
|
||||
editors="editors"
|
||||
init-variant="initVariant(variant)">
|
||||
init-variant="initVariant(variant)"
|
||||
on-split-view-changed="splitViewChanged()">
|
||||
</umb-variant-content>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<div class="umb-cropper-gravity">
|
||||
<div class="gravity-container" ng-show="loaded">
|
||||
|
||||
<div class="gravity-container" ng-show="vm.loaded">
|
||||
<div class="viewport">
|
||||
<img ng-src="{{src}}" style="max-width: 100%; max-height: 100%" ng-click="setFocalPoint($event)" draggable="false" />
|
||||
<img ng-src="{{vm.src}}" style="max-width: 100%; max-height: 100%" ng-click="vm.setFocalPoint($event)" draggable="false" />
|
||||
|
||||
<div class="overlay" ng-style="style()">
|
||||
<div class="overlay" ng-style="vm.style()">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,9 +9,26 @@ angular.module('umbraco')
|
||||
$scope.crop = crop;
|
||||
$scope.done = done;
|
||||
$scope.clear = clear;
|
||||
$scope.focalPointChanged = focalPointChanged;
|
||||
//declare a special method which will be called whenever the value has changed from the server
|
||||
$scope.model.onValueChanged = onValueChanged;
|
||||
|
||||
/**
|
||||
* Called when the umgImageGravity component updates the focal point value
|
||||
* @param {any} left
|
||||
* @param {any} top
|
||||
*/
|
||||
function focalPointChanged(left, top) {
|
||||
//update the model focalpoint value
|
||||
$scope.model.value.focalPoint = {
|
||||
left: left,
|
||||
top: top
|
||||
};
|
||||
|
||||
//set form to dirty to track changes
|
||||
$scope.imageCropperForm.$setDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to assign a new model value
|
||||
* @param {any} src
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
</div>
|
||||
|
||||
<div ng-if="!currentCrop" class="umb-cropper-imageholder clearfix">
|
||||
<pre><code>{{model.value.focalPoint | json}}</code></pre>
|
||||
<umb-image-gravity src="imageSrc"
|
||||
center="model.value.focalPoint">
|
||||
center="model.value.focalPoint"
|
||||
on-value-changed="focalPointChanged(left, top)">
|
||||
</umb-image-gravity>
|
||||
<a href class="btn btn-link btn-crop-delete" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user