diff --git a/src/SQLCE4Umbraco/SqlCEHelper.cs b/src/SQLCE4Umbraco/SqlCEHelper.cs
index a7f1abd88c..1787c05912 100644
--- a/src/SQLCE4Umbraco/SqlCEHelper.cs
+++ b/src/SQLCE4Umbraco/SqlCEHelper.cs
@@ -42,6 +42,13 @@ namespace SqlCE4Umbraco
{
var sqlCeEngine = new SqlCeEngine(ConnectionString);
sqlCeEngine.CreateDatabase();
+
+ // SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here
+ // since it's been like this for quite some time
+ //using (var sqlCeEngine = new SqlCeEngine(ConnectionString))
+ //{
+ // sqlCeEngine.CreateDatabase();
+ //}
}
}
diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs
index 79e4a72756..f1bb929a94 100644
--- a/src/Umbraco.Core/ApplicationContext.cs
+++ b/src/Umbraco.Core/ApplicationContext.cs
@@ -165,6 +165,9 @@ namespace Umbraco.Core
///
internal string OriginalRequestUrl { get; set; }
+ ///
+ /// Checks if the version configured matches the assembly version
+ ///
private bool Configured
{
get
diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs
index 3c16377a8f..dc2675bd58 100644
--- a/src/Umbraco.Core/Configuration/GlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Configuration
private static string _reservedUrls;
//ensure the built on (non-changeable) reserved paths are there at all times
private const string StaticReservedPaths = "~/app_plugins/,~/install/,";
- private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
+ private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
#endregion
diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index 849599e0c6..435470a493 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -113,8 +113,8 @@ namespace Umbraco.Core
public void ConfigureEmbeddedDatabaseConnection()
{
const string providerName = "System.Data.SqlServerCe.4.0";
- const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
+ var connectionString = GetEmbeddedDatabaseConnectionString();
SaveConnectionString(connectionString, providerName);
var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf");
@@ -122,11 +122,23 @@ namespace Umbraco.Core
{
var engine = new SqlCeEngine(connectionString);
engine.CreateDatabase();
+
+ // SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here
+ // since it's been like this for quite some time
+ //using (var engine = new SqlCeEngine(connectionString))
+ //{
+ // engine.CreateDatabase();
+ //}
}
Initialize(providerName);
}
+ public string GetEmbeddedDatabaseConnectionString()
+ {
+ return @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
+ }
+
///
/// Configure a ConnectionString that has been entered manually.
///
@@ -149,27 +161,29 @@ namespace Umbraco.Core
/// Database Password
/// Type of the provider to be used (Sql, Sql Azure, Sql Ce, MySql)
public void ConfigureDatabaseConnection(string server, string databaseName, string user, string password, string databaseProvider)
- {
- string connectionString;
- string providerName = "System.Data.SqlClient";
- if (databaseProvider.ToLower().Contains("mysql"))
- {
- providerName = "MySql.Data.MySqlClient";
- connectionString = string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password);
- }
- else if (databaseProvider.ToLower().Contains("azure"))
- {
- connectionString = BuildAzureConnectionString(server, databaseName, user, password);
- }
- else
- {
- connectionString = string.Format("server={0};database={1};user id={2};password={3}", server, databaseName, user, password);
- }
+ {
+ string providerName;
+ var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out providerName);
SaveConnectionString(connectionString, providerName);
Initialize(providerName);
}
+ public string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
+ {
+ providerName = "System.Data.SqlClient";
+ if (databaseProvider.ToLower().Contains("mysql"))
+ {
+ providerName = "MySql.Data.MySqlClient";
+ return string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password);
+ }
+ if (databaseProvider.ToLower().Contains("azure"))
+ {
+ return BuildAzureConnectionString(server, databaseName, user, password);
+ }
+ return string.Format("server={0};database={1};user id={2};password={3}", server, databaseName, user, password);
+ }
+
///
/// Configures a ConnectionString for the Umbraco database that uses Microsoft SQL Server integrated security.
///
@@ -178,12 +192,16 @@ namespace Umbraco.Core
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
{
const string providerName = "System.Data.SqlClient";
- string connectionString = String.Format("Server={0};Database={1};Integrated Security=true", server, databaseName);
-
+ var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
SaveConnectionString(connectionString, providerName);
Initialize(providerName);
}
+ public string GetIntegratedSecurityDatabaseConnectionString(string server, string databaseName)
+ {
+ return String.Format("Server={0};Database={1};Integrated Security=true", server, databaseName);
+ }
+
internal string BuildAzureConnectionString(string server, string databaseName, string user, string password)
{
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
@@ -597,5 +615,34 @@ namespace Umbraco.Core
public bool Success { get; set; }
public string Percentage { get; set; }
}
+
+ internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings)
+ {
+ var dbIsSqlCe = false;
+ if (databaseSettings != null && databaseSettings.ProviderName != null)
+ dbIsSqlCe = databaseSettings.ProviderName == "System.Data.SqlServerCe.4.0";
+ var sqlCeDatabaseExists = false;
+ if (dbIsSqlCe)
+ {
+ var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source="));
+ if (dataSourcePart != null)
+ {
+ var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString());
+ var filePath = datasource.Replace("Data Source=", string.Empty);
+ sqlCeDatabaseExists = File.Exists(filePath);
+ }
+ }
+
+ // Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet
+ if (databaseSettings == null
+ || string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName)
+ || (dbIsSqlCe && sqlCeDatabaseExists == false))
+ {
+ return false;
+ }
+
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DictionaryExtensions.cs b/src/Umbraco.Core/DictionaryExtensions.cs
index fd6476fe21..ddfe963f48 100644
--- a/src/Umbraco.Core/DictionaryExtensions.cs
+++ b/src/Umbraco.Core/DictionaryExtensions.cs
@@ -15,6 +15,25 @@ namespace Umbraco.Core
///
internal static class DictionaryExtensions
{
+
+ ///
+ /// Method to Get a value by the key. If the key doesn't exist it will create a new TVal object for the key and return it.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static TVal GetOrCreate(this IDictionary dict, TKey key)
+ where TVal : class, new()
+ {
+ if (dict.ContainsKey(key) == false)
+ {
+ dict.Add(key, new TVal());
+ }
+ return dict[key];
+ }
+
///
/// Updates an item with the specified key with the specified value
///
diff --git a/src/Umbraco.Core/Persistence/SqlExtensions.cs b/src/Umbraco.Core/Persistence/SqlExtensions.cs
new file mode 100644
index 0000000000..7fbd254709
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/SqlExtensions.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Umbraco.Core.Persistence
+{
+ //TODO: check if any of this works and for what databse types it works for:
+ // ref: http://stackoverflow.com/questions/16171144/how-to-check-for-database-availability
+
+ internal static class SqlExtensions
+ {
+ public static bool IsConnectionAvailable(string connString)
+ {
+ using (var connection = new SqlConnection(connString))
+ {
+ return connection.IsAvailable();
+ }
+ }
+
+ public static bool IsAvailable(this SqlConnection connection)
+ {
+ try
+ {
+ connection.Open();
+ connection.Close();
+ }
+ catch (SqlException)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 0d467eaab4..9e08a02dbc 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -66,7 +66,6 @@
False..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll
-
@@ -356,6 +355,7 @@
+
diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs
index 45b07d4c71..c028992772 100644
--- a/src/Umbraco.Tests/MockTests.cs
+++ b/src/Umbraco.Tests/MockTests.cs
@@ -116,7 +116,6 @@ namespace Umbraco.Tests
Assert.AreNotEqual(appCtx, result);
}
- [NUnit.Framework.Ignore("Need to fix more stuff up, this is ignore because an exception occurs because it wants to ensure we have a resolver initialized - need to make that process better for testability")]
[Test]
public void Can_Get_Umbraco_Context()
{
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 833d891a0b..b638b4060e 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -1,4 +1,4 @@
-
+
Debug
@@ -651,7 +651,9 @@
-
+
+
+ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /D
diff --git a/src/Umbraco.Web.UI.Client/gruntFile.js b/src/Umbraco.Web.UI.Client/gruntFile.js
index 15d5c6e9d4..7ae0a96841 100644
--- a/src/Umbraco.Web.UI.Client/gruntFile.js
+++ b/src/Umbraco.Web.UI.Client/gruntFile.js
@@ -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');
};
diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json
index f5f6ae1bb2..ac3f424f50 100644
--- a/src/Umbraco.Web.UI.Client/package.json
+++ b/src/Umbraco.Web.UI.Client/package.json
@@ -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"
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_black.png b/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_black.png
new file mode 100644
index 0000000000..d3c6dc56c2
Binary files /dev/null and b/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_black.png differ
diff --git a/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_white.png b/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_white.png
new file mode 100644
index 0000000000..72b2fe470a
Binary files /dev/null and b/src/Umbraco.Web.UI.Client/src/assets/img/application/logo_white.png differ
diff --git a/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg b/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg
new file mode 100644
index 0000000000..7985a510b7
Binary files /dev/null and b/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg differ
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/editors/ace.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/editors/ace.directive.js
deleted file mode 100644
index d8ef422165..0000000000
--- a/src/Umbraco.Web.UI.Client/src/common/directives/editors/ace.directive.js
+++ /dev/null
@@ -1,59 +0,0 @@
-angular.module('umbraco.directives.editors').directive('ace', function(assetsService) {
- var ACE_EDITOR_CLASS = 'ace-editor';
-
- function loadAceEditor(element, mode) {
- assetsService.loadJs("lib/ace/noconflict/ace.js").then(function(){
- var editor = ace.edit($(element).find('.' + ACE_EDITOR_CLASS)[0]);
- editor.session.setMode("ace/mode/" + mode);
- editor.renderer.setShowPrintMargin(false);
- return editor;
- });
- }
-
- function valid(editor) {
- return (Object.keys(editor.getSession().getAnnotations()).length === 0);
- }
-
- return {
- restrict: 'A',
- require: '?ngModel',
- transclude: true,
- template: '',
-
- link: function(scope, element, attrs, ngModel) {
- function read() {
- ngModel.$setViewValue(editor.getValue());
- textarea.val(editor.getValue());
- }
-
- var textarea = $(element).find('textarea');
- textarea.hide();
-
- var mode = attrs.ace;
- var editor = loadAceEditor(element, mode);
- scope.ace = editor;
-
- if (!ngModel)
- {
- return; // do nothing if no ngModel
- }
-
- ngModel.$render = function() {
- var value = ngModel.$viewValue || '';
- editor.getSession().setValue(value);
- textarea.val(value);
- };
-
- editor.getSession().on('changeAnnotation', function() {
- if (valid(editor)) {
- scope.$apply(read);
- }
- });
-
- editor.getSession().setValue(textarea.val());
-
- read();
-
- }
- };
-});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbsinglefileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbsinglefileupload.directive.js
similarity index 96%
rename from src/Umbraco.Web.UI.Client/src/common/directives/umbsinglefileupload.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/editors/umbsinglefileupload.directive.js
index e1f6dd380f..b8123b9202 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbsinglefileupload.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbsinglefileupload.directive.js
@@ -1,33 +1,33 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:umbFileUpload
-* @function
-* @restrict A
-* @scope
-* @description
-* A single file upload field that will reset itself based on the object passed in for the rebuild parameter. This
-* is required because the only way to reset an upload control is to replace it's html.
-**/
-function umbSingleFileUpload($compile) {
- return {
- restrict: "E",
- scope: {
- rebuild: "="
- },
- replace: true,
- template: "",
- link: function (scope, el, attrs) {
-
- scope.$watch("rebuild", function (newVal, oldVal) {
- if (newVal && newVal !== oldVal) {
- //recompile it!
- el.html("");
- $compile(el.contents())(scope);
- }
- });
-
- }
- };
-}
-
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:umbFileUpload
+* @function
+* @restrict A
+* @scope
+* @description
+* A single file upload field that will reset itself based on the object passed in for the rebuild parameter. This
+* is required because the only way to reset an upload control is to replace it's html.
+**/
+function umbSingleFileUpload($compile) {
+ return {
+ restrict: "E",
+ scope: {
+ rebuild: "="
+ },
+ replace: true,
+ template: "",
+ link: function (scope, el, attrs) {
+
+ scope.$watch("rebuild", function (newVal, oldVal) {
+ if (newVal && newVal !== oldVal) {
+ //recompile it!
+ el.html("");
+ $compile(el.contents())(scope);
+ }
+ });
+
+ }
+ };
+}
+
angular.module('umbraco.directives').directive("umbSingleFileUpload", umbSingleFileUpload);
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/sectionicon.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/sectionicon.directive.js
similarity index 97%
rename from src/Umbraco.Web.UI.Client/src/common/directives/sectionicon.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/html/sectionicon.directive.js
index 7f8ea83215..d6a4537262 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/sectionicon.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/sectionicon.directive.js
@@ -1,30 +1,30 @@
-angular.module("umbraco.directives")
-.directive('sectionIcon', function ($compile, iconHelper) {
- return {
- restrict: 'E',
- replace: true,
-
- link: function (scope, element, attrs) {
-
- var icon = attrs.icon;
-
- if (iconHelper.isLegacyIcon(icon)) {
- //its a known legacy icon, convert to a new one
- element.html("");
- }
- else if (iconHelper.isFileBasedIcon(icon)) {
- var convert = iconHelper.convertFromLegacyImage(icon);
- if(convert){
- element.html("");
- }else{
- element.html("");
- }
- //it's a file, normally legacy so look in the icon tray images
- }
- else {
- //it's normal
- element.html("");
- }
- }
- };
+angular.module("umbraco.directives")
+.directive('sectionIcon', function ($compile, iconHelper) {
+ return {
+ restrict: 'E',
+ replace: true,
+
+ link: function (scope, element, attrs) {
+
+ var icon = attrs.icon;
+
+ if (iconHelper.isLegacyIcon(icon)) {
+ //its a known legacy icon, convert to a new one
+ element.html("");
+ }
+ else if (iconHelper.isFileBasedIcon(icon)) {
+ var convert = iconHelper.convertFromLegacyImage(icon);
+ if(convert){
+ element.html("");
+ }else{
+ element.html("");
+ }
+ //it's a file, normally legacy so look in the icon tray images
+ }
+ else {
+ //it's normal
+ element.html("");
+ }
+ }
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbavatar.directive.js
similarity index 96%
rename from src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/html/umbavatar.directive.js
index 6779b6e1d8..0702d7207c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbavatar.directive.js
@@ -1,27 +1,27 @@
-/**
-* @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/directives/umb-avatar.html',
- scope: {
- name: '@',
- email: '@',
- hash: '@'
- },
- link: function(scope, element, attr, ctrl) {
-
- scope.$watch("hash", function (val) {
- //set the gravatar url
- scope.gravatar = "http://www.gravatar.com/avatar/" + val + "?s=40";
- });
-
- }
- };
-}
-
-angular.module('umbraco.directives').directive("umbAvatar", avatarDirective);
+/**
+* @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/directives/umb-avatar.html',
+ scope: {
+ name: '@',
+ email: '@',
+ hash: '@'
+ },
+ link: function(scope, element, attr, ctrl) {
+
+ scope.$watch("hash", function (val) {
+ //set the gravatar url
+ scope.gravatar = "http://www.gravatar.com/avatar/" + val + "?s=40";
+ });
+
+ }
+ };
+}
+
+angular.module('umbraco.directives').directive("umbAvatar", avatarDirective);
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbheader.directive.js
similarity index 97%
rename from src/Umbraco.Web.UI.Client/src/common/directives/umbheader.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/html/umbheader.directive.js
index cba6a05e60..b1cca01d44 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbheader.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbheader.directive.js
@@ -1,79 +1,79 @@
-angular.module("umbraco.directives")
-.directive('umbHeader', function($parse, $timeout){
- return {
- restrict: 'E',
- replace: true,
- transclude: 'true',
- templateUrl: 'views/directives/umb-header.html',
- //create a new isolated scope assigning a tabs property from the attribute 'tabs'
- //which is bound to the parent scope property passed in
- scope: {
- tabs: "="
- },
- link: function (scope, iElement, iAttrs) {
-
- var maxTabs = 4;
-
- function collectFromDom(activeTab){
- var $panes = $('div.tab-content');
-
- angular.forEach($panes.find('.tab-pane'), function (pane, index) {
- var $this = angular.element(pane);
-
- var id = $this.attr("rel");
- var label = $this.attr("label");
- var tab = {id: id, label: label, active: false};
- if(!activeTab){
- tab.active = true;
- activeTab = tab;
- }
-
- if ($this.attr("rel") === String(activeTab.id)) {
- $this.addClass('active');
- }
- else {
- $this.removeClass('active');
- }
-
- if(label){
- scope.visibleTabs.push(tab);
- }
-
- });
- }
-
- scope.showTabs = iAttrs.tabs ? true : false;
- scope.visibleTabs = [];
- scope.overflownTabs = [];
-
- $timeout(function () {
- collectFromDom(undefined);
- }, 500);
-
- //when the tabs change, we need to hack the planet a bit and force the first tab content to be active,
- //unfortunately twitter bootstrap tabs is not playing perfectly with angular.
- scope.$watch("tabs", function (newValue, oldValue) {
-
- angular.forEach(newValue, function(val, index){
- var tab = {id: val.id, label: val.label};
- scope.visibleTabs.push(tab);
- });
-
- //don't process if we cannot or have already done so
- if (!newValue) {return;}
- if (!newValue.length || newValue.length === 0){return;}
-
- var activeTab = _.find(newValue, function (item) {
- return item.active;
- });
-
- //we need to do a timeout here so that the current sync operation can complete
- // and update the UI, then this will fire and the UI elements will be available.
- $timeout(function () {
- collectFromDom(activeTab);
- }, 500);
-
- });
- }
- };
+angular.module("umbraco.directives")
+.directive('umbHeader', function($parse, $timeout){
+ return {
+ restrict: 'E',
+ replace: true,
+ transclude: 'true',
+ templateUrl: 'views/directives/umb-header.html',
+ //create a new isolated scope assigning a tabs property from the attribute 'tabs'
+ //which is bound to the parent scope property passed in
+ scope: {
+ tabs: "="
+ },
+ link: function (scope, iElement, iAttrs) {
+
+ var maxTabs = 4;
+
+ function collectFromDom(activeTab){
+ var $panes = $('div.tab-content');
+
+ angular.forEach($panes.find('.tab-pane'), function (pane, index) {
+ var $this = angular.element(pane);
+
+ var id = $this.attr("rel");
+ var label = $this.attr("label");
+ var tab = {id: id, label: label, active: false};
+ if(!activeTab){
+ tab.active = true;
+ activeTab = tab;
+ }
+
+ if ($this.attr("rel") === String(activeTab.id)) {
+ $this.addClass('active');
+ }
+ else {
+ $this.removeClass('active');
+ }
+
+ if(label){
+ scope.visibleTabs.push(tab);
+ }
+
+ });
+ }
+
+ scope.showTabs = iAttrs.tabs ? true : false;
+ scope.visibleTabs = [];
+ scope.overflownTabs = [];
+
+ $timeout(function () {
+ collectFromDom(undefined);
+ }, 500);
+
+ //when the tabs change, we need to hack the planet a bit and force the first tab content to be active,
+ //unfortunately twitter bootstrap tabs is not playing perfectly with angular.
+ scope.$watch("tabs", function (newValue, oldValue) {
+
+ angular.forEach(newValue, function(val, index){
+ var tab = {id: val.id, label: val.label};
+ scope.visibleTabs.push(tab);
+ });
+
+ //don't process if we cannot or have already done so
+ if (!newValue) {return;}
+ if (!newValue.length || newValue.length === 0){return;}
+
+ var activeTab = _.find(newValue, function (item) {
+ return item.active;
+ });
+
+ //we need to do a timeout here so that the current sync operation can complete
+ // and update the UI, then this will fire and the UI elements will be available.
+ $timeout(function () {
+ collectFromDom(activeTab);
+ }, 500);
+
+ });
+ }
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/html/umbpanel.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbpanel.directive.js
index 79524e06e6..5b32941fff 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/html/umbpanel.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbpanel.directive.js
@@ -9,66 +9,6 @@ angular.module("umbraco.directives.html")
restrict: 'E',
replace: true,
transclude: 'true',
- templateUrl: 'views/directives/html/umb-panel.html',
- link: function (scope, el, attrs) {
-
-
- function _setClass(bar, resize){
-
- bar = $(bar);
-
- //no need to process
- if(resize){
- bar.removeClass("umb-bottom-bar");
- }
-
- //already positioned
- if(bar.hasClass("umb-bottom-bar")){
- return;
- }
-
- var offset = bar.offset();
- if(offset){
- var bottom = bar.offset().top + bar.height();
- if(bottom > $(window).height()){
- bar.addClass("umb-bottom-bar");
- $(".tab-content .active").addClass("with-buttons");
- }else{
- bar.removeClass("umb-bottom-bar");
- $(".tab-content .active").removeClass("with-buttons");
- }
- }
- }
-
-
- //initial loading
- $timeout(function(){
- var bar = $(".tab-content .active .umb-tab-buttons")[0] || $(".tab-content .umb-tab-buttons")[0];
- var winHeight = $(window).height();
-
- scope.$watch(function () {
- if(!bar){
- bar = $(".tab-content .active .umb-tab-buttons")[0] || $(".tab-content .umb-tab-buttons")[0];
- }
-
- var bottom = bar.offsetTop + bar.offsetHeight;
- return bottom > winHeight;
- }, function(val) {
- _setClass(bar);
- });
-
-
- $(window).bind("resize", function () {
- _setClass(bar, true);
- winHeight = $(window).height();
- });
-
- $('a[data-toggle="tab"]').on('shown', function (e) {
- bar = $(".tab-content .active .umb-tab-buttons")[0];
- _setClass(bar);
- });
-
- }, 1000, false);
- }
+ templateUrl: 'views/directives/html/umb-panel.html'
};
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbtab.directive.js
similarity index 95%
rename from src/Umbraco.Web.UI.Client/src/common/directives/umbtab.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/html/umbtab.directive.js
index be26042678..3758c64179 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtab.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbtab.directive.js
@@ -1,14 +1,14 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:umbTab
-* @restrict E
-**/
-angular.module("umbraco.directives")
-.directive('umbTab', function(){
- return {
- restrict: 'E',
- replace: true,
- transclude: 'true',
- templateUrl: 'views/directives/umb-tab.html'
- };
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:umbTab
+* @restrict E
+**/
+angular.module("umbraco.directives")
+.directive('umbTab', function(){
+ return {
+ restrict: 'E',
+ replace: true,
+ transclude: 'true',
+ templateUrl: 'views/directives/umb-tab.html'
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtabview.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbtabview.directive.js
similarity index 95%
rename from src/Umbraco.Web.UI.Client/src/common/directives/umbtabview.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/html/umbtabview.directive.js
index 505acb3328..7bb4f1cb18 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtabview.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/html/umbtabview.directive.js
@@ -1,14 +1,14 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:umbTabView
-* @restrict E
-**/
-angular.module("umbraco.directives")
-.directive('umbTabView', function($timeout, $log){
- return {
- restrict: 'E',
- replace: true,
- transclude: 'true',
- templateUrl: 'views/directives/umb-tab-view.html'
- };
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:umbTabView
+* @restrict E
+**/
+angular.module("umbraco.directives")
+.directive('umbTabView', function($timeout, $log){
+ return {
+ restrict: 'E',
+ replace: true,
+ transclude: 'true',
+ templateUrl: 'views/directives/umb-tab-view.html'
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/autoscale.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/autoscale.directive.js
similarity index 96%
rename from src/Umbraco.Web.UI.Client/src/common/directives/autoscale.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/autoscale.directive.js
index daa432d5ba..11fff9639f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/autoscale.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/utill/autoscale.directive.js
@@ -1,38 +1,38 @@
-/**
- * @ngdoc directive
- * @name umbraco.directives.directive:autoScale
- * @element div
- * @function
- *
- * @description
- * Resize div's automatically to fit to the bottom of the screen, as an optional parameter an y-axis offset can be set
- * So if you only want to scale the div to 70 pixels from the bottom you pass "70"
- *
- * @example
-
-
-
-
-
- */
-angular.module("umbraco.directives")
- .directive('autoScale', function ($window) {
- return function (scope, el, attrs) {
-
- var totalOffset = 0;
- var offsety = parseInt(attrs.autoScale, 10);
- var window = angular.element($window);
- if (offsety !== undefined){
- totalOffset += offsety;
- }
-
- setTimeout(function () {
- el.height(window.height() - (el.offset().top + totalOffset));
- }, 500);
-
- window.bind("resize", function () {
- el.height(window.height() - (el.offset().top + totalOffset));
- });
-
- };
+/**
+ * @ngdoc directive
+ * @name umbraco.directives.directive:autoScale
+ * @element div
+ * @function
+ *
+ * @description
+ * Resize div's automatically to fit to the bottom of the screen, as an optional parameter an y-axis offset can be set
+ * So if you only want to scale the div to 70 pixels from the bottom you pass "70"
+ *
+ * @example
+
+
+
+
+
+ */
+angular.module("umbraco.directives")
+ .directive('autoScale', function ($window) {
+ return function (scope, el, attrs) {
+
+ var totalOffset = 0;
+ var offsety = parseInt(attrs.autoScale, 10);
+ var window = angular.element($window);
+ if (offsety !== undefined){
+ totalOffset += offsety;
+ }
+
+ setTimeout(function () {
+ el.height(window.height() - (el.offset().top + totalOffset));
+ }, 500);
+
+ window.bind("resize", function () {
+ el.height(window.height() - (el.offset().top + totalOffset));
+ });
+
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/utill/detectfold.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/detectfold.directive.js
new file mode 100644
index 0000000000..a0d1a8293b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/utill/detectfold.directive.js
@@ -0,0 +1,49 @@
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:umbPanel
+* @restrict E
+**/
+angular.module("umbraco.directives.html")
+ .directive('detectFold', function($timeout, $log){
+ return {
+ restrict: 'A',
+ link: function (scope, el, attrs) {
+
+ var state = false,
+ parent = $(".umb-panel-body"),
+ winHeight = $(window).height(),
+ calculate = _.throttle(function(){
+ if(el && el.is(":visible") && !el.hasClass("umb-bottom-bar")){
+ //var parent = el.parent();
+ var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
+ //var belowFold = (el.offset().top + el.height()) > winHeight;
+ if(hasOverflow){
+ el.addClass("umb-bottom-bar");
+ }
+ }
+ return state;
+ }, 1000);
+
+ scope.$watch(calculate, function(newVal, oldVal) {
+ if(newVal !== oldVal){
+ if(newVal){
+ el.addClass("umb-bottom-bar");
+ }else{
+ el.removeClass("umb-bottom-bar");
+ }
+ }
+ });
+
+ $(window).bind("resize", function () {
+ winHeight = $(window).height();
+ el.removeClass("umb-bottom-bar");
+ state = false;
+ calculate();
+ });
+
+ $('a[data-toggle="tab"]').on('shown', function (e) {
+ calculate();
+ });
+ }
+ };
+ });
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/hotkey.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/hotkey.directive.js
similarity index 96%
rename from src/Umbraco.Web.UI.Client/src/common/directives/hotkey.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/hotkey.directive.js
index f5277e98e0..39a565b7ab 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/hotkey.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/utill/hotkey.directive.js
@@ -1,27 +1,27 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:headline
-**/
-angular.module("umbraco.directives")
- .directive('hotkey', function ($window, keyboardService, $log) {
-
- return function (scope, el, attrs) {
-
- //support data binding
-
- var keyCombo = scope.$eval(attrs["hotkey"]);
- if (!keyCombo) {
- keyCombo = attrs["hotkey"];
- }
-
- keyboardService.bind(keyCombo, function() {
- var element = $(el);
- if(element.is("a,button,input[type='button'],input[type='submit']")){
- element.click();
- }else{
- element.focus();
- }
- });
-
- };
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:headline
+**/
+angular.module("umbraco.directives")
+ .directive('hotkey', function ($window, keyboardService, $log) {
+
+ return function (scope, el, attrs) {
+
+ //support data binding
+
+ var keyCombo = scope.$eval(attrs["hotkey"]);
+ if (!keyCombo) {
+ keyCombo = attrs["hotkey"];
+ }
+
+ keyboardService.bind(keyCombo, function() {
+ var element = $(el);
+ if(element.is("a,button,input[type='button'],input[type='submit']")){
+ element.click();
+ }else{
+ element.focus();
+ }
+ });
+
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/localize.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/localize.directive.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/common/directives/localize.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/localize.directive.js
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/preventdefault.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/preventdefault.directive.js
similarity index 97%
rename from src/Umbraco.Web.UI.Client/src/common/directives/preventdefault.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/preventdefault.directive.js
index e0747600ac..d1e279a9ac 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/preventdefault.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/utill/preventdefault.directive.js
@@ -1,29 +1,29 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:preventDefault
-**/
-angular.module("umbraco.directives")
- .directive('preventDefault', function() {
- return function(scope, element, attrs) {
-
- var enabled = true;
- //check if there's a value for the attribute, if there is and it's false then we conditionally don't
- //prevent default.
- if (attrs.preventDefault) {
- attrs.$observe("preventDefault", function (newVal) {
- enabled = (newVal === "false" || newVal === 0 || newVal === false) ? false : true;
- });
- }
-
- $(element).click(function (event) {
- if (event.metaKey || event.ctrlKey) {
- return;
- }
- else {
- if (enabled === true) {
- event.preventDefault();
- }
- }
- });
- };
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:preventDefault
+**/
+angular.module("umbraco.directives")
+ .directive('preventDefault', function() {
+ return function(scope, element, attrs) {
+
+ var enabled = true;
+ //check if there's a value for the attribute, if there is and it's false then we conditionally don't
+ //prevent default.
+ if (attrs.preventDefault) {
+ attrs.$observe("preventDefault", function (newVal) {
+ enabled = (newVal === "false" || newVal === 0 || newVal === false) ? false : true;
+ });
+ }
+
+ $(element).click(function (event) {
+ if (event.metaKey || event.ctrlKey) {
+ return;
+ }
+ else {
+ if (enabled === true) {
+ event.preventDefault();
+ }
+ }
+ });
+ };
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/resizeToContent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/resizeToContent.directive.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/common/directives/resizeToContent.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/resizeToContent.directive.js
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/selectOnFocus.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/utill/selectOnFocus.directive.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/common/directives/selectOnFocus.directive.js
rename to src/Umbraco.Web.UI.Client/src/common/directives/utill/selectOnFocus.directive.js
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
index 1b3902122b..0ce434d7c9 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
@@ -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);
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/views/common/main.controller.js
rename to src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js
rename to src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/search.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/search.controller.js
similarity index 100%
rename from src/Umbraco.Web.UI.Client/src/views/common/search.controller.js
rename to src/Umbraco.Web.UI.Client/src/controllers/search.controller.js
diff --git a/src/Umbraco.Web.UI.Client/src/install.loader.js b/src/Umbraco.Web.UI.Client/src/install.loader.js
new file mode 100644
index 0000000000..bf4a8e787d
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/install.loader.js
@@ -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']);
+ });
+ }
+});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.controller.js b/src/Umbraco.Web.UI.Client/src/installer/installer.controller.js
new file mode 100644
index 0000000000..30bf96a329
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer.controller.js
@@ -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);
+ };
+});
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.html b/src/Umbraco.Web.UI.Client/src/installer/installer.html
new file mode 100644
index 0000000000..39a822a896
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ Install Umbraco
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.service.js b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js
new file mode 100644
index 0000000000..e74e90eddf
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js
@@ -0,0 +1,320 @@
+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 helped millions of people watch a man jump from the edge of space',
+ 'Over 250.000 websites are currently powered by Umbraco',
+ 'On an average day, more then 1000 people download Umbraco',
+ 'umbraco.tv is the premier source of Umbraco video tutorials to get you started',
+ 'You can find the worlds friendliest CMS community at our.umbraco.org',
+ 'You can become a certified Umbraco developer by attending one of the official courses',
+ 'Umbraco works really well on tablets',
+ 'You have 100% control over your markup and design when crafting a website in Umbraco',
+ 'Umbraco is the best of both worlds: 100% free and open source, and backed by a professional and profitable company',
+ "There's a pretty big chance, you've visited a website powered by Umbraco today",
+ "'Umbraco-spotting' is the game of spotting big brands running Umbraco",
+ "Atleast 2 people have the Umbraco logo tattooed on them",
+ "'Umbraco' is the danish name for an allen key",
+ "Has been around since 2005, that's a looong time in IT",
+ "More than 400 people from all over the world meet each year in Denmark in June for our annual conference CodeGarden",
+ "While you install Umbraco someone else on the other side of the planet probably does it too",
+ "You can extend Umbraco without modifying the source code and using either javascript or c#"
+ ];
+
+ /**
+ 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+1 / 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;
+ service.status.fact = 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;
+});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/continueinstall.html b/src/Umbraco.Web.UI.Client/src/installer/steps/continueinstall.html
new file mode 100644
index 0000000000..28fa1d3fff
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/continueinstall.html
@@ -0,0 +1,13 @@
+
+
Continue Umbraco Installation
+
+ You see this screen because your Umbraco installation did not complete correctly.
+
+
+ Simply click continue below to be guided through the rest of the installation process.
+
+ Enter connection and authentication details for the database you want to install Umbraco on
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/error.html b/src/Umbraco.Web.UI.Client/src/installer/steps/error.html
new file mode 100644
index 0000000000..234f86e1a4
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/error.html
@@ -0,0 +1,9 @@
+
+
Error during installation
+
+
{{installer.current.model.message}}
+
+
See log for full details
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html b/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html
new file mode 100644
index 0000000000..3ced6ed678
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html
@@ -0,0 +1,26 @@
+
+
Your permission settings are not ready for umbraco
+
+ 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
+ here.
+
+
+ The following report list the permissions that are currently failing. Once the permissions are fixed press the 'Go back' button to restart the installation.
+
+
+
+
+
{{category}}
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.controller.js b/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.controller.js
new file mode 100644
index 0000000000..81958ddd55
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.controller.js
@@ -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();
+ };
+
+});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.html b/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.html
new file mode 100644
index 0000000000..7347023c9d
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/starterkit.html
@@ -0,0 +1,20 @@
+
+
Install a starter website
+
+
+ Installing a starter website helps you learn how Umbraco works, and gives you a solid
+ and simple foundation to build on top of.
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/upgrade.html b/src/Umbraco.Web.UI.Client/src/installer/steps/upgrade.html
new file mode 100644
index 0000000000..3638f7f37a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/upgrade.html
@@ -0,0 +1,14 @@
+
+
Upgrading Umbraco
+
+ 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.
+
+
+ Simply click continue below to be guided through the rest of the upgrade
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js b/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js
new file mode 100644
index 0000000000..6c689a3166
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js
@@ -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();
+ }
+ };
+
+});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/user.html b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html
new file mode 100644
index 0000000000..0b8b44124a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html
@@ -0,0 +1,56 @@
+
+
Install Umbraco 7
+
+
Enter your name, email and password to install Umbraco 7 with its default settings, alternatively you can customize your installation
+
+
+
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/version7upgradereport.html b/src/Umbraco.Web.UI.Client/src/installer/steps/version7upgradereport.html
new file mode 100644
index 0000000000..df1e58d737
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/version7upgradereport.html
@@ -0,0 +1,22 @@
+
+
Major version upgrade from {{installer.current.model.currentVersion}} to {{installer.current.model.newVersion}}
+
There were {{installer.current.model.errors.length}} issues detected
+
+ 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.
+
+
+ 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.
+