Merge branch '7.1.0-installer' into 7.1.0

Conflicts:
	src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js
	src/Umbraco.Web.UI.Client/test/unit/app/media/edit-media-controller.spec.js
This commit is contained in:
Shannon
2014-03-06 12:28:50 +11:00
152 changed files with 4495 additions and 4629 deletions

View File

@@ -3,17 +3,18 @@ module.exports = function (grunt) {
// Default task.
grunt.registerTask('default', ['jshint:dev','build','karma:unit']);
grunt.registerTask('dev', ['jshint:dev', 'build', 'webserver', 'open:dev', 'watch']);
//run by the watch task
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:vs','karma:unit']);
grunt.registerTask('watch-less', ['recess:build','copy:assets','copy:vs']);
grunt.registerTask('watch-less', ['recess:build','recess:installer','copy:assets','copy:vs']);
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
grunt.registerTask('watch-packages', ['copy:packages']);
grunt.registerTask('watch-installer', ['concat:install','concat:installJs','copy:installer', 'copy:vs']);
grunt.registerTask('watch-test', ['jshint:dev', 'karma:unit']);
//triggered from grunt dev or grunt
grunt.registerTask('build', ['clean','concat','recess:min','copy']);
grunt.registerTask('build', ['clean','concat','recess:min','recess:installer','copy']);
//utillity tasks
grunt.registerTask('docs', ['ngdocs']);
grunt.registerTask('webserver', ['connect:devserver']);
@@ -68,7 +69,7 @@ module.exports = function (grunt) {
specs: ['test/**/*.spec.js'],
scenarios: ['test/**/*.scenario.js'],
samples: ['sample files/*.js'],
html: ['src/index.html'],
html: ['src/index.html','src/install.html'],
everything:['src/**/*.*', 'test/**/*.*', 'docs/**/*.*'],
@@ -86,6 +87,11 @@ module.exports = function (grunt) {
assets: {
files: [{ dest: '<%= distdir %>/assets', src : '**', expand: true, cwd: 'src/assets/' }]
},
installer: {
files: [{ dest: '<%= distdir %>/views/install', src : '**/*.html', expand: true, cwd: 'src/installer/steps' }]
},
vendor: {
files: [{ dest: '<%= distdir %>/lib', src : '**', expand: true, cwd: 'lib/' }]
},
@@ -130,8 +136,24 @@ module.exports = function (grunt) {
process: true
}
},
install: {
src: ['src/installer/installer.html'],
dest: '<%= distdir %>/installer.html',
options: {
process: true
}
},
installJs: {
src: ['src/installer/**/*.js'],
dest: '<%= distdir %>/js/umbraco.installer.js',
options: {
banner: "<%= banner %>\n(function() { \n\n angular.module('umbraco.install', []); \n",
footer: "\n\n})();"
}
},
controllers: {
src:['src/views/**/*.controller.js'],
src:['src/controllers/**/*.controller.js','src/views/**/*.controller.js'],
dest: '<%= distdir %>/js/umbraco.controllers.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
@@ -198,7 +220,7 @@ module.exports = function (grunt) {
}
}
},
recess: {
build: {
files: {
@@ -208,6 +230,14 @@ module.exports = function (grunt) {
compile: true
}
},
installer: {
files: {
'<%= distdir %>/assets/css/installer.css':
['src/less/installer.less'] },
options: {
compile: true
}
},
min: {
files: {
'<%= distdir %>/assets/css/<%= pkg.name %>.css': ['<%= src.less %>']
@@ -220,7 +250,6 @@ module.exports = function (grunt) {
},
watch:{
css: {
files: '**/*.less',
@@ -237,6 +266,10 @@ module.exports = function (grunt) {
files: ['test/**/*.js'],
tasks: ['watch-test', 'timestamp'],
},
installer: {
files: ['src/installer/**/*.*'],
tasks: ['watch-installer', 'timestamp'],
},
html: {
files: ['src/views/**/*.html', 'src/*.html'],
tasks:['watch-html','timestamp']
@@ -288,7 +321,7 @@ module.exports = function (grunt) {
//NOTE: we ignore tabs vs spaces because enforcing that causes lots of errors depending on the text editor being used
smarttabs: true,
globals:{}
}
}
},
build:{
files:['<%= src.prod %>'],
@@ -312,13 +345,13 @@ module.exports = function (grunt) {
smarttabs: true,
globalstrict:true,
globals:{$:false, jQuery:false,define:false,require:false,window:false}
}
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
@@ -328,11 +361,10 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-recess');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-ngdocs');
grunt.loadNpmTasks('grunt-ngmin');
};

View File

@@ -42,7 +42,6 @@
"karma-coffee-preprocessor": "0.0.1",
"karma": "~0.9",
"karma-phantomjs-launcher": "0.0.2",
"grunt-ngdocs": "~0.1.2",
"grunt-ngmin": "0.0.3"
"grunt-ngdocs": "~0.1.2"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 KiB

View File

@@ -125,6 +125,39 @@ function mediaHelper(umbRequestHelper) {
return "";
},
registerFileResolver: function(propertyEditorAlias, func){
_mediaFileResolvers[propertyEditorAlias] = func;
},
resolveFile : function(mediaItem){
var _props = [];
//we either have properties raw on the object, or spread out on tabs
if(mediaItem.properties){
_props = mediaItem.properties;
}else if(mediaItem.tabs){
_.each(mediaItem.tabs, function(tab){
if(tab.properties){
_props.concat(tab.propeties);
}
});
}
//we go through our file resolvers to see if any of them matches the editors
var result = "";
_.each(_mediaFileResolvers, function(resolver, key){
var property = _.find(_props, function(property){ return property.editor === key; });
if(property){
var file = resolver(property);
if(file){
result = file;
}
}
});
return result;
},
/**
* @ngdoc function
* @name umbraco.services.mediaHelper#scaleToMaxSize
@@ -208,41 +241,8 @@ function mediaHelper(umbRequestHelper) {
var lowered = imagePath.toLowerCase();
var ext = lowered.substr(lowered.lastIndexOf(".") + 1);
return ("," + Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes + ",").indexOf("," + ext + ",") !== -1;
},
registerFileResolver: function(propertyEditorAlias, func){
_mediaFileResolvers[propertyEditorAlias] = func;
},
resolveFile : function(mediaItem){
var _props = [];
//we either have properties raw on the object, or spread out on tabs
if(mediaItem.properties){
_props = mediaItem.properties;
}else if(mediaItem.tabs){
_.each(mediaItem.tabs, function(tab){
if(tab.properties){
_props.concat(tab.propeties);
}
});
}
//we go through our file resolvers to see if any of them matches the editors
var result = "";
_.each(_mediaFileResolvers, function(resolver, key){
var property = _.find(_props, function(property){ return property.editor === key; });
if(property){
var file = resolver(property);
if(file){
result = file;
}
}
});
return result;
}
};
}
angular.module('umbraco.services').factory('mediaHelper', mediaHelper);

View File

@@ -0,0 +1,21 @@
yepnope({
load: [
'lib/jquery/jquery-2.0.3.min.js',
/* 1.1.5 */
'lib/angular/1.1.5/angular.min.js',
'lib/angular/1.1.5/angular-cookies.min.js',
'lib/angular/1.1.5/angular-mobile.min.js',
'lib/angular/1.1.5/angular-mocks.js',
'lib/angular/1.1.5/angular-sanitize.min.js',
'lib/underscore/underscore.js',
'js/umbraco.installer.js'
],
complete: function () {
jQuery(document).ready(function () {
angular.bootstrap(document, ['umbraco.install']);
});
}
});

View File

@@ -0,0 +1,32 @@
angular.module("umbraco.install").controller("Umbraco.InstallerController",
function($scope, installerService){
$scope.stepIndex = 0;
//comment this out if you just want to see tips
installerService.init();
//uncomment this to see tips
//installerService.switchToFeedback();
$scope.installer = installerService.status;
$scope.forward = function(){
installerService.forward();
};
$scope.backward = function(){
installerService.backward();
};
$scope.install = function(){
installerService.install();
};
$scope.gotoStep = function(step){
installerService.gotoNamedStep(step);
};
$scope.restart = function () {
installerService.gotoStep(0);
};
});

View File

@@ -0,0 +1,24 @@
<!doctype html>
<html lang="en">
<head>
<base href="/belle/" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Install Umbraco</title>
<link rel="stylesheet" href="assets/css/installer.css" />
</head>
<body ng-class="{touch:touchDevice, installing:installer.current.installing}" ng-controller="Umbraco.InstallerController" id="umbracoInstallPageBody">
<img src="assets/img/application/logo_white.png" id="logo" />
<div id="installer" class="absolute-center clearfix" ng-if="installer.current">
<div ng-include="installer.current.view"></div>
</div>
<div id="overlay"></div>
<script src="lib/yepnope/yepnope.min.js"></script>
<script src="js/install.loader.js"></script>
</body>
</html>

View File

@@ -0,0 +1,308 @@
angular.module("umbraco.install").factory('installerService', function($rootScope, $q, $timeout, $http, $location, $log){
var _status = {
index: 0,
current: undefined,
steps: undefined,
loading: true,
progress: "100%"
};
var factTimer = undefined;
var _installerModel = {
installId: undefined,
instructions: {
}
};
//add to umbraco installer facts here
var facts = ['Umbraco was founded in 2005',
'Over 200.000 websites are currently powered by Umbraco',
'On an average day, more then 1000 people download Umbraco',
'<a target="_blank" href="http://umbraco.tv">umbraco.tv</a> is the premier source of Umbraco video tutorials to get you started',
'<a target="_blank" href="http://our.umbraco.org">our.umbraco.org</a> is the home of the friendly Umbraco community, and excellent resource for any Umbraco developer'
];
/**
Returns the description for the step at a given index based on the order of the serverOrder of steps
Since they don't execute on the server in the order that they are displayed in the UI.
*/
function getDescriptionForStepAtIndex(steps, index) {
var sorted = _.sortBy(steps, "serverOrder");
if (sorted[index]) {
return sorted[index].description;
}
return null;
}
/* Returns the description for the given step name */
function getDescriptionForStepName(steps, name) {
var found = _.find(steps, function(i) {
return i.name == name;
});
return (found) ? found.description : null;
}
//calculates the offset of the progressbar on the installaer
function calculateProgress(steps, next) {
var pct = "100%";
var f = _.find(steps, function(item, index) {
if(item.name == next){
pct = Math.floor((index / steps.length * 100)) + "%";
return true;
}else{
return false;
}
});
return pct;
}
//helpful defaults for the view loading
function resolveView(view){
if(view.indexOf(".html") < 0){
view = view + ".html";
}
if(view.indexOf("/") < 0){
view = "views/install/" + view;
}
return view;
}
/** Have put this here because we are not referencing our other modules */
function safeApply (scope, fn) {
if (scope.$$phase || scope.$root.$$phase) {
if (angular.isFunction(fn)) {
fn();
}
}
else {
if (angular.isFunction(fn)) {
scope.$apply(fn);
}
else {
scope.$apply();
}
}
}
var service = {
status : _status,
//loads the needed steps and sets the intial state
init : function(){
service.status.loading = true;
if(!_status.all){
service.getSteps().then(function(response){
service.status.steps = response.data.steps;
service.status.index = 0;
_installerModel.installId = response.data.installId;
service.findNextStep();
$timeout(function(){
service.status.loading = false;
service.status.configuring = true;
}, 2000);
});
}
},
//loads available packages from our.umbraco.org
getPackages : function(){
return $http.get(Umbraco.Sys.ServerVariables.installApiBaseUrl + "GetPackages");
},
getSteps : function(){
return $http.get(Umbraco.Sys.ServerVariables.installApiBaseUrl + "GetSetup");
},
gotoStep : function(index){
var step = service.status.steps[index];
step.view = resolveView(step.view);
if(!step.model){
step.model = {};
}
service.status.index = index;
service.status.current = step;
service.retrieveCurrentStep();
},
gotoNamedStep : function(stepName){
var step = _.find(service.status.steps, function(s, index){
if (s.view && s.name === stepName) {
service.status.index = index;
return true;
}
return false;
});
step.view = resolveView(step.view);
if(!step.model){
step.model = {};
}
service.retrieveCurrentStep();
service.status.current = step;
},
/**
Finds the next step containing a view. If one is found it stores it as the current step
and retreives the step information and returns it, otherwise returns null .
*/
findNextStep : function(){
var step = _.find(service.status.steps, function(s, index){
if(s.view && index >= service.status.index){
service.status.index = index;
return true;
}
return false;
});
if (step) {
if (step.view.indexOf(".html") < 0) {
step.view = step.view + ".html";
}
if (step.view.indexOf("/") < 0) {
step.view = "views/install/" + step.view;
}
if (!step.model) {
step.model = {};
}
service.status.current = step;
service.retrieveCurrentStep();
//returns the next found step
return step;
}
else {
//there are no more steps found containing a view so return null
return null;
}
},
storeCurrentStep : function(){
_installerModel.instructions[service.status.current.name] = service.status.current.model;
},
retrieveCurrentStep : function(){
if(_installerModel.instructions[service.status.current.name]){
service.status.current.model = _installerModel.instructions[service.status.current.name];
}
},
/** Moves the installer forward to the next view, if there are not more views than the installation will commence */
forward : function(){
service.storeCurrentStep();
service.status.index++;
var found = service.findNextStep();
if (!found) {
//no more steps were found so start the installation process
service.install();
}
},
backwards : function(){
service.storeCurrentStep();
service.gotoStep(service.status.index--);
},
install : function(){
service.storeCurrentStep();
service.switchToFeedback();
service.status.feedback = getDescriptionForStepAtIndex(service.status.steps, 0);
service.status.progress = 0;
function processInstallStep(){
$http.post(Umbraco.Sys.ServerVariables.installApiBaseUrl + "PostPerformInstall",
_installerModel).then(function(response){
if(!response.data.complete){
//progress feedback
service.status.progress = calculateProgress(service.status.steps, response.data.nextStep);
if(response.data.view){
//set the current view and model to whatever the process returns, the view is responsible for retriggering install();
var v = resolveView(response.data.view);
service.status.current = {view: v, model: response.data.model};
//turn off loading bar and feedback
service.switchToConfiguration();
}
else {
var desc = getDescriptionForStepName(service.status.steps, response.data.nextStep);
if (desc) {
service.status.feedback = desc;
}
processInstallStep();
}
}
else {
service.complete();
}
}, function(err){
//this is where we handle installer error
var v = err.data.view ? resolveView(err.data.view) : resolveView("error");
var model = err.data.model ? err.data.model : err.data;
service.status.current = {view: v, model: model};
service.switchToConfiguration();
});
}
processInstallStep();
},
randomFact: function () {
safeApply($rootScope, function() {
service.status.fact = facts[_.random(facts.length - 1)];
});
},
switchToFeedback : function(){
service.status.current = undefined;
service.status.loading = true;
service.status.configuring = false;
//initial fact
service.randomFact();
//timed facts
factTimer = window.setInterval(function(){
service.randomFact();
},6000);
},
switchToConfiguration : function(){
service.status.loading = false;
service.status.configuring = true;
service.status.feedback = undefined;
if(factTimer){
clearInterval(factTimer);
}
},
complete : function(){
service.status.progress = "100%";
service.status.done = true;
service.status.feedback = "Redirecting you to Umbraco, please wait";
service.status.loading = false;
if(factTimer){
clearInterval(factTimer);
}
$timeout(function(){
window.location.href = Umbraco.Sys.ServerVariables.umbracoBaseUrl;
}, 1500);
}
};
return service;
});

View File

@@ -0,0 +1,13 @@
<div>
<h1>Continue Umbraco Installation</h1>
<p>
You see this screen because your Umbraco installation did not complete correctly.
</p>
<p>
Simply click <strong>continue</strong> below to be guided through the rest of the installation process.
</p>
<p>
<button class="btn btn-success" ng-click="install()">Continue</button>
</p>
</div>

View File

@@ -0,0 +1,25 @@
angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseController", function($scope, $http, installerService){
$scope.checking = false;
$scope.validateAndForward = function(){
if(!$scope.checking && this.myForm.$valid){
$scope.checking = true;
var model = installerService.status.current.model;
$http.post(Umbraco.Sys.ServerVariables.installApiBaseUrl + "PostValidateDatabaseConnection",
model).then(function(response){
if(response.data === "true"){
installerService.forward();
}else{
$scope.invalidDbDns = true;
}
$scope.checking = false;
}, function(){
$scope.invalidDbDns = true;
$scope.checking = false;
});
}
};
});

View File

@@ -0,0 +1,135 @@
<div ng-controller="Umbraco.Installer.DataBaseController">
<h1>Configure your database</h1>
<p>
Enter connection and authentication details for the database you want to install Umbraco on
</p>
<form name="myForm" class="form-horizontal" novalidate ng-submit="validateAndForward();">
<div class="control-group">
<legend>What type of database do you use?</legend>
<label class="control-label" for="dbType">Database type</label>
<div class="controls">
<select name="dbType" ng-model="installer.current.model.dbType" required>
<optgroup>
<option value="0">Embedded database SQL CE</option>
<option value="1">Microsft SQL Server</option>
<option value="2">MySQL</option>
</optgroup>
<optgroup>
<option value="-1">Custom connection-string</option>
</optgroup>
</select>
</div>
</div>
<div ng-if="installer.current.model.dbType == 0">
<p>Great!, no need to configure anything then, you simply click the <strong>continue</strong> button below to continue to the next step</p>
</div>
<div ng-if="installer.current.model.dbType < 0">
<legend>What is the exact connectionstring we should use?</legend>
<div class="control-group">
<label class="control-label" for="server">Connection string</label>
<div class="controls">
<textarea class="input-block-level" required ng-model="installer.current.model.connectionString" rows="5">
</textarea>
<small class="inline-help">Enter a valid database connection string.</small>
</div>
</div>
</div>
<div ng-if="installer.current.model.dbType > 0">
<div class="row">
<legend>Where do we find your database?</legend>
<div class="span6">
<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" />
<small class="inline-help">Enter server domain or IP</small>
</div>
</div>
</div>
<div class="span6">
<div class="control-group">
<label class="control-label" for="databaseName">Database name</label>
<div class="controls">
<input type="text" name="installer.current.model.databaseName"
placeholder="umbraco-cms"
required ng-model="installer.current.model.databaseName" />
<small class="inline-help">Enter the name of the database</small>
</div>
</div>
</div>
</div>
<div class="row">
<legend>What credentials are used to access the database?</legend>
<div class="span6">
<div class="control-group" ng-if="!installer.current.model.integratedAuth">
<label class="control-label" for="login">Login</label>
<div class="controls">
<input type="text" name="login"
placeholder="databaseuser"
required ng-model="installer.current.model.login" />
<small class="inline-help">Enter the database user name</small>
</div>
</div>
</div>
<div class="span6">
<div class="control-group" ng-if="!installer.current.model.integratedAuth">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" name="password"
placeholder="umbraco-cms"
required ng-model="installer.current.model.password" />
<small class="inline-help">Enter the database password</small>
</div>
</div>
</div>
<div class="span12 control-group" ng-if="installer.current.model.dbType == 1">
<div class="controls">
<label class="checkbox" for="integratedAuth">
<input type="checkbox" name="integratedAuth"
placeholder="umbraco-cms"
ng-model="installer.current.model.integratedAuth" /> Use intergrated authentication</label>
</div>
</div>
</div>
</div>
<div class="row">
<div class="control-group" ng-class="{disabled:myForm.$invalid}">
<div class="controls">
<input type="submit" ng-disabled="myForm.$invalid || checking"
value="Continue" class="btn btn-success" />
<br/>
<span class="inline-help" ng-if="checking" ng-animate="'fade'">
Validating your database connection
</span>
<span class="inline-help error" ng-if="invalidDbDns" ng-animate="'fade'">
Could not connect to the database, please correct your connection details
</span>
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,9 @@
<div class="error">
<h1>Error during installation</h1>
<p class="message">{{installer.current.model.message}}</p>
<p><small>See log for full details</small></p>
<button class="btn btn-success" ng-click="restart()">Go back</button>
</div>

View File

@@ -0,0 +1,26 @@
<div>
<h1>Your permission settings are not ready for umbraco</h1>
<p>
In order to run umbraco, you'll need to update your permission settings.
Detailed information about the correct file & folder permissions for Umbraco can be found
<a href="http://our.umbraco.org/documentation/Installation/permissions"><strong>here</strong></a>.
</p>
<p>
The following report list the permissions that are currently failing. Once the permissions are fixed press the 'Go back' button to restart the installation.
</p>
<ul class="permissions-report">
<li ng-repeat="(category, items) in installer.current.model.errors">
<h4>{{category}}</h4>
<ul>
<li ng-repeat="item in items">
{{item}}
</li>
</ul>
</li>
</ul>
<p>
<button class="btn btn-success" ng-click="restart()">Go back</button>
</p>
</div>

View File

@@ -0,0 +1,12 @@
angular.module("umbraco.install").controller("Umbraco.Installer.PackagesController", function ($scope, installerService) {
installerService.getPackages().then(function (response) {
$scope.packages = response.data;
});
$scope.setPackageAndContinue = function (pckId) {
installerService.status.current.model = pckId;
installerService.forward();
};
});

View File

@@ -0,0 +1,20 @@
<div ng-controller="Umbraco.Installer.PackagesController">
<h1>Install a starter website</h1>
<p>
Installing a starter website helps you learn how Umbraco works, and gives you a solid
and simple foundation to build on top of.
</p>
<ul class="thumbnails">
<li class="span3" ng-repeat="pck in packages">
<a href ng-click="setPackageAndContinue(pck.id)" class="thumbnail">
<img ng-src="http://our.umbraco.org{{pck.thumbnail}}" alt="{{pck.name}}">
</a>
</li>
</ul>
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')" class="btn btn-link">
No thanks, I do not want to install a starter website
</a>
</div>

View File

@@ -0,0 +1,14 @@
<div>
<h1>Upgrading Umbraco</h1>
<p>
Welcome to the Umbraco installer. You see this screen because your Umbraco installation needs a quick upgrade of its database and files,
it is completely harmless and will simply ensure your website is kept as fast, secure and uptodate as possible.
</p>
<p>
Simply click <strong>continue</strong> below to be guided through the rest of the upgrade
</p>
<p>
<button class="btn btn-success" ng-click="install()">Continue</button>
</p>
</div>

View File

@@ -0,0 +1,24 @@
angular.module("umbraco.install").controller("Umbraco.Install.UserController", function($scope, installerService) {
$scope.passwordPattern = /.*/;
if ($scope.installer.current.model.minNonAlphaNumericLength > 0) {
var exp = "";
for (var i = 0; i < $scope.installer.current.model.minNonAlphaNumericLength; i++) {
exp += ".*[\\W].*";
}
//replace duplicates
exp = exp.replace(".*.*", ".*");
$scope.passwordPattern = new RegExp(exp);
}
$scope.validateAndInstall = function(){
installerService.install();
};
$scope.validateAndForward = function(){
if(this.myForm.$valid){
installerService.forward();
}
};
});

View File

@@ -0,0 +1,56 @@
<div ng-controller="Umbraco.Install.UserController">
<h1>Install Umbraco 7</h1>
<p>Enter your name, email and password to install Umbraco 7 with its default settings, alternatively you can customize your installation</p>
<form name="myForm" class="form-horizontal" novalidate ng-submit="validateAndInstall();">
<div class="row">
<div class="span8">
<div class="pull-right">
<div class="control-group">
<label class="control-label" for="name">Name</label>
<div class="controls">
<input type="text" name="name" placeholder="First Last" required
ng-model="installer.current.model.name" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email">Email</label>
<div class="controls">
<input type="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" />
<small class="inline-help">Your email will be used as your login</small>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" name="installer.current.model.password"
ng-minlength="{{installer.current.model.minCharLength}}"
ng-pattern="passwordPattern"
required
ng-model="installer.current.model.password" />
<small class="inline-help">At least {{installer.current.model.minCharLength}} characters long</small>
<small ng-if="installer.current.model.minNonAlphaNumericLength > 0" class="inline-help">
At least {{installer.current.model.minNonAlphaNumericLength}} symbol{{installer.current.model.minNonAlphaNumericLength > 1 ? 's' : ''}}
</small>
</div>
</div>
<div class="control-group" ng-class="{disabled:myForm.$invalid}">
<div class="controls">
<input type="submit" ng-disabled="myForm.$invalid" value="Install" class="btn btn-success" />
<a href class="btn btn-link" ng-disabled="myForm.$invalid" ng-click="validateAndForward()">Customize</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,22 @@
<div>
<h1>Major version upgrade from {{installer.current.model.currentVersion}} to {{installer.current.model.newVersion}}</h1>
<h2>There were {{installer.current.model.errors.length}} issues detected</h2>
<p>
The following compatibility issues were found. If you continue all non-compatible property editors will be converted to a Readonly/Label.
You will be able to change the property editor to a compatible type manually by editing the data type after installation.
</p>
<p>
Otherwise if you choose not to proceed you will need to fix the errors listed below.
Refer to v{{installer.current.model.newVersion}} upgrade instructions for full details.
</p>
<ul class="upgrade-report">
<li ng-repeat="item in installer.current.model.errors">
{{item}}
</li>
</ul>
<p>
<button class="btn btn-success" ng-click="forward()">Continue</button>
</p>
</div>

View File

@@ -0,0 +1,280 @@
// Core variables and mixins
@import "fonts.less"; // Loading fonts
@import "variables.less"; // Modify this for custom colors, font-sizes, etc
@import "mixins.less";
@import "buttons.less";
@import "forms.less";
// Grid system and page structure
@import "../../lib/bootstrap/less/scaffolding.less";
@import "../../lib/bootstrap/less/grid.less";
@import "../../lib/bootstrap/less/layouts.less";
@import "../../lib/bootstrap/less/thumbnails.less";
@import "../../lib/bootstrap/less/media.less";
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
html {
background: url('../img/installer.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
font-family: @baseFontFamily;
font-size: @baseFontSize;
line-height: @baseLineHeight;
color: @textColor;
vertical-align: center;
text-align: center;
}
#logo{
position: absolute;
top: 20px;
left: 20px;
opacity: 0.8;
z-index: 777;
}
#installer{
margin: auto;
background: white;
width: 750px;
height: 600px;
text-align: left;
padding: 30px;
overflow:hidden;
z-index: 667;
}
#overlay{
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: @blackLight;
z-index: 666;
}
.loading #overlay{
opacity: 0.5;
display: block !important;
}
#fact{
color: #fff;
text-shadow: 0px 0px 4px black;
font-size: 25px;
text-align: left;
line-height: 35px;
z-index: 667;
height: 600px;
width: 750px;
}
#fact h2{
font-size: 35px;
border-bottom: 1px solid white;
padding-bottom: 10px;
margin-bottom: 20px;
color: white;
}
#fact a{color: white;}
#feedback{
color: #fff;
text-shadow: 0px 0px 4px black;
font-size: 14px;
text-align: center;
line-height: 20px;
z-index: 667;
bottom: 20px;
right: 0;
left: 0;
height: 25px;
position: absolute;
}
h1{
border-bottom: 1px solid @grayLighter;
padding-bottom: 10px;
color: @gray;
}
.error h1, .error .message, span.error{ color: @red;}
legend{font-size: 14px; font-weight: bold}
input.ng-dirty.ng-invalid{border-color: #b94a48; color: #b94a48;}
.disabled{
opacity: 0.6;
}
.controls{
text-align: left
}
.controls small{display: block; color: @gray;}
.absolute-center {
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
.fade-hide, .fade-show {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
.fade-hide {
opacity:1;
}
.fade-hide.fade-hide-active {
opacity:0;
}
.fade-show {
opacity:0;
}
.fade-show.fade-show-active {
opacity:1;
}
.umb-loader{
background-color: white;
margin-top:0;
margin-left:-100%;
-moz-animation-name:bounce_loadingProgressG;
-moz-animation-duration:1s;
-moz-animation-iteration-count:infinite;
-moz-animation-timing-function:linear;
-webkit-animation-name:bounce_loadingProgressG;
-webkit-animation-duration:1s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:linear;
-ms-animation-name:bounce_loadingProgressG;
-ms-animation-duration:1s;
-ms-animation-iteration-count:infinite;
-ms-animation-timing-function:linear;
-o-animation-name:bounce_loadingProgressG;
-o-animation-duration:1s;
-o-animation-iteration-count:infinite;
-o-animationtiming-function:linear;
animation-name:bounce_loadingProgressG;
animation-duration:1s;
animation-iteration-count:infinite;
animation-timing-function:linear;
width:100%;
height: 5px;
}
@-moz-keyframes bounce_loadingProgressG{
0%{
margin-left:-100%;
}
100%{
margin-left:100%;
}
}
@-webkit-keyframes bounce_loadingProgressG{
0%{
margin-left:-100%;
}
100%{
margin-left:100%;
}
}
@-ms-keyframes bounce_loadingProgressG{
0%{
margin-left:-100%;
}
100%{
margin-left:100%;
}
}
@-o-keyframes bounce_loadingProgressG{
0%{
margin-left:-100%;
}
100%{
margin-left:100%;
}
}
@keyframes bounce_loadingProgressG{
0%{
margin-left:-100%;
}
100%{
margin-left:100%;
}
}
//loader defaults
.umb-loader-container, .umb-loader-done{
height: 3px;
position: absolute;
bottom: 0;
left: 0;
overflow: hidden;
width: 0%;
z-index: 777;
}
.umb-loader-done{
right: 0%;
background: white;
}
.permissions-report {
overflow:auto;
height:320px;
margin:0;
display:block;
padding:0;
}
.permissions-report > li {
list-style:none;
}
.permissions-report h4 {
margin:7px;
}
.upgrade-report {
overflow:auto;
height:280px;
display:block;
}

View File

@@ -15,8 +15,8 @@
*/
function fileUploadController($scope, $element, $compile, imageHelper, fileManager, umbRequestHelper, mediaHelper) {
mediaHelper.registerFileResolver("Umbraco.UploadField", function (property) {
return property.value;
mediaHelper.registerFileResolver("Umbraco.UploadField", function(property){
return property.value;
});
/** Clears the file collections when content is saving (if we need to clear) or after saved */

View File

@@ -5,7 +5,7 @@ describe('edit media controller tests', function () {
beforeEach(module('umbraco'));
//inject the contentMocks service
beforeEach(inject(function ($rootScope, $controller, angularHelper, $httpBackend, mediaMocks, mocksUtils, entityMocks) {
beforeEach(inject(function ($rootScope, $controller, angularHelper, $httpBackend, mediaMocks, entityMocks, mocksUtils) {
//for these tests we don't want any authorization to occur
mocksUtils.disableAuth();