Merge remote-tracking branch 'origin/dev-v7' into 7.4.0

Conflicts:
	build/RevertToCleanInstall.bat
	build/RevertToEmptyInstall.bat
	src/Umbraco.Web.UI.Client/src/canvasdesigner.loader.js
	src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbavatar.directive.js
	src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js
	src/Umbraco.Web.UI.Client/src/less/pages/login.less
	src/Umbraco.Web.UI.Client/src/views/components/application/umb-avatar.html
	src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html
This commit is contained in:
Shannon
2015-11-09 12:33:53 +01:00
61 changed files with 744 additions and 375 deletions

View File

@@ -1 +1,17 @@
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url('../fonts/opensans/OpenSans-Regular-webfont.eot');
src: local('Open Sans'), local('OpenSans'), url('../fonts/opensans/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/opensans/OpenSans-Regular-webfont.ttf') format('truetype'), url('../fonts/opensans/OpenSans-Regular-webfont.svg#open_sansregular') format('svg');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url('../fonts/opensans/OpenSans-Semibold-webfont.eot');
src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('../fonts/opensans/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/opensans/OpenSans-Semibold-webfont.ttf') format('truetype'), url('../fonts/opensans/OpenSans-Semibold-webfont.svg#open_sanssemibold') format('svg');
}
abbr,address,article,aside,audio,b,blockquote,body,canvas,caption,cite,code,dd,del,details,dfn,div,dl,dt,em,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,samp,section,small,span,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,ul,var,video{margin:0;padding:0;outline:0;border:0;background:0 0;vertical-align:baseline;font-size:100%}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}a{margin:0;padding:0;background:0 0;vertical-align:baseline;font-size:100%}ins{background-color:#ff9;color:#000;text-decoration:none}mark{background-color:#ff9;color:#000;font-weight:700;font-style:italic}del{text-decoration:line-through}abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help}table{border-spacing:0;border-collapse:collapse}hr{display:block;margin:1em 0;padding:0;height:1px;border:0;border-top:1px solid #ccc}input,select{vertical-align:middle}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{height:100%;width:100%;color:#fff;font-family:'Open Sans',sans-serif;font-weight:400;font-size:.9375em;line-height:1.5}h1{font-size:1.7em;margin:40px auto 10px;font-weight:700}h2{font-size:1.35em;margin:0 auto .4em;font-weight:700}h3{font-size:1em;font-weight:400;font-style:italic}p{font-size:1em;line-height:1.6}p+a{margin-top:1rem;display:inline-block}a,a:active,a:visited{text-decoration:none}.cta{margin:4.5em auto 1.5em;padding-bottom:4.5em}.button,.button:visited{padding:.9375em 1.875em;border-radius:.1em;font-weight:600;font-size:1.2em;background:#2e99f4;color:#fff;display:inline-block;border:none;transition:all 200ms ease-in-out}.button:hover,.button:visited:hover{border-bottom:none;background:#0c80e3}section{background:url(../img/nonodesbg.jpg) center center/cover;height:100%;width:100%;display:table;padding:3em 1.75em}section a,section a:focus,section a:visited{color:#46a5f5;font-size:1.1625em;border-bottom:1px solid transparent;transition:border-bottom 100ms ease-in-out}section a:focus:hover,section a:hover,section a:visited:hover{border-bottom:1px solid}section:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.17);background:linear-gradient(45deg,rgba(85,98,112,.1) 10%,rgba(255,107,107,.1) 95%);z-index:0}section article{display:table-cell;vertical-align:middle;margin:0 auto;text-align:center;position:relative;z-index:100}section article>div{max-width:60em;margin:0 auto}section .logo{background:url(../img/logo.png) no-repeat;width:91px;height:91px;margin:0 auto}section .row{overflow:hidden}section .row .col{text-align:left;width:100%}section .row .col:nth-child(2){margin-top:3em}@media screen and (min-width:48em){body,html{font-size:1em}h1{font-size:2.5em;margin:70px auto 0;letter-spacing:.5px}h2{font-size:1.4375em;margin:0 auto 1em}h3{font-size:1.2em}a{font-size:1.1rem;font-weight:600}p+a{margin-top:3rem}.cta{margin:7.5em auto 2.5em;border-bottom:1px solid rgba(255,255,255,.5);padding-bottom:7.5em}section{padding:0 15px}section .row .col{float:left;width:50%;padding-right:5%;display:inline-block}section .row .col:nth-child(2){padding-right:0;padding-left:5%;margin-top:0}.button{font-size:1.1625em}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,16 +1,18 @@
LazyLoad.js([
'/Umbraco/lib/jquery/jquery.min.js',
'/Umbraco/lib/jquery-ui/jquery-ui.min.js',
'/Umbraco/lib/angular/1.1.5/angular.min.js',
'/Umbraco/lib/underscore/underscore-min.js',
'/Umbraco/js/app.js',
'/Umbraco/js/umbraco.resources.js',
'/Umbraco/js/umbraco.services.js',
'/Umbraco/js/umbraco.security.js',
'/Umbraco/ServerVariables',
'/Umbraco/lib/spectrum/spectrum.js',
'/Umbraco/js/canvasdesigner.panel.js',
'../lib/jquery/jquery.min.js',
'../lib/jquery-ui/jquery-ui.min.js',
'../lib/angular/1.1.5/angular.min.js',
'../lib/underscore/underscore-min.js',
'../lib/umbraco/Extensions.js',
'../js/app.js',
'../js/umbraco.resources.js',
'../js/umbraco.services.js',
'../js/umbraco.security.js',
'../ServerVariables',
'../lib/spectrum/spectrum.js',
'../js/canvasdesigner.panel.js',
], function () {
jQuery(document).ready(function () {
angular.bootstrap(document, ['Umbraco.canvasdesigner']);

View File

@@ -9,11 +9,6 @@ var canvasdesignerConfig = {
schema: "body",
selector: "body",
editors: [
{
type: "wide",
category: "Dimension",
name: "Layout"
},
{
type: "background",
category: "Color",

View File

@@ -104,6 +104,30 @@ angular.module("Umbraco.canvasdesigner")
}
};
function loadFont(font, variant) {
WebFont.load({
google: {
families: [font.fontFamily + ":" + variant]
},
loading: function () {
console.log('loading');
},
active: function () {
$scope.selectedFont = font;
$scope.selectedFont.fontWeight = googleGetWeight(variant);
$scope.selectedFont.fontStyle = googleGetStyle(variant);
// If $apply isn't called, the new font family isn't applied until the next user click.
$scope.change({
fontFamily: $scope.selectedFont.fontFamily,
fontType: $scope.selectedFont.fontType,
fontWeight: $scope.selectedFont.fontWeight,
fontStyle: $scope.selectedFont.fontStyle,
});
}
});
}
var webFontScriptLoaded = false;
$scope.showFontPreview = function (font, variant) {
if (!variant)
@@ -114,27 +138,19 @@ angular.module("Umbraco.canvasdesigner")
// Font needs to be independently loaded in the iframe for live preview to work.
document.getElementById("resultFrame").contentWindow.getFont(font.fontFamily + ":" + variant);
WebFont.load({
google: {
families: [font.fontFamily + ":" + variant]
},
loading: function () {
console.log('loading');
},
active: function () {
$scope.selectedFont = font;
$scope.selectedFont.fontWeight = googleGetWeight(variant);
$scope.selectedFont.fontStyle = googleGetStyle(variant);
// If $apply isn't called, the new font family isn't applied until the next user click.
$scope.change({
fontFamily: $scope.selectedFont.fontFamily,
fontType: $scope.selectedFont.fontType,
fontWeight: $scope.selectedFont.fontWeight,
fontStyle: $scope.selectedFont.fontStyle,
if (!webFontScriptLoaded) {
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
.done(function() {
webFontScriptLoaded = true;
loadFont(font, variant);
})
.fail(function() {
console.log('error loading webfont');
});
}
});
}
else {
loadFont(font, variant);
}
}
else {

View File

@@ -1,27 +0,0 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbAvatar
* @restrict E
**/
function avatarDirective() {
return {
restrict: "E", // restrict to an element
replace: true, // replace the html element with the template
templateUrl: 'views/components/application/umb-avatar.html',
scope: {
name: '@',
email: '@',
hash: '@'
},
link: function(scope, element, attr, ctrl) {
scope.$watch("hash", function (val) {
//set the gravatar url
scope.gravatar = "https://www.gravatar.com/avatar/" + val + "?s=40";
});
}
};
}
angular.module('umbraco.directives').directive("umbAvatar", avatarDirective);

View File

@@ -13,14 +13,16 @@ angular.module("umbraco.directives")
restrict: 'E',
replace: true,
templateUrl: 'views/components/property/umb-property.html',
link: function(scope) {
scope.propertyAlias = Umbraco.Sys.ServerVariables.isDebuggingEnabled === true ? scope.property.alias : null;
},
//Define a controller for this directive to expose APIs to other directives
controller: function ($scope, $timeout) {
var self = this;
//set the API properties/methods
self.property = $scope.property;
self.setPropertyError = function(errorMsg) {
$scope.property.propertyErrorMessage = errorMsg;

View File

@@ -149,6 +149,12 @@ function entityResource($q, $http, umbRequestHelper) {
_.each(ids, function(item) {
query += "ids=" + item + "&";
});
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
if (ids.length === 0) {
query += "ids=&";
}
query += "type=" + type;
return umbRequestHelper.resourcePromise(

View File

@@ -1,6 +1,6 @@
angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
// This http interceptor listens for authentication successes and failures
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', function ($injector, queue, notifications) {
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'requestInterceptorFilter', function ($injector, queue, notifications, requestInterceptorFilter) {
return function(promise) {
return promise.then(
@@ -19,6 +19,19 @@ angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
return promise;
}, function(originalResponse) {
// Intercept failed requests
//Here we'll check if we should ignore the error, this will be based on an original header set
var headers = originalResponse.config ? originalResponse.config.headers : {};
if (headers["x-umb-ignore-error"] === "ignore") {
//exit/ignore
return promise;
}
var filtered = _.find(requestInterceptorFilter(), function(val) {
return originalResponse.config.url.indexOf(val) > 0;
});
if (filtered) {
return promise;
}
//A 401 means that the user is not logged in
if (originalResponse.status === 401) {
@@ -72,6 +85,10 @@ angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
};
}])
.value('requestInterceptorFilter', function() {
return ["www.gravatar.com"];
})
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('securityInterceptor');

View File

@@ -1,5 +1,5 @@
angular.module('umbraco.services')
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper) {
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper, $http) {
var currentUser = null;
var lastUserId = null;
@@ -250,7 +250,7 @@ angular.module('umbraco.services')
}
setCurrentUser(data);
currentUser.avatar = 'https://www.gravatar.com/avatar/' + data.emailHash + '?s=40&d=404';
deferred.resolve(currentUser);
});

View File

@@ -372,9 +372,6 @@ function xmlhelper($http) {
fromJson: function (json) {
var xml = x2js.json2xml_str(json);
return xml;
},
parseFeed: function (url) {
return $http.jsonp('//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url));
}
};
}

View File

@@ -13,7 +13,11 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
//the null is important because we do an explicit bool check on this in the view
//the avatar is by default the umbraco logo
$scope.authenticated = null;
$scope.avatar = "assets/img/application/logo.png";
$scope.avatar = [
{ value: "assets/img/application/logo.png" },
{ value: "assets/img/application/logo@2x.png" },
{ value: "assets/img/application/logo@3x.png" }
];
$scope.touchDevice = appState.getGlobalState("touchDevice");
@@ -84,20 +88,32 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
tmhDynamicLocale.set($scope.user.locale);
}
if($scope.user.emailHash){
$timeout(function () {
//yes this is wrong..
$("#avatar-img").fadeTo(1000, 0, function () {
$timeout(function () {
//this can be null if they time out
if ($scope.user && $scope.user.emailHash) {
$scope.avatar = "https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=mm";
}
if ($scope.user.emailHash) {
//let's attempt to load the avatar, it might not exist or we might not have
// internet access so we'll detect it first
$http.get("https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=404")
.then(
function successCallback(response) {
$("#avatar-img").fadeTo(1000, 0, function () {
$scope.$apply(function () {
//this can be null if they time out
if ($scope.user && $scope.user.emailHash) {
var avatarBaseUrl = "https://www.gravatar.com/avatar/",
hash = $scope.user.emailHash;
$scope.avatar = [
{ value: avatarBaseUrl + hash + ".jpg?s=30&d=mm" },
{ value: avatarBaseUrl + hash + ".jpg?s=60&d=mm" },
{ value: avatarBaseUrl + hash + ".jpg?s=90&d=mm" }
];
}
});
$("#avatar-img").fadeTo(1000, 1);
});
}, function errorCallback(response) {
//cannot load it from the server so we cannot do anything
});
$("#avatar-img").fadeTo(1000, 1);
});
}, 3000);
}
}));

View File

@@ -42,7 +42,7 @@
<div class="control-group">
<label class="control-label" for="server">Server</label>
<div class="controls">
<input type="text" name="server" placeholder="127.0.0.1/SQLEXPRESS" required ng-model="installer.current.model.server" />
<input type="text" name="server" placeholder="127.0.0.1\SQLEXPRESS" required ng-model="installer.current.model.server" />
<small class="inline-help">Enter server domain or IP</small>
</div>
</div>

View File

@@ -8,7 +8,7 @@
background-size: 30px 30px !important;
color: @white;
position: absolute;
z-index: 2000;
z-index: 10000;
top: 0px;
left: 0px;
margin: 0 !Important;

View File

@@ -81,8 +81,8 @@ ul.sections li.avatar a {
}
ul.sections li.avatar a img {
border-radius: 16px;
width: 30px
border-radius: 50%;
width: 30px;
}
.faded ul.sections li {

View File

@@ -1,3 +0,0 @@
<a href="#" title="{{name}}">
<img ng-src="{{gravatar}}" />
</a>

View File

@@ -3,7 +3,7 @@
<ul class="sections">
<li class="avatar">
<a href="#" ng-click="avatarClick()" hotkey="ctrl+shift+u" title="{{user.name}}" prevent-default>
<img id="avatar-img" ng-src="{{avatar}}" />
<img id="avatar-img" ng-src="{{avatar[0].value}}" ng-srcset="{{avatar[1].value}} 2x, {{avatar[2].value}} 3x" />
</a>
</li>
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">

View File

@@ -6,9 +6,9 @@
<div class="umb-el-wrap">
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}">
{{property.label}}
<small ng-bind="property.description"></small>
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}" ng-attr-title="{{propertyAlias}}">
{{property.label}}
<small ng-bind-html="property.description"></small>
</label>
<div class="controls" ng-transclude>

View File

@@ -1,13 +1,29 @@
angular.module('umbraco').controller("Umbraco.PropertyEditors.UrlListController",
function($rootScope, $scope, $filter) {
function formatDisplayValue() {
$scope.renderModel = _.map($scope.model.value.split(","), function (item) {
return {
url: item,
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank"
};
});
function formatDisplayValue() {
if (angular.isArray($scope.model.value)) {
//it's the json value
$scope.renderModel = _.map($scope.model.value, function (item) {
return {
url: item.url,
linkText: item.linkText,
urlTarget: (item.target) ? item.target : "_blank",
icon: (item.icon) ? item.icon : "icon-out"
};
});
}
else {
//it's the default csv value
$scope.renderModel = _.map($scope.model.value.split(","), function (item) {
return {
url: item,
linkText: "",
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank",
icon: ($scope.config && $scope.config.icon) ? $scope.config.icon : "icon-out"
};
});
}
}
$scope.getUrl = function(valueUrl) {

View File

@@ -1,7 +1,11 @@
<div ng-controller="Umbraco.PropertyEditors.UrlListController">
<ul class="nav nav-stacked">
<li ng-repeat="value in renderModel">
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}"><i class="icon-out"></i> {{value.url}}</a>
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}">
<i ng-class="value.icon"></i>
<span ng-if="value.linkText">{{value.linkText}}</span>
<span ng-if="!value.linkText">{{value.url}}</span>
</a>
</li>
</ul>
</div>