Merge remote-tracking branch 'origin/7.1.0-ImageCropper-WIP' into 7.1.0
This commit is contained in:
@@ -139,7 +139,7 @@ namespace Umbraco.Core
|
|||||||
///// <summary>
|
///// <summary>
|
||||||
///// Alias for the Image Cropper datatype.
|
///// Alias for the Image Cropper datatype.
|
||||||
///// </summary>
|
///// </summary>
|
||||||
//public const string ImageCropperAlias = "Umbraco.ImageCropper";
|
public const string ImageCropperAlias = "Umbraco.ImageCropper";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Guid for the Integer datatype.
|
/// Guid for the Integer datatype.
|
||||||
|
|||||||
BIN
src/Umbraco.Web.UI.Client/src/assets/img/mocks/big-image.jpg
Normal file
BIN
src/Umbraco.Web.UI.Client/src/assets/img/mocks/big-image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 309 KiB |
BIN
src/Umbraco.Web.UI.Client/src/assets/img/mocks/big-thumb.jpg
Normal file
BIN
src/Umbraco.Web.UI.Client/src/assets/img/mocks/big-thumb.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
@@ -5,21 +5,21 @@
|
|||||||
* @function
|
* @function
|
||||||
**/
|
**/
|
||||||
angular.module("umbraco.directives")
|
angular.module("umbraco.directives")
|
||||||
.directive('umbImageCrop', function ($timeout, localizationService, $log) {
|
.directive('umbImageCrop',
|
||||||
|
function ($timeout, localizationService, cropperHelper, $log) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
replace: true,
|
replace: true,
|
||||||
templateUrl: 'views/directives/imaging/umb-image-crop.html',
|
templateUrl: 'views/directives/imaging/umb-image-crop.html',
|
||||||
scope: {
|
scope: {
|
||||||
src: '=',
|
src: '=',
|
||||||
width: '=',
|
width: '@',
|
||||||
height: '=',
|
height: '@',
|
||||||
crop: "="
|
crop: "=",
|
||||||
|
center: "=",
|
||||||
},
|
},
|
||||||
|
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
|
|
||||||
scope.scale = 100;
|
|
||||||
|
|
||||||
//if image is over this, we re-calculate the editors global ratio
|
//if image is over this, we re-calculate the editors global ratio
|
||||||
//this will not have an effect on the result, since that is returned in percentage
|
//this will not have an effect on the result, since that is returned in percentage
|
||||||
scope.maxHeight = 500;
|
scope.maxHeight = 500;
|
||||||
@@ -32,17 +32,23 @@ angular.module("umbraco.directives")
|
|||||||
image: {},
|
image: {},
|
||||||
cropper:{},
|
cropper:{},
|
||||||
viewport:{},
|
viewport:{},
|
||||||
margin: 20,
|
margin: 40,
|
||||||
ratio: 1
|
scale: {
|
||||||
|
min: 0.3,
|
||||||
|
max: 3,
|
||||||
|
current: 1
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.style = function () {
|
|
||||||
return {
|
|
||||||
'height': (parseInt(scope.height, 10) + 2 * scope.dimensions.margin) + 'px',
|
|
||||||
'width': (parseInt(scope.width, 10) + 2 * scope.dimensions.margin) + 'px'
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
//live rendering of viewport and image styles
|
||||||
|
scope.style = function () {
|
||||||
|
return {
|
||||||
|
'height': (parseInt(scope.height, 10) + 2 * scope.dimensions.margin) + 'px',
|
||||||
|
'width': (parseInt(scope.width, 10) + 2 * scope.dimensions.margin) + 'px'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//elements
|
//elements
|
||||||
var $viewport = element.find(".viewport");
|
var $viewport = element.find(".viewport");
|
||||||
@@ -51,11 +57,31 @@ angular.module("umbraco.directives")
|
|||||||
var $container = element.find(".crop-container");
|
var $container = element.find(".crop-container");
|
||||||
|
|
||||||
//default constraints for drag n drop
|
//default constraints for drag n drop
|
||||||
var constraints = {left: {max: 20, min: 20}, top: {max: 20, min: 20}, };
|
var constraints = {left: {max: scope.dimensions.margin, min: scope.dimensions.margin}, top: {max: scope.dimensions.margin, min: scope.dimensions.margin}, };
|
||||||
|
scope.constraints = constraints;
|
||||||
var setDimensions = function(){
|
|
||||||
scope.dimensions.image.width = $image.width();
|
|
||||||
scope.dimensions.image.height = $image.height();
|
//set constaints for cropping drag and drop
|
||||||
|
var setConstraints = function(){
|
||||||
|
constraints.left.min = scope.dimensions.margin + scope.dimensions.cropper.width - scope.dimensions.image.width;
|
||||||
|
constraints.top.min = scope.dimensions.margin + scope.dimensions.cropper.height - scope.dimensions.image.height;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var setDimensions = function(originalImage){
|
||||||
|
originalImage.width("auto");
|
||||||
|
originalImage.height("auto");
|
||||||
|
|
||||||
|
var image = {};
|
||||||
|
image.originalWidth = originalImage.width();
|
||||||
|
image.originalHeight = originalImage.height();
|
||||||
|
|
||||||
|
image.width = image.originalWidth;
|
||||||
|
image.height = image.originalHeight;
|
||||||
|
image.left = originalImage[0].offsetLeft;
|
||||||
|
image.top = originalImage[0].offsetTop;
|
||||||
|
|
||||||
|
scope.dimensions.image = image;
|
||||||
|
|
||||||
scope.dimensions.viewport.width = $viewport.width();
|
scope.dimensions.viewport.width = $viewport.width();
|
||||||
scope.dimensions.viewport.height = $viewport.height();
|
scope.dimensions.viewport.height = $viewport.height();
|
||||||
@@ -64,39 +90,12 @@ angular.module("umbraco.directives")
|
|||||||
scope.dimensions.cropper.height = scope.dimensions.viewport.height - 2 * scope.dimensions.margin;
|
scope.dimensions.cropper.height = scope.dimensions.viewport.height - 2 * scope.dimensions.margin;
|
||||||
};
|
};
|
||||||
|
|
||||||
var setImageSize = function(width, height){
|
|
||||||
$image.width(width);
|
|
||||||
$image.height(height);
|
|
||||||
scope.dimensions.image.width = width;
|
|
||||||
scope.dimensions.image.height = height;
|
|
||||||
};
|
|
||||||
|
|
||||||
//when loading an image without any crop info, we center and fit it
|
//when loading an image without any crop info, we center and fit it
|
||||||
var fitImage = function(){
|
var resizeImageToEditor = function(){
|
||||||
fitToViewPort($image);
|
|
||||||
centerImage($image);
|
|
||||||
syncOverLay();
|
|
||||||
setConstraints($image);
|
|
||||||
};
|
|
||||||
|
|
||||||
//utill for centering scaled image
|
|
||||||
var centerImage = function(img) {
|
|
||||||
var image_width = img.width(),
|
|
||||||
image_height = img.height(),
|
|
||||||
mask_width = $viewport.width(),
|
|
||||||
mask_height = $viewport.height();
|
|
||||||
|
|
||||||
img.css({
|
|
||||||
'position': 'absolute',
|
|
||||||
'left': scope.dimensions.viewport.width / 2 - scope.dimensions.image.width / 2,
|
|
||||||
'top': scope.dimensions.viewport.height / 2 - scope.dimensions.image.height / 2
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//utill for scaling image to fit viewport
|
|
||||||
var fitToViewPort = function(img) {
|
|
||||||
//returns size fitting the cropper
|
//returns size fitting the cropper
|
||||||
var size = calculateAspectRatioFit(
|
var size = cropperHelper.calculateAspectRatioFit(
|
||||||
scope.dimensions.image.width,
|
scope.dimensions.image.width,
|
||||||
scope.dimensions.image.height,
|
scope.dimensions.image.height,
|
||||||
scope.dimensions.cropper.width,
|
scope.dimensions.cropper.width,
|
||||||
@@ -104,163 +103,154 @@ angular.module("umbraco.directives")
|
|||||||
true);
|
true);
|
||||||
|
|
||||||
//sets the image size and updates the scope
|
//sets the image size and updates the scope
|
||||||
setImageSize(size.width, size.height);
|
scope.dimensions.image.width = size.width;
|
||||||
|
scope.dimensions.image.height = size.height;
|
||||||
|
|
||||||
scope.minScale = size.ratio;
|
//calculate the best suited ratios
|
||||||
scope.maxScale = size.ratio * 3;
|
scope.dimensions.scale.min = size.ratio;
|
||||||
scope.currentScale = scope.minScale;
|
scope.dimensions.scale.max = 2;
|
||||||
scope.scale = scope.currentScale;
|
scope.dimensions.scale.current = size.ratio;
|
||||||
|
|
||||||
|
//center the image
|
||||||
|
var position = cropperHelper.centerInsideViewPort(scope.dimensions.image, scope.dimensions.cropper);
|
||||||
|
scope.dimensions.top = position.top;
|
||||||
|
scope.dimensions.left = position.left;
|
||||||
|
|
||||||
|
setConstraints();
|
||||||
};
|
};
|
||||||
|
|
||||||
var resizeImageToScale = function(img, ratio){
|
//resize to a given ratio
|
||||||
|
var resizeImageToScale = function(ratio){
|
||||||
//do stuff
|
//do stuff
|
||||||
var size = calculateSizeToRatio(scope.dimensions.image.originalWidth, scope.dimensions.image.originalHeight, ratio);
|
var size = cropperHelper.calculateSizeToRatio(scope.dimensions.image.originalWidth, scope.dimensions.image.originalHeight, ratio);
|
||||||
|
scope.dimensions.image.width = size.width;
|
||||||
setImageSize(size.width, size.height);
|
scope.dimensions.image.height = size.height;
|
||||||
centerImage(img);
|
|
||||||
scope.currentScale = scope.scale;
|
|
||||||
|
|
||||||
syncOverLay();
|
setConstraints();
|
||||||
|
validatePosition(scope.dimensions.image.left, scope.dimensions.image.top);
|
||||||
};
|
};
|
||||||
|
|
||||||
//set constaints for cropping drag and drop
|
//resize the image to a predefined crop coordinate
|
||||||
var setConstraints = function(img){
|
var resizeImageToCrop = function(){
|
||||||
//do stuff
|
scope.dimensions.image = cropperHelper.convertToStyle(
|
||||||
var w = img.width(),
|
scope.crop,
|
||||||
h = img.height(),
|
{width: scope.dimensions.image.originalWidth, height: scope.dimensions.image.originalHeight},
|
||||||
crop_width = $viewport.width() - 2 * 20,
|
scope.dimensions.cropper,
|
||||||
crop_height = $viewport.height() - 2 * 20;
|
scope.dimensions.margin);
|
||||||
|
|
||||||
constraints.left.min = 20 + crop_width - w;
|
var ratioCalculation = cropperHelper.calculateAspectRatioFit(
|
||||||
constraints.top.min = 20 + crop_height - h;
|
scope.dimensions.image.originalWidth,
|
||||||
|
scope.dimensions.image.originalHeight,
|
||||||
|
scope.dimensions.cropper.width,
|
||||||
|
scope.dimensions.cropper.height,
|
||||||
|
true);
|
||||||
|
|
||||||
|
scope.dimensions.scale.current = scope.dimensions.image.ratio;
|
||||||
|
|
||||||
|
//min max based on original width/height
|
||||||
|
scope.dimensions.scale.min = ratioCalculation.ratio;
|
||||||
|
scope.dimensions.scale.max = 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
//utill for getting either min/max aspect ratio to scale image after
|
|
||||||
var calculateAspectRatioFit = function(srcWidth, srcHeight, maxWidth, maxHeight, maximize) {
|
|
||||||
var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
|
|
||||||
|
|
||||||
if(maximize){
|
|
||||||
ratio = Math.max(ratio[0], ratio[1]);
|
var validatePosition = function(left, top){
|
||||||
}else{
|
if(left > constraints.left.max)
|
||||||
ratio = Math.min(ratio[0], ratio[1]);
|
{
|
||||||
|
left = constraints.left.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
|
if(left <= constraints.left.min){
|
||||||
};
|
left = constraints.left.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(top > constraints.top.max)
|
||||||
|
{
|
||||||
|
top = constraints.top.max;
|
||||||
|
}
|
||||||
|
if(top <= constraints.top.min){
|
||||||
|
top = constraints.top.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.dimensions.image.left = left;
|
||||||
|
scope.dimensions.image.top = top;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//utill for scaling width / height given a ratio
|
|
||||||
var calculateSizeToRatio= function(srcWidth, srcHeight, ratio) {
|
|
||||||
return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//sets scope.crop to the recalculated % based crop
|
||||||
var calculateCropBox = function(){
|
var calculateCropBox = function(){
|
||||||
scope.crop.left = Math.abs($image[0].offsetLeft - scope.dimensions.margin) / scope.dimensions.image.width;
|
scope.crop = cropperHelper.pixelsToCoordinates(scope.dimensions.image, scope.dimensions.cropper.width, scope.dimensions.cropper.height, scope.dimensions.margin);
|
||||||
scope.crop.top = Math.abs($image[0].offsetTop - scope.dimensions.margin) / scope.dimensions.image.height;
|
|
||||||
|
|
||||||
scope.crop.right = 1 - Math.abs(scope.dimensions.cropper.width - (scope.dimensions.image.width - scope.crop.left)) / scope.dimensions.image.width;
|
|
||||||
scope.crop.bottom = 1 - Math.abs(scope.dimensions.cropper.height - (scope.dimensions.image.height - scope.crop.top)) / scope.dimensions.image.height;
|
|
||||||
};
|
|
||||||
|
|
||||||
var calculatePosition = function(crop){
|
|
||||||
|
|
||||||
var left = (crop.left * scope.dimensions.image.originalWidth);
|
|
||||||
var top = (crop.top * scope.dimensions.image.originalHeight);
|
|
||||||
|
|
||||||
var cropped_width = scope.dimensions.image.originalWidth - left;
|
|
||||||
var ratio = cropped_width / scope.dimensions.image.originalWidth;
|
|
||||||
|
|
||||||
scope.scale = ratio;
|
|
||||||
resizeImageToScale($image, ratio);
|
|
||||||
|
|
||||||
$image.css({
|
|
||||||
"top": -top,
|
|
||||||
"left": -left
|
|
||||||
});
|
|
||||||
|
|
||||||
syncOverLay();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var syncOverLay = function(){
|
|
||||||
$overlay.height($image.height());
|
|
||||||
$overlay.width($image.width());
|
|
||||||
|
|
||||||
$overlay.css({
|
|
||||||
"top": $image[0].offsetTop,
|
|
||||||
"left": $image[0].offsetLeft
|
|
||||||
});
|
|
||||||
|
|
||||||
calculateCropBox();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Drag and drop positioning, using jquery ui draggable
|
//Drag and drop positioning, using jquery ui draggable
|
||||||
var onStartDragPosition, top, left;
|
var onStartDragPosition, top, left;
|
||||||
$overlay.draggable({
|
$overlay.draggable({
|
||||||
start: function(event, ui) {
|
|
||||||
syncOverLay();
|
|
||||||
},
|
|
||||||
drag: function(event, ui) {
|
drag: function(event, ui) {
|
||||||
|
scope.$apply(function(){
|
||||||
|
validatePosition(ui.position.left, ui.position.top);
|
||||||
if(ui.position.left <= constraints.left.max && ui.position.left >= constraints.left.min){
|
});
|
||||||
$image.css({
|
|
||||||
'left': ui.position.left
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ui.position.top <= constraints.top.max && ui.position.top >= constraints.top.min){
|
|
||||||
$image.css({
|
|
||||||
'top': ui.position.top
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
stop: function() {
|
stop: function(event, ui){
|
||||||
syncOverLay();
|
scope.$apply(function(){
|
||||||
|
calculateCropBox();
|
||||||
|
scope.dimensions.image.rnd = Math.random();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var init = function(image){
|
||||||
|
scope.loaded = false;
|
||||||
|
|
||||||
|
//set dimensions on image, viewport, cropper etc
|
||||||
|
setDimensions(image);
|
||||||
|
|
||||||
|
//if we have a crop already position the image
|
||||||
|
if(scope.crop){
|
||||||
|
resizeImageToCrop();
|
||||||
|
}else{
|
||||||
|
resizeImageToEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
//sets constaints for the cropper
|
||||||
|
setConstraints();
|
||||||
|
|
||||||
|
|
||||||
|
scope.loaded = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// WATCHERS ////
|
||||||
|
scope.$watchCollection('[width, height]', function(newValues, oldValues){
|
||||||
|
//we have to reinit the whole thing if
|
||||||
|
//one of the external params changes
|
||||||
|
if(newValues !== oldValues){
|
||||||
|
setDimensions($image);
|
||||||
|
setConstraints();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//happens when we change the scale
|
||||||
|
scope.$watch("dimensions.scale.current", function(){
|
||||||
|
if(scope.loaded){
|
||||||
|
resizeImageToScale(scope.dimensions.scale.current);
|
||||||
|
calculateCropBox();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//// INIT /////
|
//// INIT /////
|
||||||
$image.load(function(){
|
$image.load(function(){
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
$image.width("auto");
|
init($image);
|
||||||
$image.height("auto");
|
|
||||||
|
|
||||||
scope.dimensions.image.originalWidth = $image.width();
|
|
||||||
scope.dimensions.image.originalHeight = $image.height();
|
|
||||||
|
|
||||||
setDimensions();
|
|
||||||
|
|
||||||
if(scope.crop && scope.crop.top){
|
|
||||||
calculatePosition(scope.crop);
|
|
||||||
}else{
|
|
||||||
scope.crop = {};
|
|
||||||
fitImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.loaded = true;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/// WATCHERS ////
|
|
||||||
scope.$watch("scale", function(){
|
|
||||||
if(scope.loaded && scope.scale !== scope.currentScale){
|
|
||||||
resizeImageToScale($image, scope.scale);
|
|
||||||
setConstraints($image);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/// WATCHERS ////
|
|
||||||
scope.$watch("crop", function(newVal, oldVal){
|
|
||||||
if(scope.loaded && newVal !== oldVal){
|
|
||||||
calculatePosition(scope.crop);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -14,104 +14,69 @@ angular.module("umbraco.directives")
|
|||||||
templateUrl: 'views/directives/imaging/umb-image-gravity.html',
|
templateUrl: 'views/directives/imaging/umb-image-gravity.html',
|
||||||
scope: {
|
scope: {
|
||||||
src: '=',
|
src: '=',
|
||||||
width: "=",
|
center: "="
|
||||||
height: "=",
|
|
||||||
gravity: "="
|
|
||||||
},
|
},
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
|
|
||||||
|
//Internal values for keeping track of the dot and the size of the editor
|
||||||
|
scope.dimensions = {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
left: 0,
|
||||||
|
top: 0
|
||||||
|
};
|
||||||
|
|
||||||
//elements
|
//elements
|
||||||
var $viewport = element.find(".viewport");
|
var $viewport = element.find(".viewport");
|
||||||
var $image = element.find("img");
|
var $image = element.find("img");
|
||||||
var $overlay = element.find(".overlay");
|
var $overlay = element.find(".overlay");
|
||||||
|
|
||||||
|
scope.style = function () {
|
||||||
|
if(scope.dimensions.width <= 0){
|
||||||
|
setDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'top': scope.dimensions.top + 'px',
|
||||||
|
'left': scope.dimensions.left + 'px'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
var setDimensions = function(){
|
var setDimensions = function(){
|
||||||
scope.imagewidth = $image.width();
|
scope.dimensions.width = $image.width();
|
||||||
scope.imageheight = $image.height();
|
scope.dimensions.height = $image.height();
|
||||||
};
|
|
||||||
|
|
||||||
var setImageSize = function(width, height){
|
if(scope.center){
|
||||||
$image.width(width);
|
scope.dimensions.left = scope.center.left * scope.dimensions.width -10;
|
||||||
$image.height(height);
|
scope.dimensions.top = scope.center.top * scope.dimensions.height -10;
|
||||||
|
|
||||||
$viewport.width(width);
|
|
||||||
$viewport.height(height);
|
|
||||||
};
|
|
||||||
|
|
||||||
var fitImage = function(){
|
|
||||||
fitToViewPort($image);
|
|
||||||
centerImage($image);
|
|
||||||
$log.log("centered and fitted");
|
|
||||||
};
|
|
||||||
|
|
||||||
//utill for centering scaled image
|
|
||||||
var centerImage = function(img) {
|
|
||||||
img.css({
|
|
||||||
'position': 'absolute',
|
|
||||||
'left': scope.width / 2 - scope.imageWidth / 2,
|
|
||||||
'top': scope.height / 2 - scope.imageHeight / 2
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//utill for scaling image to fit viewport
|
|
||||||
var fitToViewPort = function(img) {
|
|
||||||
//returns size fitting the cropper
|
|
||||||
var size = calculateAspectRatioFit(
|
|
||||||
scope.imageWidth,
|
|
||||||
scope.imageHeight,
|
|
||||||
scope.width,
|
|
||||||
scope.height,
|
|
||||||
false);
|
|
||||||
|
|
||||||
//sets the image size and updates the scope
|
|
||||||
setImageSize(size.width, size.height);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//utill for getting either min/max aspect ratio to scale image after
|
|
||||||
var calculateAspectRatioFit = function(srcWidth, srcHeight, maxWidth, maxHeight, maximize) {
|
|
||||||
var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
|
|
||||||
|
|
||||||
if(maximize){
|
|
||||||
ratio = Math.max(ratio[0], ratio[1]);
|
|
||||||
}else{
|
|
||||||
ratio = Math.min(ratio[0], ratio[1]);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
|
|
||||||
};
|
|
||||||
|
|
||||||
var calculateGravity = function(){
|
|
||||||
scope.gravity.left = $overlay[0].offsetLeft + 10;
|
|
||||||
scope.gravity.top = $overlay[0].offsetTop + 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
var calculateGravity = function(){
|
||||||
|
scope.dimensions.left = $overlay[0].offsetLeft;
|
||||||
|
scope.dimensions.top = $overlay[0].offsetTop;
|
||||||
|
|
||||||
|
scope.center.left = (scope.dimensions.left+10) / scope.dimensions.width;
|
||||||
|
scope.center.top = (scope.dimensions.top+10) / scope.dimensions.height;
|
||||||
|
};
|
||||||
|
|
||||||
//Drag and drop positioning, using jquery ui draggable
|
//Drag and drop positioning, using jquery ui draggable
|
||||||
var onStartDragPosition, top, left;
|
//TODO ensure that the point doesnt go outside the box
|
||||||
$overlay.draggable({
|
$overlay.draggable({
|
||||||
|
containment: "parent",
|
||||||
stop: function() {
|
stop: function() {
|
||||||
calculateGravity();
|
scope.$apply(function(){
|
||||||
|
calculateGravity();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//// INIT /////
|
//// INIT /////
|
||||||
$image.load(function(){
|
$image.load(function(){
|
||||||
|
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
$image.width("auto");
|
|
||||||
$image.height("auto");
|
|
||||||
|
|
||||||
setDimensions();
|
setDimensions();
|
||||||
fitImage();
|
|
||||||
|
|
||||||
scope.loaded = true;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
* Used by editors that require naming an entity. Shows a textbox/headline with a required validator within it's own form.
|
* Used by editors that require naming an entity. Shows a textbox/headline with a required validator within it's own form.
|
||||||
**/
|
**/
|
||||||
angular.module("umbraco.directives")
|
angular.module("umbraco.directives")
|
||||||
.directive('umbImageThumbnail', function ($timeout, localizationService, $log) {
|
.directive('umbImageThumbnail',
|
||||||
|
function ($timeout, localizationService, cropperHelper, $log) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
replace: true,
|
replace: true,
|
||||||
@@ -15,17 +16,69 @@ angular.module("umbraco.directives")
|
|||||||
|
|
||||||
scope: {
|
scope: {
|
||||||
src: '=',
|
src: '=',
|
||||||
width: '=',
|
width: '@',
|
||||||
height: '=',
|
height: '@',
|
||||||
gravity: "=",
|
center: "=",
|
||||||
crop: "="
|
crop: "="
|
||||||
},
|
},
|
||||||
|
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
scope.marginLeft = 0-Math.abs( scope.width * scope.gravity.left);
|
//// INIT /////
|
||||||
scope.marginTop = 0-Math.abs( scope.width * scope.gravity.top);
|
var $image = element.find("img");
|
||||||
|
$image.load(function(){
|
||||||
|
$timeout(function(){
|
||||||
|
$image.width("auto");
|
||||||
|
$image.height("auto");
|
||||||
|
|
||||||
|
scope.image = {};
|
||||||
|
scope.image.width = $image[0].width;
|
||||||
|
scope.image.height = $image[0].height;
|
||||||
|
|
||||||
|
setPreviewStyle();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/// WATCHERS ////
|
||||||
|
scope.$watchCollection('[crop, center]', function(newValues, oldValues){
|
||||||
|
//we have to reinit the whole thing if
|
||||||
|
//one of the external params changes
|
||||||
|
setPreviewStyle();
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.$watch("center", function(){
|
||||||
|
setPreviewStyle();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
function setPreviewStyle(){
|
||||||
|
if(scope.crop && scope.image){
|
||||||
|
scope.preview = cropperHelper.convertToStyle(
|
||||||
|
scope.crop,
|
||||||
|
scope.image,
|
||||||
|
{width: scope.width, height: scope.height},
|
||||||
|
0);
|
||||||
|
}else if(scope.image){
|
||||||
|
|
||||||
|
//returns size fitting the cropper
|
||||||
|
var p = cropperHelper.calculateAspectRatioFit(
|
||||||
|
scope.image.width,
|
||||||
|
scope.image.height,
|
||||||
|
scope.width,
|
||||||
|
scope.height,
|
||||||
|
true);
|
||||||
|
|
||||||
|
|
||||||
|
if(scope.center){
|
||||||
|
var xy = cropperHelper.alignToCoordinates(p, scope.center, {width: scope.width, height: scope.height});
|
||||||
|
p.top = xy.top;
|
||||||
|
p.left = xy.left;
|
||||||
|
}else{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
p.position = "absolute";
|
||||||
|
scope.preview = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -19,7 +19,7 @@ function mediaHelper(umbRequestHelper) {
|
|||||||
* @param {object} options.imageOnly Optional, if true then will only return a path if the media item is an image
|
* @param {object} options.imageOnly Optional, if true then will only return a path if the media item is an image
|
||||||
*/
|
*/
|
||||||
getMediaPropertyValue: function (options) {
|
getMediaPropertyValue: function (options) {
|
||||||
return "assets/img/mocks/image.jpg";
|
return "assets/img/mocks/big-image.jpg";
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +35,7 @@ function mediaHelper(umbRequestHelper) {
|
|||||||
* @param {object} options.imageModel The media object to retrieve the image path from
|
* @param {object} options.imageModel The media object to retrieve the image path from
|
||||||
*/
|
*/
|
||||||
getImagePropertyValue: function (options) {
|
getImagePropertyValue: function (options) {
|
||||||
return "assets/img/mocks/image.jpg";
|
return "assets/img/mocks/big-image.jpg";
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @ngdoc function
|
* @ngdoc function
|
||||||
|
|||||||
@@ -90,17 +90,21 @@ angular.module('umbraco.services')
|
|||||||
var t = timeout || 5000;
|
var t = timeout || 5000;
|
||||||
var a = attributes || undefined;
|
var a = attributes || undefined;
|
||||||
|
|
||||||
yepnope.injectCss(path, function () {
|
yepnope({
|
||||||
|
forceCSS: true,
|
||||||
if (!scope) {
|
load: path,
|
||||||
deferred.resolve(true);
|
timeout: t,
|
||||||
}else{
|
attrs: a,
|
||||||
angularHelper.safeApply(scope, function () {
|
callback: function (url, result, key) {
|
||||||
deferred.resolve(true);
|
if (!scope) {
|
||||||
});
|
deferred.resolve(true);
|
||||||
}
|
}else{
|
||||||
|
angularHelper.safeApply(scope, function () {
|
||||||
},a,t);
|
deferred.resolve(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
@@ -124,6 +128,26 @@ angular.module('umbraco.services')
|
|||||||
var t = timeout || 5000;
|
var t = timeout || 5000;
|
||||||
var a = attributes || undefined;
|
var a = attributes || undefined;
|
||||||
|
|
||||||
|
|
||||||
|
yepnope({
|
||||||
|
forceJS: true,
|
||||||
|
load: path,
|
||||||
|
timeout: t,
|
||||||
|
attrs: a,
|
||||||
|
callback: function (url, result, key) {
|
||||||
|
|
||||||
|
if (!scope) {
|
||||||
|
deferred.resolve(true);
|
||||||
|
}else{
|
||||||
|
angularHelper.safeApply(scope, function () {
|
||||||
|
deferred.resolve(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
yepnope.injectJs(path, function () {
|
yepnope.injectJs(path, function () {
|
||||||
|
|
||||||
if (!scope) {
|
if (!scope) {
|
||||||
@@ -135,6 +159,7 @@ angular.module('umbraco.services')
|
|||||||
}
|
}
|
||||||
|
|
||||||
},a,t);
|
},a,t);
|
||||||
|
*/
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
* @ngdoc service
|
||||||
|
* @name umbraco.services.mediaHelper
|
||||||
|
* @description A helper object used for dealing with media items
|
||||||
|
**/
|
||||||
|
function cropperHelper(umbRequestHelper) {
|
||||||
|
var service = {
|
||||||
|
//utill for getting either min/max aspect ratio to scale image after
|
||||||
|
calculateAspectRatioFit : function(srcWidth, srcHeight, maxWidth, maxHeight, maximize) {
|
||||||
|
var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
|
||||||
|
|
||||||
|
if(maximize){
|
||||||
|
ratio = Math.max(ratio[0], ratio[1]);
|
||||||
|
}else{
|
||||||
|
ratio = Math.min(ratio[0], ratio[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
|
||||||
|
},
|
||||||
|
|
||||||
|
//utill for scaling width / height given a ratio
|
||||||
|
calculateSizeToRatio : function(srcWidth, srcHeight, ratio) {
|
||||||
|
return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
|
||||||
|
},
|
||||||
|
|
||||||
|
//returns a ng-style object with top,left,width,height pixel measurements
|
||||||
|
//expects {left,right,top,bottom} - {width,height}, {width,height}, int
|
||||||
|
//offset is just to push the image position a number of pixels from top,left
|
||||||
|
convertToStyle : function(coordinates, originalSize, viewPort, offset){
|
||||||
|
|
||||||
|
var coordinates_px = service.coordinatesToPixels(coordinates, originalSize, offset);
|
||||||
|
var _offset = offset || 0;
|
||||||
|
|
||||||
|
var x = coordinates.x1 + Math.abs(coordinates.x2);
|
||||||
|
var left_of_x = originalSize.width - (originalSize.width * x);
|
||||||
|
var ratio = viewPort.width / left_of_x;
|
||||||
|
|
||||||
|
var style = {
|
||||||
|
position: "absolute",
|
||||||
|
top: -(coordinates_px.y1*ratio)+ _offset,
|
||||||
|
left: -(coordinates_px.x1* ratio)+ _offset,
|
||||||
|
width: Math.floor(originalSize.width * ratio),
|
||||||
|
height: Math.floor(originalSize.height * ratio),
|
||||||
|
originalWidth: originalSize.width,
|
||||||
|
originalHeight: originalSize.height,
|
||||||
|
ratio: ratio
|
||||||
|
};
|
||||||
|
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
|
||||||
|
//returns a ng-style object with top,left,width,height pixel measurements
|
||||||
|
//expects {left,right,top,bottom} - {width,height}, {width,height}, int
|
||||||
|
//offset is just to push the image position a number of pixels from top,left
|
||||||
|
coordinatesToPixels : function(coordinates, originalSize, offset){
|
||||||
|
|
||||||
|
var coordinates_px = {
|
||||||
|
x1: Math.floor(coordinates.x1 * originalSize.width),
|
||||||
|
y1: Math.floor(coordinates.y1 * originalSize.height),
|
||||||
|
x2: Math.floor(coordinates.x2 * originalSize.width),
|
||||||
|
y2: Math.floor(coordinates.y2 * originalSize.height)
|
||||||
|
};
|
||||||
|
|
||||||
|
return coordinates_px;
|
||||||
|
},
|
||||||
|
|
||||||
|
pixelsToCoordinates : function(image, width, height, offset){
|
||||||
|
|
||||||
|
var x1_px = Math.abs(image.left-offset);
|
||||||
|
var y1_px = Math.abs(image.top-offset);
|
||||||
|
|
||||||
|
var x2_px = (x1_px + width) - image.width;
|
||||||
|
var y2_px = (y1_px + height) - image.height;
|
||||||
|
|
||||||
|
//crop coordinates in %
|
||||||
|
var crop = {};
|
||||||
|
crop.x1 = x1_px / image.width;
|
||||||
|
crop.y1 = y1_px / image.height;
|
||||||
|
crop.x2 = x2_px / image.width;
|
||||||
|
crop.y2 = y2_px / image.height;
|
||||||
|
|
||||||
|
return crop;
|
||||||
|
},
|
||||||
|
|
||||||
|
centerInsideViewPort : function(img, viewport){
|
||||||
|
var left = viewport.width/ 2 - img.width / 2,
|
||||||
|
top = viewport.height / 2 - img.height / 2;
|
||||||
|
|
||||||
|
return {left: left, top: top};
|
||||||
|
},
|
||||||
|
|
||||||
|
alignToCoordinates : function(image, center, viewport){
|
||||||
|
|
||||||
|
var min_left = (image.width) - (viewport.width);
|
||||||
|
var min_top = (image.height) - (viewport.height);
|
||||||
|
|
||||||
|
var c_top = -(center.top * image.height) + (viewport.height / 2);
|
||||||
|
var c_left = -(center.left * image.width) + (viewport.width / 2);
|
||||||
|
|
||||||
|
if(c_top < -min_top){
|
||||||
|
c_top = -min_top;
|
||||||
|
}
|
||||||
|
if(c_top > 0){
|
||||||
|
c_top = 0;
|
||||||
|
}
|
||||||
|
if(c_left < -min_left){
|
||||||
|
c_left = -min_left;
|
||||||
|
}
|
||||||
|
if(c_left > 0){
|
||||||
|
c_left = 0;
|
||||||
|
}
|
||||||
|
return {left: c_left, top: c_top};
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
syncElements : function(source, target){
|
||||||
|
target.height(source.height());
|
||||||
|
target.width(source.width());
|
||||||
|
|
||||||
|
target.css({
|
||||||
|
"top": source[0].offsetTop,
|
||||||
|
"left": source[0].offsetLeft
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.module('umbraco.services').factory('cropperHelper', cropperHelper);
|
||||||
@@ -41,7 +41,7 @@ function mediaHelper(umbRequestHelper) {
|
|||||||
|
|
||||||
//this performs a simple check to see if we have a media file as value
|
//this performs a simple check to see if we have a media file as value
|
||||||
//it doesnt catch everything, but better then nothing
|
//it doesnt catch everything, but better then nothing
|
||||||
if (item.value.indexOf(mediaRoot) === 0) {
|
if (angular.isString(item.value) && item.value.indexOf(mediaRoot) === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
/*Contains multiple services for various helper tasks */
|
/*Contains multiple services for various helper tasks */
|
||||||
|
|
||||||
function packageHelper(assetsService, treeService, eventsService) {
|
function packageHelper(assetsService, treeService, eventsService, $templateCache) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
/** Called when a package is installed, this resets a bunch of data and ensures the new package assets are loaded in */
|
/** Called when a package is installed, this resets a bunch of data and ensures the new package assets are loaded in */
|
||||||
packageInstalled: function () {
|
packageInstalled: function () {
|
||||||
//assetsService._reloadApplicationAssets().then(function() {
|
|
||||||
// treeService.clearCache();
|
|
||||||
// //send event
|
|
||||||
// //eventsService.emit("app.reInitialize");
|
|
||||||
|
|
||||||
// //TODO: This doesn't work and will end in an infinite browser load loop, we can't really
|
//clears the tree
|
||||||
// // re-bootstrap anyways since that would be the same as loading the whole browser window.
|
treeService.clearCache();
|
||||||
// //angular.bootstrap(document, ['umbraco']);
|
|
||||||
//});
|
//clears the template cache
|
||||||
|
$templateCache.removeAll();
|
||||||
|
|
||||||
|
//emit event to notify anything else
|
||||||
|
eventsService.emit("app.reInitialize");
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
@import "../../lib/bootstrap/less/modals.less";
|
@import "../../lib/bootstrap/less/modals.less";
|
||||||
@import "../../lib/bootstrap/less/tooltip.less";
|
@import "../../lib/bootstrap/less/tooltip.less";
|
||||||
@import "../../lib/bootstrap/less/popovers.less";
|
@import "../../lib/bootstrap/less/popovers.less";
|
||||||
|
@import "tipmenu.less";
|
||||||
|
|
||||||
// Components: Misc
|
// Components: Misc
|
||||||
@import "../../lib/bootstrap/less/thumbnails.less";
|
@import "../../lib/bootstrap/less/thumbnails.less";
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ ul.color-picker li a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.umb-thumbnails{
|
.umb-thumbnails{
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -194,13 +196,17 @@ ul.color-picker li a {
|
|||||||
// Cropper
|
// Cropper
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
.umb-cropper{
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.umb-cropper img, .umb-cropper-gravity img{
|
.umb-cropper img, .umb-cropper-gravity img{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.umb-cropper .overlay, .umb-cropper-gravity .overlay {
|
.umb-cropper .overlay, .umb-cropper-gravity .overlay {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -208,13 +214,19 @@ ul.color-picker li a {
|
|||||||
z-index: 6001;
|
z-index: 6001;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umb-cropper .viewport, .umb-cropper-gravity .viewport {
|
.umb-cropper .viewport{
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
border:1px solid @grayLight;
|
border: 1px solid @grayLight;
|
||||||
width: 600px;
|
|
||||||
height: 480px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.umb-cropper-gravity .viewport{
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: 400px;
|
||||||
|
height: 300px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.umb-cropper .viewport:after {
|
.umb-cropper .viewport:after {
|
||||||
content: "";
|
content: "";
|
||||||
@@ -227,9 +239,9 @@ ul.color-picker li a {
|
|||||||
-moz-opacity: .75;
|
-moz-opacity: .75;
|
||||||
opacity: .75;
|
opacity: .75;
|
||||||
filter: alpha(opacity=7);
|
filter: alpha(opacity=7);
|
||||||
-webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
|
-webkit-box-shadow: inset 0 0 0 40px white,inset 0 0 0 41px rgba(0,0,0,.1),inset 0 0 40px 41px rgba(0,0,0,.2);
|
||||||
-moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
|
-moz-box-shadow: inset 0 0 0 40px white,inset 0 0 0 41px rgba(0,0,0,.1),inset 0 0 40px 41px rgba(0,0,0,.2);
|
||||||
box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
|
box-shadow: inset 0 0 0 40px white,inset 0 0 0 41px rgba(0,0,0,.1),inset 0 0 40px 41px rgba(0,0,0,.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.umb-cropper-gravity .overlay{
|
.umb-cropper-gravity .overlay{
|
||||||
@@ -240,12 +252,27 @@ ul.color-picker li a {
|
|||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umb-cropper-gravity .overlay i{
|
.umb-cropper-gravity .overlay i{
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
opacity: 0.8 !important;
|
opacity: 0.8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.umb-cropper .crop-container{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.umb-cropper .crop-slider{
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 250px;
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.umb-cropper .crop-slider i{color: @gray;}
|
||||||
|
.umb-cropper .crop-slider input{
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
15
src/Umbraco.Web.UI.Client/src/less/tipmenu.less
Normal file
15
src/Umbraco.Web.UI.Client/src/less/tipmenu.less
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.tipmenu .tooltip{
|
||||||
|
position:absolute;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tipmenu:hover .tooltip{
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tipmenu:hover .tooltip a{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
|
//global no-cache filter, this is enabled when we're in debug mode
|
||||||
|
//in live mode we use client dependency and don't turn this thing on
|
||||||
|
yepnope.addFilter(function (resourceObj) {
|
||||||
|
var url = resourceObj.url;
|
||||||
|
if(url.indexOf("lib/") === 0 || url.indexOf("js/umbraco.") === 0){
|
||||||
|
return resourceObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceObj.url = resourceObj.url + "?umb__rnd=" + (new Date).getTime();
|
||||||
|
return resourceObj;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
yepnope({
|
yepnope({
|
||||||
|
|
||||||
load: [
|
load: [
|
||||||
'lib/jquery/jquery-2.0.3.min.js',
|
'lib/jquery/jquery-2.0.3.min.js',
|
||||||
|
|
||||||
/* the jquery ui elements we need */
|
/* the jquery ui elements we need */
|
||||||
/* NOTE: I've opted not to use the full lib, just the parts we need to save on DL*/
|
'lib/jquery/jquery-ui-1.10.3.custom.min.js',
|
||||||
'lib/jquery/jquery.ui.core.min.js',
|
|
||||||
'lib/jquery/jquery.ui.widget.min.js',
|
|
||||||
|
|
||||||
'lib/jquery/jquery.ui.mouse.min.js',
|
|
||||||
'lib/jquery/jquery.ui.sortable.min.js',
|
|
||||||
|
|
||||||
/* 1.1.5 */
|
/* 1.1.5 */
|
||||||
'lib/angular/1.1.5/angular.min.js',
|
'lib/angular/1.1.5/angular.min.js',
|
||||||
'lib/angular/1.1.5/angular-cookies.min.js',
|
'lib/angular/1.1.5/angular-cookies.min.js',
|
||||||
|
|||||||
@@ -1,32 +1,21 @@
|
|||||||
<div class="umb-cropper" ng-show="src">
|
<div class="umb-cropper umb-editor" ng-show="src">
|
||||||
|
|
||||||
<div class="crop-container">
|
<div class="crop-container">
|
||||||
<div class="viewport" ng-style="style()">
|
<div class="viewport" ng-style="style()">
|
||||||
<img src="{{src}}" />
|
<img src="{{src}}" ng-style="dimensions.image"/>
|
||||||
<div class="overlay"></div>
|
<div class="overlay" ng-style="dimensions.image"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input
|
<div class="crop-slider">
|
||||||
type="range"
|
<i class="icon-picture"></i>
|
||||||
min="{{minScale}}"
|
<input
|
||||||
max="{{maxScale}}"
|
type="range"
|
||||||
step="0.01"
|
min="{{dimensions.scale.min}}"
|
||||||
ng-model="scale" />
|
max="{{dimensions.scale.max}}"
|
||||||
|
step="0.01"
|
||||||
<pre>
|
ng-model="dimensions.scale.current" />
|
||||||
{{dimensions | json}}
|
|
||||||
</pre>
|
<i class="icon-picture" style="font-size: 22px"></i>
|
||||||
|
</div>
|
||||||
<pre>
|
|
||||||
{{box | json}}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<ul class="crops-preview">
|
|
||||||
<li ng-repeat="preview in previews">
|
|
||||||
<div ng-style="preview.style">
|
|
||||||
<img src="{{preview.src" ng-style="preview.imageStyle">
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul> -->
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<div class="umb-cropper-gravity">
|
<div class="umb-cropper-gravity">
|
||||||
<div class="gravity-container">
|
<div class="gravity-container">
|
||||||
<div class="viewport" ng-style="style()">
|
<div class="viewport">
|
||||||
<img src="{{src}}" />
|
<img src="{{src}}" style="max-width: 100%; max-height: 100%" />
|
||||||
|
|
||||||
<div class="overlay">
|
<div class="overlay" ng-style="style()">
|
||||||
<i class="icon-crosshair"></i>
|
<i class="icon-crosshair"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<div class="umb-crop-thumbnail-container"
|
<div class="umb-crop-thumbnail-container"
|
||||||
ng-style="{height: height, width: width, border: '1px solid red', overflow: 'hidden'}">
|
ng-style="{height: height, width: width, overflow: 'hidden', position: 'relative'}">
|
||||||
<img src="{{src}}"
|
<img src="{{src}}" ng-style="preview" class="noScale" />
|
||||||
ng-style="{'margin-left': marginLeft, 'margin-top': marginTop}" class="noScale" />
|
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||||
|
//with a specified callback, this callback will receive an object with a selection on it
|
||||||
|
angular.module('umbraco').controller("Umbraco.PropertyEditors.ImageCropperController",
|
||||||
|
function($rootScope, $scope, mediaHelper, $timeout, editorState) {
|
||||||
|
|
||||||
|
//check the pre-values for multi-picker
|
||||||
|
var multiPicker = $scope.model.config.multiPicker !== '0' ? true : false;
|
||||||
|
|
||||||
|
//used to reference the part of the data we will either crop or "point"
|
||||||
|
$scope.currentCrop = undefined;
|
||||||
|
$scope.currentPoint = undefined;
|
||||||
|
|
||||||
|
var imgPath = mediaHelper.getImagePropertyValue({imageModel: editorState.current});
|
||||||
|
|
||||||
|
$scope.crop = function(crop){
|
||||||
|
$scope.currentCrop = crop;
|
||||||
|
$scope.currentPoint = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.done = function(){
|
||||||
|
$scope.currentCrop = undefined;
|
||||||
|
$scope.currentPoint = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Data sample
|
||||||
|
if(!$scope.model.value){
|
||||||
|
$scope.model.value = {
|
||||||
|
//image to crops
|
||||||
|
src: imgPath,
|
||||||
|
|
||||||
|
//global intrestpoint, used if no crop is specified
|
||||||
|
center: {left: 0.5, top: 0.4},
|
||||||
|
crops:{
|
||||||
|
thumbnail:
|
||||||
|
{
|
||||||
|
//crop dimensions
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
|
||||||
|
//crops in percentages
|
||||||
|
crop:{
|
||||||
|
"x1": 0.31731772342645215,
|
||||||
|
"y1": 0.17420325244997603,
|
||||||
|
"x2": -0.36246473116627076,
|
||||||
|
"y2": -0.30226197981593617
|
||||||
|
}
|
||||||
|
},
|
||||||
|
highrise:
|
||||||
|
{
|
||||||
|
width: 90,
|
||||||
|
height: 340
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<div class="umb-editor umb-mediapicker"
|
||||||
|
ng-controller="Umbraco.PropertyEditors.ImageCropperController">
|
||||||
|
|
||||||
|
<div ng-if="model.value.src">
|
||||||
|
<div style="border-bottom: 1px solid #f8f8f8; padding-bottom: 10px; margin-bottom: 15px;">
|
||||||
|
<div ng-if="currentCrop">
|
||||||
|
<div>
|
||||||
|
<umb-image-crop
|
||||||
|
height="{{currentCrop.height}}"
|
||||||
|
width= "{{currentCrop.width}}"
|
||||||
|
crop="currentCrop.crop"
|
||||||
|
center="model.value.center"
|
||||||
|
src="model.value.src" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href class="btn btn-success" ng-click="done()">Done</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="!currentCrop">
|
||||||
|
<umb-image-gravity
|
||||||
|
src="model.value.src"
|
||||||
|
center="model.value.center" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="umb-sortable-thumbnails">
|
||||||
|
<li class="tipmenu" ng-repeat="(key,value) in model.value.crops">
|
||||||
|
<a href ng-click="crop(value)">
|
||||||
|
<umb-image-thumbnail
|
||||||
|
center="model.value.center"
|
||||||
|
crop="value.crop"
|
||||||
|
src="model.value.src"
|
||||||
|
height="{{value.height}}"
|
||||||
|
width="{{value.width}}" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="tooltip bottom" ng-if="value.crop">
|
||||||
|
<div class="tooltip-arrow"></div>
|
||||||
|
<div class="tooltip-inner">
|
||||||
|
<a href ng-click="value.crop = undefined">Reset</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -11,7 +11,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
|||||||
//Data sample
|
//Data sample
|
||||||
var __img = {
|
var __img = {
|
||||||
//image to crop
|
//image to crop
|
||||||
src: "assets/img/mocks/image.jpg",
|
src: "assets/img/mocks/big-image.jpg",
|
||||||
|
|
||||||
//global gravity, used if not crop is specified
|
//global gravity, used if not crop is specified
|
||||||
gravity: {left: 0.5, top: 0.4},
|
gravity: {left: 0.5, top: 0.4},
|
||||||
@@ -20,8 +20,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
|||||||
thumbnail:
|
thumbnail:
|
||||||
{
|
{
|
||||||
//crop dimensions
|
//crop dimensions
|
||||||
width: "30px",
|
width: 100,
|
||||||
height: "40px",
|
height: 100,
|
||||||
|
|
||||||
//crops in percentages
|
//crops in percentages
|
||||||
crop:{ "left": 0.31731772342645215,
|
crop:{ "left": 0.31731772342645215,
|
||||||
@@ -33,8 +33,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
|||||||
|
|
||||||
banner:
|
banner:
|
||||||
{
|
{
|
||||||
width: "200px",
|
width: 340,
|
||||||
height: "20px",
|
height: 90,
|
||||||
|
|
||||||
crop:{ "left": 0.31731772342645215,
|
crop:{ "left": 0.31731772342645215,
|
||||||
"top": 0.17420325244997603,
|
"top": 0.17420325244997603,
|
||||||
@@ -45,8 +45,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
|||||||
|
|
||||||
highrise:
|
highrise:
|
||||||
{
|
{
|
||||||
width: "20px",
|
width: 90,
|
||||||
height: "200px"
|
height: 340
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -81,7 +81,6 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
|||||||
|
|
||||||
$scope.edit = function(image){
|
$scope.edit = function(image){
|
||||||
$scope.currentImage = image;
|
$scope.currentImage = image;
|
||||||
|
|
||||||
$scope.cropper.image = __img;
|
$scope.cropper.image = __img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,38 @@
|
|||||||
<div class="umb-editor umb-mediapicker" ng-controller="Umbraco.PropertyEditors.MediaPickerController">
|
<div class="umb-editor umb-mediapicker" ng-controller="Umbraco.PropertyEditors.MediaPickerController">
|
||||||
|
|
||||||
<div ng-if="cropper.image">
|
<div ng-if="cropper.image">
|
||||||
<div ng-if="cropper.crop">
|
<div ng-if="cropper.preset">
|
||||||
<umb-image-crop
|
<umb-image-crop
|
||||||
crop="cropper.crop"
|
height="{{cropper.preset.height}}"
|
||||||
gravity="cropper.image.gravity"
|
width= "{{cropper.preset.width}}"
|
||||||
|
crop="cropper.preset.crop"
|
||||||
src="cropper.image.src" />
|
src="cropper.image.src" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="cropper.grav">
|
<div ng-if="cropper.point">
|
||||||
<umb-image-gravity
|
<umb-image-gravity
|
||||||
height="'300px'"
|
height="200"
|
||||||
width= "'480px'"
|
width= "380"
|
||||||
src="cropper.grav.src"
|
src="cropper.image.src"
|
||||||
gravity="cropper.grav.gravity" />
|
gravity="cropper.point.gravity" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="umb-sortable-thumbnails">
|
<ul class="umb-sortable-thumbnails">
|
||||||
<li class="span2">
|
<li class="span2">
|
||||||
<img ng-src="{{cropper.image.src}}"
|
<img ng-src="{{cropper.image.src}}"
|
||||||
ng-click="cropper.crop = undefined; cropper.grav = cropper.image" />
|
ng-click="cropper.crop = undefined; cropper.point = cropper.image" />
|
||||||
|
original
|
||||||
</li>
|
</li>
|
||||||
<li ng-repeat="crop in cropper.image.crops">
|
|
||||||
<a href ng-click="cropper.crop = crop; cropper.grav = undefined">
|
<li ng-repeat="(key,value) in cropper.image.crops">
|
||||||
|
<a href ng-click="cropper.preset = value; cropper.point = undefined">
|
||||||
|
|
||||||
<umb-image-thumbnail
|
<umb-image-thumbnail
|
||||||
gravity="cropper.image.gravity"
|
gravity="cropper.image.gravity"
|
||||||
crop="cropper.image.crop"
|
crop="cropper.image.crop"
|
||||||
src="cropper.image.src"
|
src="cropper.image.src"
|
||||||
height="crop.height"
|
height="value.height"
|
||||||
width="crop.width">
|
width="value.width">
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -38,7 +41,7 @@
|
|||||||
|
|
||||||
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
|
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
|
||||||
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
|
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
|
||||||
<img ng-src="{{image.thumbnail}}" alt="" ng-show="image.src">
|
<img ng-src="{{image.thumbnail}}" ng-click="edit(image)" alt="" ng-show="image.src">
|
||||||
|
|
||||||
<span class="icon-holder" ng-hide="image.src">
|
<span class="icon-holder" ng-hide="image.src">
|
||||||
<i class="icon {{image.icon}} large" ></i>
|
<i class="icon {{image.icon}} large" ></i>
|
||||||
|
|||||||
11
src/Umbraco.Web.UI/Properties/Settings.Designer.cs
generated
11
src/Umbraco.Web.UI/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.34003
|
// Runtime Version:4.0.30319.18408
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -22,5 +22,14 @@ namespace Umbraco.Web.UI.Properties {
|
|||||||
return defaultInstance;
|
return defaultInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("http://our.umbraco.org/umbraco/webservices/api/repository.asmx")]
|
||||||
|
public string Umbraco_Web_UI_org_umbraco_our_Repository {
|
||||||
|
get {
|
||||||
|
return ((string)(this["Umbraco_Web_UI_org_umbraco_our_Repository"]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Umbraco.Web.UI.Properties" GeneratedClassName="Settings">
|
||||||
<Profiles />
|
<Profiles />
|
||||||
<Settings />
|
<Settings>
|
||||||
|
<Setting Name="Umbraco_Web_UI_org_umbraco_our_Repository" Type="System.String" Scope="Application">
|
||||||
|
<Value Profile="(Default)">http://our.umbraco.org/umbraco/webservices/api/repository.asmx</Value>
|
||||||
|
</Setting>
|
||||||
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@@ -5,10 +5,9 @@
|
|||||||
@using Umbraco.Web
|
@using Umbraco.Web
|
||||||
@using Umbraco.Web.Editors
|
@using Umbraco.Web.Editors
|
||||||
@using umbraco
|
@using umbraco
|
||||||
|
|
||||||
@inherits System.Web.Mvc.WebViewPage
|
@inherits System.Web.Mvc.WebViewPage
|
||||||
@{
|
|
||||||
Layout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@
|
|||||||
|
|
||||||
@*And finally we can load in our angular app*@
|
@*And finally we can load in our angular app*@
|
||||||
<script type="text/javascript" src="lib/yepnope/yepnope.min.js"></script>
|
<script type="text/javascript" src="lib/yepnope/yepnope.min.js"></script>
|
||||||
<script type="text/javascript" src="@Url.Action("Application", "BackOffice")"></script>
|
<script type="text/javascript" src="@Url.GetUrlWithTimeStamp("Application", "BackOffice")"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
|
|
||||||
<asp:Content ContentPlaceHolderID="body" runat="server">
|
<asp:Content ContentPlaceHolderID="body" runat="server">
|
||||||
<cc1:UmbracoPanel ID="Panel1" Text="Install package" runat="server" Width="496px"
|
<cc1:UmbracoPanel ID="Panel1" Text="Install package" runat="server" Width="496px"
|
||||||
Height="584px">
|
Height="584px">
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
|
|
||||||
<cc1:Feedback ID="fb" Style="margin-top: 7px;" runat="server" />
|
<cc1:Feedback ID="fb" Style="margin-top: 7px;" runat="server" />
|
||||||
<cc1:Pane ID="pane_upload" runat="server" Text="Install from local package file">
|
<cc1:Pane ID="pane_upload" runat="server" Text="Install from local package file">
|
||||||
|
|
||||||
<cc1:PropertyPanel runat="server" Text="">
|
<cc1:PropertyPanel runat="server" Text="">
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
<h4>
|
<h4>
|
||||||
@@ -94,6 +96,7 @@
|
|||||||
<cc1:PropertyPanel ID="PropertyPanel2" runat="server">
|
<cc1:PropertyPanel ID="PropertyPanel2" runat="server">
|
||||||
<asp:Button ID="Button1" OnClick="fetchProtectedPackage" Text="Login" runat="server" /></cc1:PropertyPanel>
|
<asp:Button ID="Button1" OnClick="fetchProtectedPackage" Text="Login" runat="server" /></cc1:PropertyPanel>
|
||||||
</cc1:Pane>
|
</cc1:Pane>
|
||||||
|
|
||||||
<asp:Panel ID="pane_acceptLicense" runat="server" Visible="false">
|
<asp:Panel ID="pane_acceptLicense" runat="server" Visible="false">
|
||||||
<br />
|
<br />
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
@@ -103,6 +106,7 @@
|
|||||||
notifies you the install is completed.
|
notifies you the install is completed.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<cc1:Pane ID="pane_acceptLicenseInner" runat="server">
|
<cc1:Pane ID="pane_acceptLicenseInner" runat="server">
|
||||||
<cc1:PropertyPanel ID="PropertyPanel3" runat="server" Text="Name">
|
<cc1:PropertyPanel ID="PropertyPanel3" runat="server" Text="Name">
|
||||||
<asp:Label ID="LabelName" runat="server" /></cc1:PropertyPanel>
|
<asp:Label ID="LabelName" runat="server" /></cc1:PropertyPanel>
|
||||||
@@ -121,8 +125,8 @@
|
|||||||
<cc1:PropertyPanel ID="pp_unsecureFiles" runat="server" Visible="false" Text=" ">
|
<cc1:PropertyPanel ID="pp_unsecureFiles" runat="server" Visible="false" Text=" ">
|
||||||
|
|
||||||
<div class="alert alert-error" style="width: 370px;">
|
<div class="alert alert-error" style="width: 370px;">
|
||||||
<h4>
|
<h4>Binary files in the package!</h4>
|
||||||
Binary files in the package!</h4>
|
|
||||||
<a class="toggle-report" href="#">Read more...</a>
|
<a class="toggle-report" href="#">Read more...</a>
|
||||||
<div style="display:none;">
|
<div style="display:none;">
|
||||||
<p>
|
<p>
|
||||||
@@ -140,6 +144,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
|
|
||||||
<cc1:PropertyPanel ID="LegacyPropertyEditorPanel" runat="server" Visible="false" Text=" ">
|
<cc1:PropertyPanel ID="LegacyPropertyEditorPanel" runat="server" Visible="false" Text=" ">
|
||||||
@@ -158,6 +163,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
|
|
||||||
<cc1:PropertyPanel ID="BinaryFileErrorsPanel" runat="server" Visible="false" Text=" ">
|
<cc1:PropertyPanel ID="BinaryFileErrorsPanel" runat="server" Visible="false" Text=" ">
|
||||||
<div class="alert alert-error" style="width: 370px;">
|
<div class="alert alert-error" style="width: 370px;">
|
||||||
<h4>
|
<h4>
|
||||||
@@ -198,6 +204,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
|
|
||||||
<cc1:PropertyPanel ID="pp_templateConflicts" runat="server" Visible="false" Text=" ">
|
<cc1:PropertyPanel ID="pp_templateConflicts" runat="server" Visible="false" Text=" ">
|
||||||
<div class="alert alert-error" style="width: 370px;">
|
<div class="alert alert-error" style="width: 370px;">
|
||||||
<h4>
|
<h4>
|
||||||
@@ -219,6 +226,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
|
|
||||||
<cc1:PropertyPanel ID="pp_stylesheetConflicts" runat="server" Visible="false" Text=" ">
|
<cc1:PropertyPanel ID="pp_stylesheetConflicts" runat="server" Visible="false" Text=" ">
|
||||||
<div class="alert alert-error" style="width: 370px;">
|
<div class="alert alert-error" style="width: 370px;">
|
||||||
<h4>
|
<h4>
|
||||||
@@ -240,6 +248,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
|
|
||||||
<cc1:PropertyPanel runat="server" Text=" ">
|
<cc1:PropertyPanel runat="server" Text=" ">
|
||||||
<br />
|
<br />
|
||||||
<div style="display: none;" id="installingMessage">
|
<div style="display: none;" id="installingMessage">
|
||||||
@@ -251,6 +260,7 @@
|
|||||||
OnClick="startInstall"></asp:Button>
|
OnClick="startInstall"></asp:Button>
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
</cc1:Pane>
|
</cc1:Pane>
|
||||||
|
|
||||||
</asp:Panel>
|
</asp:Panel>
|
||||||
<cc1:Pane ID="pane_installing" runat="server" Visible="false" Text="Installing package">
|
<cc1:Pane ID="pane_installing" runat="server" Visible="false" Text="Installing package">
|
||||||
<cc1:PropertyPanel runat="server">
|
<cc1:PropertyPanel runat="server">
|
||||||
@@ -258,7 +268,9 @@
|
|||||||
<asp:Literal ID="lit_installStatus" runat="server" />
|
<asp:Literal ID="lit_installStatus" runat="server" />
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
</cc1:Pane>
|
</cc1:Pane>
|
||||||
|
|
||||||
<cc1:Pane ID="pane_optional" runat="server" Visible="false" />
|
<cc1:Pane ID="pane_optional" runat="server" Visible="false" />
|
||||||
|
|
||||||
<cc1:Pane ID="pane_success" runat="server" Text="Package is installed" Visible="false">
|
<cc1:Pane ID="pane_success" runat="server" Text="Package is installed" Visible="false">
|
||||||
<cc1:PropertyPanel runat="server">
|
<cc1:PropertyPanel runat="server">
|
||||||
|
|
||||||
@@ -276,12 +288,14 @@
|
|||||||
|
|
||||||
</cc1:PropertyPanel>
|
</cc1:PropertyPanel>
|
||||||
</cc1:Pane>
|
</cc1:Pane>
|
||||||
|
|
||||||
<cc1:Pane ID="pane_refresh" runat="server" Text="Browser is reloading" Visible="false">
|
<cc1:Pane ID="pane_refresh" runat="server" Text="Browser is reloading" Visible="false">
|
||||||
<cc1:PropertyPanel runat="server">
|
<cc1:PropertyPanel runat="server">
|
||||||
|
|
||||||
<div class="alert alert-block">
|
<div class="alert alert-block">
|
||||||
Please wait while the browser is reloaded...
|
Please wait while the browser is reloaded...
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
//This is all a bit zany with double encoding because we have a URL in a hash (#) url part
|
//This is all a bit zany with double encoding because we have a URL in a hash (#) url part
|
||||||
@@ -291,8 +305,15 @@
|
|||||||
var umbPath = "<%=GlobalSettings.Path%>";
|
var umbPath = "<%=GlobalSettings.Path%>";
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var mainWindow = UmbClientMgr.mainWindow();
|
var mainWindow = UmbClientMgr.mainWindow();
|
||||||
|
|
||||||
|
//kill the tree and template cache
|
||||||
|
if (mainWindow.UmbClientMgr) {
|
||||||
|
mainWindow.UmbClientMgr._packageInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
var baseUrl = mainWindow.location.href.substr(0, mainWindow.location.href.indexOf("#/developer/framed/"));
|
var baseUrl = mainWindow.location.href.substr(0, mainWindow.location.href.indexOf("#/developer/framed/"));
|
||||||
var framedUrl = baseUrl + "#/developer/framed/";
|
var framedUrl = baseUrl + "#/developer/framed/";
|
||||||
var refreshUrl = framedUrl + encodeURIComponent(encodeURIComponent(umbPath + "/developer/packages/installer.aspx?" + refreshQuery));
|
var refreshUrl = framedUrl + encodeURIComponent(encodeURIComponent(umbPath + "/developer/packages/installer.aspx?" + refreshQuery));
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ namespace Umbraco.Web.Editors
|
|||||||
{
|
{
|
||||||
public IEnumerable<Section> GetSections()
|
public IEnumerable<Section> GetSections()
|
||||||
{
|
{
|
||||||
return Services.SectionService.GetAllowedSections(UmbracoUser.Id)
|
var sections = Services.SectionService.GetAllowedSections(UmbracoUser.Id);
|
||||||
.Select(Mapper.Map<Core.Models.Section, Section>);
|
return sections.Select(Mapper.Map<Core.Models.Section, Section>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Umbraco.Core;
|
||||||
|
using Umbraco.Core.PropertyEditors;
|
||||||
|
|
||||||
|
namespace Umbraco.Web.PropertyEditors
|
||||||
|
{
|
||||||
|
[PropertyEditor(Constants.PropertyEditors.ImageCropperAlias, "Image Cropper", "imagecropper", ValueType = "JSON", HideLabel = false)]
|
||||||
|
public class ImageCropperPropertyEditor : PropertyEditor
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,10 +41,17 @@ namespace Umbraco.Web.UI.JavaScript
|
|||||||
public string GetJavascriptInitialization(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
|
public string GetJavascriptInitialization(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
|
||||||
{
|
{
|
||||||
var result = GetJavascriptInitializationArray(httpContext, umbracoInit, additionalJsFiles);
|
var result = GetJavascriptInitializationArray(httpContext, umbracoInit, additionalJsFiles);
|
||||||
|
var noCache = string.Empty;
|
||||||
|
|
||||||
|
//if debugging, add timestamp, if in production CDF will append CDF version (and should also append umb version)
|
||||||
|
if (httpContext.IsDebuggingEnabled)
|
||||||
|
noCache = Resources.JsNoCache;
|
||||||
|
|
||||||
return ParseMain(
|
|
||||||
result.ToString(),
|
return ParseMain(
|
||||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco));
|
noCache,
|
||||||
|
result.ToString(),
|
||||||
|
IOHelper.ResolveUrl(SystemDirectories.Umbraco));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JArray GetJavascriptInitializationArray(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
|
public JArray GetJavascriptInitializationArray(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
"##JsNoCache##"
|
||||||
yepnope({
|
yepnope({
|
||||||
load: [
|
load: [
|
||||||
'lib/jquery/jquery-2.0.3.min.js',
|
'lib/jquery/jquery-2.0.3.min.js',
|
||||||
|
|||||||
77
src/Umbraco.Web/UI/JavaScript/Resources.Designer.cs
generated
77
src/Umbraco.Web/UI/JavaScript/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18046
|
// Runtime Version:4.0.30319.18408
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -62,23 +62,23 @@ namespace Umbraco.Web.UI.JavaScript {
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to [
|
/// Looks up a localized string similar to [
|
||||||
/// 'lib/jquery/jquery-1.8.2.min.js',
|
/// 'lib/jquery/jquery-ui-1.10.3.custom.min.js',
|
||||||
/// 'lib/jquery/jquery.cookie.js',
|
|
||||||
/// 'lib/angular/angular.min.js',
|
|
||||||
/// 'lib/bootstrap/js/bootstrap.js',
|
|
||||||
/// 'lib/underscore/underscore.js',
|
|
||||||
/// 'lib/umbraco/Extensions.js',
|
|
||||||
///
|
///
|
||||||
/// 'js/app.js',
|
/// /*
|
||||||
|
/// 'lib/jquery/jquery-ui-1.10.3.custom.min.js',
|
||||||
|
/// 'lib/jquery/jquery.ui.core.min.js',
|
||||||
|
/// 'lib/jquery/jquery.ui.widget.min.js',
|
||||||
|
/// 'lib/jquery/jquery.ui.mouse.min.js',
|
||||||
|
/// 'lib/jquery/jquery.ui.sortable.min.js',
|
||||||
|
/// */
|
||||||
///
|
///
|
||||||
/// 'js/umbraco.resources.js',
|
/// 'lib/angular/1.1.5/angular-cookies.min.js',
|
||||||
/// 'js/umbraco.directives.js',
|
/// 'lib/angular/1.1.5/angular-mobile.js',
|
||||||
/// 'js/umbraco.filters.js',
|
/// 'lib/angular/1.1.5/angular-sanitize.min.js',
|
||||||
/// 'js/umbraco.services.js',
|
///
|
||||||
/// 'js/umbraco.security.js',
|
/// 'lib/angular/angular-ui-sortable.js',
|
||||||
/// 'js/umbraco.controllers.js',
|
///
|
||||||
/// 'js/routes.js'
|
/// 'lib/jquery/jquery.u [rest of string was truncated]";.
|
||||||
///].
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string JsInitialize {
|
internal static string JsInitialize {
|
||||||
get {
|
get {
|
||||||
@@ -87,18 +87,45 @@ namespace Umbraco.Web.UI.JavaScript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to yepnope({
|
/// Looks up a localized string similar to yepnope.addFilter(function (resourceObj) {
|
||||||
///
|
/// var url = resourceObj.url;
|
||||||
/// load: "##JsInitialize##",
|
/// var _op = "?";
|
||||||
///
|
/// if(url.indexOf("lib/") === 0 || url.indexOf("js/umbraco.") === 0){
|
||||||
/// complete: function () {
|
/// return resourceObj;
|
||||||
/// jQuery(document).ready(function () {
|
|
||||||
/// angular.bootstrap(document, ['umbraco']);
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// }
|
/// }
|
||||||
|
/// if(url.indexOf("?") > 0){
|
||||||
|
/// _op = "&";
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// resourceObj.url = resourceObj.url + _op + "umb__rnd=" + (new Date).getTime();
|
||||||
|
/// return resourceObj;
|
||||||
///});.
|
///});.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
internal static string JsNoCache {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("JsNoCache", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to "##JsNoCache##"
|
||||||
|
///yepnope({
|
||||||
|
/// load: [
|
||||||
|
/// 'lib/jquery/jquery-2.0.3.min.js',
|
||||||
|
/// 'lib/angular/1.1.5/angular.min.js',
|
||||||
|
/// 'lib/underscore/underscore.js',
|
||||||
|
/// ],
|
||||||
|
/// complete: function () {
|
||||||
|
/// yepnope({
|
||||||
|
/// load: "##JsInitialize##",
|
||||||
|
/// complete: function () {
|
||||||
|
///
|
||||||
|
/// //we need to set the legacy UmbClientMgr path
|
||||||
|
/// UmbClientMgr.setUmbracoPath('"##UmbracoPath##"');
|
||||||
|
///
|
||||||
|
/// jQuery(document).ready(function () {
|
||||||
|
/// [rest of string was truncated]";.
|
||||||
|
/// </summary>
|
||||||
internal static string Main {
|
internal static string Main {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Main", resourceCulture);
|
return ResourceManager.GetString("Main", resourceCulture);
|
||||||
|
|||||||
@@ -121,6 +121,21 @@
|
|||||||
<data name="JsInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="JsInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>jsinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
<value>jsinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="JsNoCache" xml:space="preserve">
|
||||||
|
<value>yepnope.addFilter(function (resourceObj) {
|
||||||
|
var url = resourceObj.url;
|
||||||
|
var _op = "?";
|
||||||
|
if(url.indexOf("lib/") === 0 || url.indexOf("js/umbraco.") === 0){
|
||||||
|
return resourceObj;
|
||||||
|
}
|
||||||
|
if(url.indexOf("?") > 0){
|
||||||
|
_op = "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceObj.url = resourceObj.url + _op + "umb__rnd=" + (new Date).getTime();
|
||||||
|
return resourceObj;
|
||||||
|
});</value>
|
||||||
|
</data>
|
||||||
<data name="Main" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="Main" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>Main.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
<value>Main.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -342,6 +342,7 @@
|
|||||||
<Compile Include="NotificationServiceExtensions.cs" />
|
<Compile Include="NotificationServiceExtensions.cs" />
|
||||||
<Compile Include="PropertyEditors\ColorListPreValueEditor.cs" />
|
<Compile Include="PropertyEditors\ColorListPreValueEditor.cs" />
|
||||||
<Compile Include="PropertyEditors\EmailAddressPropertyEditor.cs" />
|
<Compile Include="PropertyEditors\EmailAddressPropertyEditor.cs" />
|
||||||
|
<Compile Include="PropertyEditors\ImageCropperPropertyEditor.cs" />
|
||||||
<Compile Include="PropertyEditors\ListViewPropertyEditor.cs" />
|
<Compile Include="PropertyEditors\ListViewPropertyEditor.cs" />
|
||||||
<Compile Include="PropertyEditors\MacroContainerPropertyEditor.cs" />
|
<Compile Include="PropertyEditors\MacroContainerPropertyEditor.cs" />
|
||||||
<Compile Include="PropertyEditors\MarkdownPropertyEditor.cs" />
|
<Compile Include="PropertyEditors\MarkdownPropertyEditor.cs" />
|
||||||
@@ -1995,6 +1996,7 @@
|
|||||||
<EmbeddedResource Include="UI\JavaScript\Resources.resx">
|
<EmbeddedResource Include="UI\JavaScript\Resources.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Mvc\Strings.resx">
|
<EmbeddedResource Include="Mvc\Strings.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
|||||||
@@ -148,5 +148,29 @@ namespace Umbraco.Web
|
|||||||
return url.Action(actionName, controllerName, routeVals);
|
return url.Action(actionName, controllerName, routeVals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the Url for an action with a cache-bursting hash appended
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <param name="actionName"></param>
|
||||||
|
/// <param name="controllerName"></param>
|
||||||
|
/// <param name="routeVals"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetUrlWithTimeStamp(this UrlHelper url, string actionName, string controllerName, RouteValueDictionary routeVals = null)
|
||||||
|
{
|
||||||
|
var applicationJs = url.Action(actionName, controllerName, routeVals);
|
||||||
|
|
||||||
|
//make a hash of umbraco and client dependency version
|
||||||
|
//in case the user bypasses the installer and just bumps the web.config or clientdep config
|
||||||
|
var umb_rnd = Umbraco.Core.Configuration.GlobalSettings.CurrentVersion + "_" + ClientDependency.Core.Config.ClientDependencySettings.Instance.Version;
|
||||||
|
|
||||||
|
//if in debug mode, always burst the cache
|
||||||
|
if (Umbraco.Core.Configuration.GlobalSettings.DebugMode)
|
||||||
|
umb_rnd += "_" + System.DateTime.Now.Ticks;
|
||||||
|
|
||||||
|
applicationJs = applicationJs + "?umb__rnd=" + umb_rnd;
|
||||||
|
return applicationJs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,8 +350,13 @@ namespace umbraco.presentation.developer.packages
|
|||||||
/// <param name="packageId"></param>
|
/// <param name="packageId"></param>
|
||||||
/// <param name="dir"></param>
|
/// <param name="dir"></param>
|
||||||
private void PerformPostInstallCleanup(int packageId, string dir)
|
private void PerformPostInstallCleanup(int packageId, string dir)
|
||||||
{
|
{
|
||||||
_installer.InstallCleanUp(packageId, dir);
|
_installer.InstallCleanUp(packageId, dir);
|
||||||
|
|
||||||
|
// Update ClientDependency version
|
||||||
|
var clientDependencyConfig = new Umbraco.Core.Configuration.ClientDependencyConfiguration();
|
||||||
|
var clientDependencyUpdated = clientDependencyConfig.IncreaseVersionNumber();
|
||||||
|
|
||||||
//clear the tree cache - we'll do this here even though the browser will reload, but just in case it doesn't can't hurt.
|
//clear the tree cache - we'll do this here even though the browser will reload, but just in case it doesn't can't hurt.
|
||||||
ClientTools.ClearClientTreeCache().RefreshTree("packager");
|
ClientTools.ClearClientTreeCache().RefreshTree("packager");
|
||||||
TreeDefinitionCollection.Instance.ReRegisterTrees();
|
TreeDefinitionCollection.Instance.ReRegisterTrees();
|
||||||
|
|||||||
Reference in New Issue
Block a user