diff --git a/.hgtags b/.hgtags index 63cba0edc5..a099288f27 100644 --- a/.hgtags +++ b/.hgtags @@ -32,3 +32,4 @@ b247b35d821144849f551e02da8ba719f91d5fb0 Release-6.0.2 aed55cba29009ad3db48880a7cfb66407ce9805f release-6.0.3 87cf618a39e38ec58df916d10e6a924de62ae37d release-6.1.0-beta 0dee9964687ea51ea797984cf7cce3655d6a6558 release-6.0.4 +7670bb47a671a9ecc15118589d8048907ea76241 release-6.1.0-beta2 diff --git a/build/Build.bat b/build/Build.bat index 8617827d70..47f71860ff 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,6 +1,6 @@ @ECHO OFF SET release=6.1.0 -SET comment=beta +SET comment=beta-2 SET version=%release% IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 48bef1f8f9..dbb59b1d6c 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -18,6 +18,7 @@ + diff --git a/src/Umbraco.Core/Cache/CacheProviderBase.cs b/src/Umbraco.Core/Cache/CacheProviderBase.cs index fafa0939f8..026f6f9dbc 100644 --- a/src/Umbraco.Core/Cache/CacheProviderBase.cs +++ b/src/Umbraco.Core/Cache/CacheProviderBase.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Web.Caching; namespace Umbraco.Core.Cache { /// - /// An abstract class for implementing a cache helper + /// An abstract class for implementing a basic cache provider /// /// /// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC... @@ -22,13 +20,5 @@ namespace Umbraco.Core.Cache public abstract IEnumerable GetCacheItemsByKeySearch(string keyStartsWith); public abstract T GetCacheItem(string cacheKey); public abstract T GetCacheItem(string cacheKey, Func getCacheItem); - public abstract T GetCacheItem(string cacheKey, TimeSpan? timeout, Func getCacheItem); - public abstract T GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem); - public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem); - public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); - public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem); - public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func getCacheItem); - public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); - public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); } -} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs index 681dc8fab4..e574f38454 100644 --- a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.Cache /// /// A CacheProvider that wraps the logic of the HttpRuntime.Cache /// - internal class HttpRuntimeCacheProvider : CacheProviderBase + internal class HttpRuntimeCacheProvider : RuntimeCacheProviderBase { private readonly System.Web.Caching.Cache _cache; private static readonly object Locker = new object(); diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs index 3a41ae2a77..3d1bbaa79d 100644 --- a/src/Umbraco.Core/Cache/NullCacheProvider.cs +++ b/src/Umbraco.Core/Cache/NullCacheProvider.cs @@ -5,7 +5,7 @@ using System.Web.Caching; namespace Umbraco.Core.Cache { - internal class NullCacheProvider : CacheProviderBase + internal class NullCacheProvider : RuntimeCacheProviderBase { public override void ClearAllCache() { diff --git a/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs new file mode 100644 index 0000000000..9dddb4c576 --- /dev/null +++ b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs @@ -0,0 +1,24 @@ +using System; +using System.Text; +using System.Web.Caching; + +namespace Umbraco.Core.Cache +{ + /// + /// An abstract class for implementing a runtime cache provider + /// + /// + /// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC... + /// + internal abstract class RuntimeCacheProviderBase : CacheProviderBase + { + public abstract T GetCacheItem(string cacheKey, TimeSpan? timeout, Func getCacheItem); + public abstract T GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem); + public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem); + public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); + public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem); + public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func getCacheItem); + public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); + public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem); + } +} diff --git a/src/Umbraco.Core/Cache/StaticCacheProvider.cs b/src/Umbraco.Core/Cache/StaticCacheProvider.cs new file mode 100644 index 0000000000..0d0d2f288c --- /dev/null +++ b/src/Umbraco.Core/Cache/StaticCacheProvider.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web.Caching; + +namespace Umbraco.Core.Cache +{ + /// + /// A cache provider that statically caches everything in an in memory dictionary + /// + internal class StaticCacheProvider : CacheProviderBase + { + private readonly ConcurrentDictionary _staticCache = new ConcurrentDictionary(); + + public override void ClearAllCache() + { + _staticCache.Clear(); + } + + public override void ClearCacheItem(string key) + { + object val; + _staticCache.TryRemove(key, out val); + } + + public override void ClearCacheObjectTypes(string typeName) + { + foreach (var key in _staticCache.Keys) + { + if (_staticCache[key] != null + && _staticCache[key].GetType().ToString().InvariantEquals(typeName)) + { + object val; + _staticCache.TryRemove(key, out val); + } + } + } + + public override void ClearCacheObjectTypes() + { + foreach (var key in _staticCache.Keys) + { + if (_staticCache[key] != null + && _staticCache[key].GetType() == typeof(T)) + { + object val; + _staticCache.TryRemove(key, out val); + } + } + } + + public override void ClearCacheByKeySearch(string keyStartsWith) + { + foreach (var key in _staticCache.Keys) + { + if (key.InvariantStartsWith(keyStartsWith)) + { + ClearCacheItem(key); + } + } + } + + public override void ClearCacheByKeyExpression(string regexString) + { + foreach (var key in _staticCache.Keys) + { + if (Regex.IsMatch(key, regexString)) + { + ClearCacheItem(key); + } + } + } + + public override IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) + { + return (from KeyValuePair c in _staticCache + where c.Key.InvariantStartsWith(keyStartsWith) + select c.Value.TryConvertTo() + into attempt + where attempt.Success + select attempt.Result).ToList(); + } + + public override T GetCacheItem(string cacheKey) + { + var result = _staticCache[cacheKey]; + if (result == null) + { + return default(T); + } + return result.TryConvertTo().Result; + } + + public override T GetCacheItem(string cacheKey, Func getCacheItem) + { + return (T)_staticCache.GetOrAdd(cacheKey, getCacheItem); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 7c80a1e6d3..96b3d99de9 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -15,14 +15,13 @@ namespace Umbraco.Core /// /// Class that is exposed by the ApplicationContext for application wide caching purposes /// - /// - /// This class may be opened publicly at some point but needs a review of what is absoletely necessary. - /// - public class CacheHelper //: CacheProviderBase + public class CacheHelper { private readonly bool _enableCache; - private readonly HttpRuntimeCacheProvider _httpCache; - private readonly NullCacheProvider _nullCache = new NullCacheProvider(); + private readonly CacheProviderBase _staticCache; + private readonly CacheProviderBase _nullStaticCache = new NullCacheProvider(); + private readonly RuntimeCacheProviderBase _httpCache; + private readonly RuntimeCacheProviderBase _nullHttpCache = new NullCacheProvider(); public CacheHelper(System.Web.Caching.Cache cache) : this(cache, true) @@ -30,21 +29,185 @@ namespace Umbraco.Core } internal CacheHelper(System.Web.Caching.Cache cache, bool enableCache) - { - _httpCache = new HttpRuntimeCacheProvider(cache); - _enableCache = enableCache; + : this(new HttpRuntimeCacheProvider(cache), enableCache) + { } - + + internal CacheHelper(RuntimeCacheProviderBase httpCacheProvider, bool enableCache) + : this(httpCacheProvider, new StaticCacheProvider(), enableCache) + { + } + + internal CacheHelper(RuntimeCacheProviderBase httpCacheProvider, CacheProviderBase staticCacheProvider, bool enableCache) + { + _httpCache = httpCacheProvider; + _staticCache = staticCacheProvider; + _enableCache = enableCache; + } + + #region Static cache + + /// + /// Clears the item in umbraco's static cache + /// + internal void ClearAllStaticCache() + { + if (!_enableCache) + { + _nullStaticCache.ClearAllCache(); + } + else + { + _staticCache.ClearAllCache(); + } + } + + /// + /// Clears the item in umbraco's static cache with the given key + /// + /// Key + internal void ClearStaticCacheItem(string key) + { + if (!_enableCache) + { + _nullStaticCache.ClearCacheItem(key); + } + else + { + _staticCache.ClearCacheItem(key); + } + } + + /// + /// Clears all objects in the static cache with the System.Type name as the + /// input parameter. (using [object].GetType()) + /// + /// The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument" + internal void ClearStaticCacheObjectTypes(string typeName) + { + if (!_enableCache) + { + _nullStaticCache.ClearCacheObjectTypes(typeName); + } + else + { + _staticCache.ClearCacheObjectTypes(typeName); + } + } + + /// + /// Clears all objects in the static cache with the System.Type specified + /// + internal void ClearStaticCacheObjectTypes() + { + if (!_enableCache) + { + _nullStaticCache.ClearCacheObjectTypes(); + } + else + { + _staticCache.ClearCacheObjectTypes(); + } + } + + /// + /// Clears all static cache items that starts with the key passed. + /// + /// The start of the key + internal void ClearStaticCacheByKeySearch(string keyStartsWith) + { + if (!_enableCache) + { + _nullStaticCache.ClearCacheByKeySearch(keyStartsWith); + } + else + { + _staticCache.ClearCacheByKeySearch(keyStartsWith); + } + } + + /// + /// Clears all cache items that have a key that matches the regular expression + /// + /// + internal void ClearStaticCacheByKeyExpression(string regexString) + { + if (!_enableCache) + { + _nullStaticCache.ClearCacheByKeyExpression(regexString); + } + else + { + _staticCache.ClearCacheByKeyExpression(regexString); + } + } + + internal IEnumerable GetStaticCacheItemsByKeySearch(string keyStartsWith) + { + if (!_enableCache) + { + return _nullStaticCache.GetCacheItemsByKeySearch(keyStartsWith); + } + else + { + return _staticCache.GetCacheItemsByKeySearch(keyStartsWith); + } + } + + /// + /// Returns a static cache item by key, does not update the cache if it isn't there. + /// + /// + /// + /// + internal TT GetStaticCacheItem(string cacheKey) + { + if (!_enableCache) + { + return _nullStaticCache.GetCacheItem(cacheKey); + } + else + { + return _staticCache.GetCacheItem(cacheKey); + } + } + + /// + /// Gets (and adds if necessary) an item from the static cache with all of the default parameters + /// + /// + /// + /// + /// + internal TT GetStaticCacheItem(string cacheKey, Func getCacheItem) + { + if (!_enableCache) + { + return _nullStaticCache.GetCacheItem(cacheKey, getCacheItem); + } + else + { + return _staticCache.GetCacheItem(cacheKey, getCacheItem); + } + } + + #endregion + + + #region Runtime/Http Cache + /// + /// Clears the item in umbraco's runtime cache + /// public void ClearAllCache() - { - if (!_enableCache) - { - _nullCache.ClearAllCache(); - } - else - { - _httpCache.ClearAllCache(); - } + { + if (!_enableCache) + { + _nullHttpCache.ClearAllCache(); + } + else + { + _httpCache.ClearAllCache(); + } } /// @@ -55,7 +218,7 @@ namespace Umbraco.Core { if (!_enableCache) { - _nullCache.ClearCacheItem(key); + _nullHttpCache.ClearCacheItem(key); } else { @@ -73,7 +236,7 @@ namespace Umbraco.Core { if (!_enableCache) { - _nullCache.ClearCacheObjectTypes(typeName); + _nullHttpCache.ClearCacheObjectTypes(typeName); } else { @@ -84,55 +247,55 @@ namespace Umbraco.Core /// /// Clears all objects in the System.Web.Cache with the System.Type specified /// - public void ClearCacheObjectTypes() - { + public void ClearCacheObjectTypes() + { if (!_enableCache) { - _nullCache.ClearCacheObjectTypes(); + _nullHttpCache.ClearCacheObjectTypes(); } else { _httpCache.ClearCacheObjectTypes(); } - } + } - /// + /// /// Clears all cache items that starts with the key passed. /// /// The start of the key public void ClearCacheByKeySearch(string keyStartsWith) - { + { if (!_enableCache) { - _nullCache.ClearCacheByKeySearch(keyStartsWith); + _nullHttpCache.ClearCacheByKeySearch(keyStartsWith); } else { _httpCache.ClearCacheByKeySearch(keyStartsWith); } - } + } /// /// Clears all cache items that have a key that matches the regular expression /// /// - public void ClearCacheByKeyExpression(string regexString) - { + public void ClearCacheByKeyExpression(string regexString) + { if (!_enableCache) { - _nullCache.ClearCacheByKeyExpression(regexString); + _nullHttpCache.ClearCacheByKeyExpression(regexString); } else { _httpCache.ClearCacheByKeyExpression(regexString); } - } + } public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { if (!_enableCache) { - return _nullCache.GetCacheItemsByKeySearch(keyStartsWith); + return _nullHttpCache.GetCacheItemsByKeySearch(keyStartsWith); } else { @@ -140,7 +303,7 @@ namespace Umbraco.Core } } - /// + /// /// Returns a cache item by key, does not update the cache if it isn't there. /// /// @@ -150,7 +313,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey); + return _nullHttpCache.GetCacheItem(cacheKey); } else { @@ -169,7 +332,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem); } else { @@ -190,7 +353,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, timeout, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, timeout, getCacheItem); } else { @@ -213,7 +376,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, refreshAction, timeout, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, refreshAction, timeout, getCacheItem); } else { @@ -237,7 +400,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, priority, refreshAction, timeout, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, priority, refreshAction, timeout, getCacheItem); } else { @@ -257,15 +420,15 @@ namespace Umbraco.Core /// /// public TT GetCacheItem(string cacheKey, - CacheItemPriority priority, - CacheItemRemovedCallback refreshAction, - CacheDependency cacheDependency, - TimeSpan timeout, - Func getCacheItem) + CacheItemPriority priority, + CacheItemRemovedCallback refreshAction, + CacheDependency cacheDependency, + TimeSpan timeout, + Func getCacheItem) { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem); } else { @@ -289,7 +452,7 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullCache.GetCacheItem(cacheKey, priority, null, cacheDependency, null, getCacheItem); + return _nullHttpCache.GetCacheItem(cacheKey, priority, null, cacheDependency, null, getCacheItem); } else { @@ -310,14 +473,14 @@ namespace Umbraco.Core { if (!_enableCache) { - _nullCache.InsertCacheItem(cacheKey, priority, getCacheItem); + _nullHttpCache.InsertCacheItem(cacheKey, priority, getCacheItem); } else { _httpCache.InsertCacheItem(cacheKey, priority, getCacheItem); } } - + /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced /// @@ -333,7 +496,7 @@ namespace Umbraco.Core { if (!_enableCache) { - _nullCache.InsertCacheItem(cacheKey, priority, timeout, getCacheItem); + _nullHttpCache.InsertCacheItem(cacheKey, priority, timeout, getCacheItem); } else { @@ -341,30 +504,30 @@ namespace Umbraco.Core } } - /// - /// Inserts an item into the cache, if it already exists in the cache it will be replaced - /// - /// - /// - /// - /// - /// This will set an absolute expiration from now until the timeout - /// - public void InsertCacheItem(string cacheKey, - CacheItemPriority priority, - CacheDependency cacheDependency, - TimeSpan timeout, - Func getCacheItem) - { + /// + /// Inserts an item into the cache, if it already exists in the cache it will be replaced + /// + /// + /// + /// + /// + /// This will set an absolute expiration from now until the timeout + /// + public void InsertCacheItem(string cacheKey, + CacheItemPriority priority, + CacheDependency cacheDependency, + TimeSpan timeout, + Func getCacheItem) + { if (!_enableCache) { - _nullCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem); + _nullHttpCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem); } else { _httpCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem); } - } + } /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced @@ -376,22 +539,23 @@ namespace Umbraco.Core /// /// This will set an absolute expiration from now until the timeout /// - public void InsertCacheItem(string cacheKey, - CacheItemPriority priority, - CacheItemRemovedCallback refreshAction, - CacheDependency cacheDependency, - TimeSpan? timeout, - Func getCacheItem) - { + public void InsertCacheItem(string cacheKey, + CacheItemPriority priority, + CacheItemRemovedCallback refreshAction, + CacheDependency cacheDependency, + TimeSpan? timeout, + Func getCacheItem) + { if (!_enableCache) { - _nullCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem); + _nullHttpCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem); } else { _httpCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem); } - } + } + #endregion } diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 3558901033..9d9a1d91f0 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration /// Gets the version comment (like beta or RC). /// /// The version comment. - public static string CurrentComment { get { return "beta"; } } + public static string CurrentComment { get { return "beta-2"; } } // Get the version of the umbraco.dll by looking at a class in that dll // Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 43b6c68d3e..106a73f367 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix; using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; +using Umbraco.Core.Profiling; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Publishing; using Umbraco.Core.Macros; @@ -52,8 +53,9 @@ namespace Umbraco.Core if (_isInitialized) throw new InvalidOperationException("The boot manager has already been initialized"); - LogHelper.Info("Umbraco application starting"); - _timer = DisposableTimer.Start(x => LogHelper.Info("Umbraco application startup complete" + " (took " + x + "ms)")); + InitializeProfilerResolver(); + + _timer = DisposableTimer.DebugDuration("Umbraco application starting", "Umbraco application startup complete"); //create database and service contexts for the app context var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName); @@ -93,6 +95,20 @@ namespace Umbraco.Core ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext); } + /// + /// Special method to initialize the ProfilerResolver + /// + protected virtual void InitializeProfilerResolver() + { + //By default we'll initialize the Log profiler (in the web project, we'll override with the web profiler) + ProfilerResolver.Current = new ProfilerResolver(new LogProfiler()) + { + //This is another special resolver that needs to be resolvable before resolution is frozen + //since it is used for profiling the application startup + CanResolveBeforeFrozen = true + }; + } + /// /// Special method to initialize the ApplicationEventsResolver and any modifications required for it such /// as adding custom types to the resolver. @@ -185,7 +201,8 @@ namespace Umbraco.Core /// Create the resolvers /// protected virtual void InitializeResolvers() - { + { + //by default we'll use the standard configuration based sync ServerRegistrarResolver.Current = new ServerRegistrarResolver( new ConfigServerRegistrar()); diff --git a/src/Umbraco.Core/DictionaryExtensions.cs b/src/Umbraco.Core/DictionaryExtensions.cs index 83d89fcaba..73866f2c9b 100644 --- a/src/Umbraco.Core/DictionaryExtensions.cs +++ b/src/Umbraco.Core/DictionaryExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; @@ -10,10 +11,60 @@ using System.Web; namespace Umbraco.Core { /// - /// Extension methods for dictionary + /// Extension methods for dictionary & concurrentdictionary /// internal static class DictionaryExtensions { + /// + /// Updates an item with the specified key with the specified value + /// + /// + /// + /// + /// + /// + /// + /// + /// Taken from: http://stackoverflow.com/questions/12240219/is-there-a-way-to-use-concurrentdictionary-tryupdate-with-a-lambda-expression + /// + /// If there is an item in the dictionary with the key, it will keep trying to update it until it can + /// + public static bool TryUpdate(this ConcurrentDictionary dict, TKey key, Func updateFactory) + { + TValue curValue; + while (dict.TryGetValue(key, out curValue)) + { + if (dict.TryUpdate(key, updateFactory(curValue), curValue)) + return true; + //if we're looping either the key was removed by another thread, or another thread + //changed the value, so we start again. + } + return false; + } + + /// + /// Updates an item with the specified key with the specified value + /// + /// + /// + /// + /// + /// + /// + /// + /// Taken from: http://stackoverflow.com/questions/12240219/is-there-a-way-to-use-concurrentdictionary-tryupdate-with-a-lambda-expression + /// + /// WARNING: If the value changes after we've retreived it, then the item will not be updated + /// + public static bool TryUpdateOptimisitic(this ConcurrentDictionary dict, TKey key, Func updateFactory) + { + TValue curValue; + if (!dict.TryGetValue(key, out curValue)) + return false; + dict.TryUpdate(key, updateFactory(curValue), curValue); + return true;//note we return true whether we succeed or not, see explanation below. + } + /// /// Converts a dictionary to another type by only using direct casting /// diff --git a/src/Umbraco.Core/DisposableTimer.cs b/src/Umbraco.Core/DisposableTimer.cs index f2a6904b9f..f0df0be23e 100644 --- a/src/Umbraco.Core/DisposableTimer.cs +++ b/src/Umbraco.Core/DisposableTimer.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics; +using System.Web; using Umbraco.Core.Logging; +using Umbraco.Core.Profiling; namespace Umbraco.Core { @@ -9,11 +11,17 @@ namespace Umbraco.Core /// /// /// + /// + /// using (DisposableTimer.TraceDuration{MyType}("starting", "finished")) + /// { + /// Thread.Sleep(567); + /// } + /// /// Console.WriteLine("Testing Stopwatchdisposable, should be 567:"); - // using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result))) - // { - // Thread.Sleep(567); - // } + /// using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result))) + /// { + /// Thread.Sleep(567); + /// } /// /// public class DisposableTimer : DisposableObject @@ -24,7 +32,7 @@ namespace Umbraco.Core protected DisposableTimer(Action callback) { _callback = callback; - } + } public Stopwatch Stopwatch { @@ -36,96 +44,149 @@ namespace Umbraco.Core /// /// The callback. /// + [Obsolete("Use either TraceDuration or DebugDuration instead of using Start")] public static DisposableTimer Start(Action callback) { return new DisposableTimer(callback); } - public static DisposableTimer TraceDuration(Func startMessage, Func completeMessage) - { - return TraceDuration(typeof(T), startMessage, completeMessage); - } + #region TraceDuration + public static DisposableTimer TraceDuration(Func startMessage, Func completeMessage) + { + return TraceDuration(typeof(T), startMessage, completeMessage); + } - public static DisposableTimer TraceDuration(Type loggerType, Func startMessage, Func completeMessage) - { - LogHelper.Debug(loggerType, startMessage); - return new DisposableTimer(x => LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)")); - } + public static DisposableTimer TraceDuration(Type loggerType, Func startMessage, Func completeMessage) + { + var startMsg = startMessage(); + LogHelper.Info(loggerType, startMsg); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("Start: " + startMsg); + var profiler = ActivateProfiler(loggerType, startMsg); + return new DisposableTimer(x => + { + profiler.DisposeIfDisposable(); + LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)"); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("End: " + startMsg); + }); + } - /// - /// Adds a start and end log entry as Info and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer TraceDuration(string startMessage, string completeMessage) - { - return TraceDuration(typeof(T), startMessage, completeMessage); - } + /// + /// Adds a start and end log entry as Info and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer TraceDuration(string startMessage, string completeMessage) + { + return TraceDuration(typeof(T), startMessage, completeMessage); + } - /// - /// Adds a start and end log entry as Info and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage) - { - LogHelper.Info(loggerType, () => startMessage); - return new DisposableTimer(x => LogHelper.Info(loggerType, () => completeMessage + " (took " + x + "ms)")); - } + public static DisposableTimer TraceDuration(string startMessage) + { + return TraceDuration(typeof(T), startMessage, "Complete"); + } - /// - /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer DebugDuration(string startMessage, string completeMessage) - { - return DebugDuration(typeof(T), startMessage, completeMessage); - } + /// + /// Adds a start and end log entry as Info and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage) + { + LogHelper.Info(loggerType, startMessage); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("Start: " + startMessage); + var profiler = ActivateProfiler(loggerType, startMessage); + return new DisposableTimer(x => + { + profiler.DisposeIfDisposable(); + LogHelper.Info(loggerType, () => completeMessage + " (took " + x + "ms)"); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("End: " + startMessage); + }); + } + #endregion - /// - /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer DebugDuration(Func startMessage, Func completeMessage) - { - return DebugDuration(typeof(T), startMessage, completeMessage); - } + #region DebugDuration + /// + /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer DebugDuration(string startMessage, string completeMessage) + { + return DebugDuration(typeof(T), startMessage, completeMessage); + } - /// - /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage) - { - LogHelper.Debug(loggerType, () => startMessage); - return new DisposableTimer(x => LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)")); - } + public static DisposableTimer DebugDuration(string startMessage) + { + return DebugDuration(typeof(T), startMessage, "Complete"); + } - /// - /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. - /// - /// - /// - /// - /// - public static DisposableTimer DebugDuration(Type loggerType, Func startMessage, Func completeMessage) - { - LogHelper.Debug(loggerType, startMessage); - return new DisposableTimer(x => LogHelper.Debug(loggerType, () => completeMessage() + " (took " + x + "ms)")); - } + /// + /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer DebugDuration(Func startMessage, Func completeMessage) + { + return DebugDuration(typeof(T), startMessage, completeMessage); + } + + /// + /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage) + { + LogHelper.Debug(loggerType, startMessage); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("Start: " + startMessage); + var profiler = ActivateProfiler(loggerType, startMessage); + return new DisposableTimer(x => + { + profiler.DisposeIfDisposable(); + LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)"); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("End: " + startMessage); + }); + } + + /// + /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. + /// + /// + /// + /// + /// + public static DisposableTimer DebugDuration(Type loggerType, Func startMessage, Func completeMessage) + { + var msg = startMessage(); + LogHelper.Debug(loggerType, msg); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("Start: " + startMessage); + var profiler = ActivateProfiler(loggerType, msg); + return new DisposableTimer(x => + { + profiler.DisposeIfDisposable(); + LogHelper.Debug(loggerType, () => completeMessage() + " (took " + x + "ms)"); + if (HttpContext.Current != null) + HttpContext.Current.Trace.Write("End: " + startMessage); + }); + } + #endregion /// /// Handles the disposal of resources. Derived from abstract class which handles common required locking logic. @@ -134,5 +195,19 @@ namespace Umbraco.Core { _callback.Invoke(Stopwatch.ElapsedMilliseconds); } + + private static IDisposable ActivateProfiler(Type loggerType, string profileName) + { + try + { + return ProfilerResolver.Current.Profiler.Step(loggerType, profileName); + } + catch (InvalidOperationException) + { + //swallow this exception, it will occur if the ProfilerResolver is not initialized... generally only in + // unit tests. + } + return null; + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/IO/FileSystemProviderAttribute.cs b/src/Umbraco.Core/IO/FileSystemProviderAttribute.cs index 39bb8db8dc..f94cee537d 100644 --- a/src/Umbraco.Core/IO/FileSystemProviderAttribute.cs +++ b/src/Umbraco.Core/IO/FileSystemProviderAttribute.cs @@ -5,12 +5,11 @@ using System.Text; using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.IO -{ - [UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")] +{ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - internal class FileSystemProviderAttribute : Attribute + public class FileSystemProviderAttribute : Attribute { - public string Alias { get; set; } + public string Alias { get; private set; } public FileSystemProviderAttribute(string alias) { diff --git a/src/Umbraco.Core/IO/FileSystemProvider.cs b/src/Umbraco.Core/IO/FileSystemProviderConstants.cs similarity index 56% rename from src/Umbraco.Core/IO/FileSystemProvider.cs rename to src/Umbraco.Core/IO/FileSystemProviderConstants.cs index 1f6013078f..a447c4df8e 100644 --- a/src/Umbraco.Core/IO/FileSystemProvider.cs +++ b/src/Umbraco.Core/IO/FileSystemProviderConstants.cs @@ -6,8 +6,7 @@ using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.IO { - [UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")] - internal class FileSystemProvider + internal class FileSystemProviderConstants { public const string Media = "media"; } diff --git a/src/Umbraco.Core/IO/FileSystemProviderManager.cs b/src/Umbraco.Core/IO/FileSystemProviderManager.cs index 5654e764d6..cb18454fb8 100644 --- a/src/Umbraco.Core/IO/FileSystemProviderManager.cs +++ b/src/Umbraco.Core/IO/FileSystemProviderManager.cs @@ -9,9 +9,8 @@ using Umbraco.Core.CodeAnnotations; using Umbraco.Core.Configuration; namespace Umbraco.Core.IO -{ - [UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")] - internal class FileSystemProviderManager +{ + public class FileSystemProviderManager { private readonly FileSystemProvidersSection _config; @@ -28,7 +27,7 @@ namespace Umbraco.Core.IO #region Constructors - public FileSystemProviderManager() + internal FileSystemProviderManager() { _config = (FileSystemProvidersSection)ConfigurationManager.GetSection("FileSystemProviders"); } @@ -48,7 +47,15 @@ namespace Umbraco.Core.IO private readonly ConcurrentDictionary _providerLookup = new ConcurrentDictionary(); private readonly ConcurrentDictionary _wrappedProviderLookup = new ConcurrentDictionary(); - public IFileSystem GetFileSystemProvider(string alias) + /// + /// Returns the underlying (non-typed) file system provider for the alias specified + /// + /// + /// + /// + /// It is recommended to use the typed GetFileSystemProvider method instead to get a strongly typed provider instance. + /// + public IFileSystem GetUnderlyingFileSystemProvider(string alias) { //either get the constructor info from cache or create it and add to cache var ctorInfo = _providerLookup.GetOrAdd(alias, s => @@ -88,6 +95,11 @@ namespace Umbraco.Core.IO return fs; } + /// + /// Returns the strongly typed file system provider + /// + /// + /// public TProviderTypeFilter GetFileSystemProvider() where TProviderTypeFilter : FileSystemWrapper { @@ -111,7 +123,7 @@ namespace Umbraco.Core.IO return attr.Alias; }); - var innerFs = GetFileSystemProvider(alias); + var innerFs = GetUnderlyingFileSystemProvider(alias); var outputFs = Activator.CreateInstance(typeof (TProviderTypeFilter), innerFs); return (TProviderTypeFilter)outputFs; } diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index 4a5f7cbd99..4f3bc2665b 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -170,7 +170,7 @@ namespace Umbraco.Core.ObjectResolution get { // ensure we can - if (!CanResolveBeforeFrozen) + if (CanResolveBeforeFrozen == false) Resolution.EnsureIsFrozen(); // note: we apply .ToArray() to the output of CreateInstance() because that is an IEnumerable that diff --git a/src/Umbraco.Core/ObjectResolution/ResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ResolverBase.cs index fd22a76610..d6bf59351d 100644 --- a/src/Umbraco.Core/ObjectResolution/ResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ResolverBase.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.ObjectResolution //add itself to the internal collection ResolverCollection.Add(this, resetAction); } - + } /// diff --git a/src/Umbraco.Core/ObjectResolution/SingleObjectResolverBase.cs b/src/Umbraco.Core/ObjectResolution/SingleObjectResolverBase.cs index 5d0e57c8f9..b4a54f66b6 100644 --- a/src/Umbraco.Core/ObjectResolution/SingleObjectResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/SingleObjectResolverBase.cs @@ -69,6 +69,12 @@ namespace Umbraco.Core.ObjectResolution #endregion + /// + /// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen. + /// + /// This is false by default and is used for some special internal resolvers. + internal bool CanResolveBeforeFrozen { get; set; } + /// /// Gets a value indicating whether the resolved object instance can be null. /// @@ -96,7 +102,10 @@ namespace Umbraco.Core.ObjectResolution { get { - Resolution.EnsureIsFrozen(); + // ensure we can + if (CanResolveBeforeFrozen == false) + Resolution.EnsureIsFrozen(); + using (new ReadLock(_lock)) { if (!_canBeNull && _value == null) diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs index 254133fe8e..7a65fe33bc 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs @@ -455,9 +455,12 @@ namespace Umbraco.Core.Persistence.Querying if (fieldType == typeof(decimal)) return ((decimal)value).ToString(CultureInfo.InvariantCulture); - if(fieldType == typeof(DateTime)) + if (fieldType == typeof(DateTime)) return "'" + EscapeParam(((DateTime)value).ToString(CultureInfo.InvariantCulture)) + "'"; - + + if (fieldType == typeof(bool)) + return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture); + return ShouldQuoteValue(fieldType) ? "'" + EscapeParam(value) + "'" : value.ToString(); diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 60d28e5292..e69ef4cca2 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using StackExchange.Profiling; using Umbraco.Core.Logging; namespace Umbraco.Core.Persistence @@ -40,6 +41,13 @@ namespace Umbraco.Core.Persistence { } + public override IDbConnection OnConnectionOpened(IDbConnection connection) + { + // wrap the connection with a profiling connection that tracks timings + return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current); + } + + public override void OnException(Exception x) { LogHelper.Info(x.StackTrace); diff --git a/src/Umbraco.Core/Profiling/IProfiler.cs b/src/Umbraco.Core/Profiling/IProfiler.cs new file mode 100644 index 0000000000..4a3f7a8829 --- /dev/null +++ b/src/Umbraco.Core/Profiling/IProfiler.cs @@ -0,0 +1,43 @@ +using System; + +namespace Umbraco.Core.Profiling +{ + /// + /// Defines an object for use in the application to profile operations + /// + internal interface IProfiler + { + /// + /// Render the UI to display the profiler + /// + /// + /// + /// Generally used for HTML displays + /// + string Render(); + + /// + /// Profile an operation + /// + /// + /// + /// + /// Use the 'using(' syntax + /// + IDisposable Step(string name); + + /// + /// Start the profiler + /// + void Start(); + + /// + /// Start the profiler + /// + /// + /// set discardResults to false when you want to abandon all profiling, this is useful for + /// when someone is not authenticated or you want to clear the results based on some other mechanism. + /// + void Stop(bool discardResults = false); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Profiling/LogProfiler.cs b/src/Umbraco.Core/Profiling/LogProfiler.cs new file mode 100644 index 0000000000..fbcb21988a --- /dev/null +++ b/src/Umbraco.Core/Profiling/LogProfiler.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Profiling +{ + /// + /// A profiler that outputs its results to the LogHelper + /// + internal class LogProfiler : IProfiler + { + public string Render() + { + return string.Empty; + } + + public IDisposable Step(string name) + { + LogHelper.Debug(typeof(LogProfiler), "Starting - " + name); + return DisposableTimer.Start(l => LogHelper.Info(typeof(LogProfiler), () => name + " (took " + l + "ms)")); + } + + public void Start() + { + //the log will alwasy be started + } + + public void Stop(bool discardResults = false) + { + //we don't need to do anything here + } + } +} diff --git a/src/Umbraco.Core/Profiling/ProfilerExtensions.cs b/src/Umbraco.Core/Profiling/ProfilerExtensions.cs new file mode 100644 index 0000000000..d4bbeb6744 --- /dev/null +++ b/src/Umbraco.Core/Profiling/ProfilerExtensions.cs @@ -0,0 +1,35 @@ +using System; + +namespace Umbraco.Core.Profiling +{ + internal static class ProfilerExtensions + { + /// + /// Writes out a step prefixed with the type + /// + /// + /// + /// + /// + internal static IDisposable Step(this IProfiler profiler, string name) + { + if (profiler == null) throw new ArgumentNullException("profiler"); + return profiler.Step(typeof (T), name); + } + + /// + /// Writes out a step prefixed with the type + /// + /// + /// + /// + /// + internal static IDisposable Step(this IProfiler profiler, Type objectType, string name) + { + if (profiler == null) throw new ArgumentNullException("profiler"); + if (objectType == null) throw new ArgumentNullException("objectType"); + if (name == null) throw new ArgumentNullException("name"); + return profiler.Step(string.Format("[{0}] {1}", objectType.Name, name)); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Profiling/ProfilerResolver.cs b/src/Umbraco.Core/Profiling/ProfilerResolver.cs new file mode 100644 index 0000000000..e6b8bc7aab --- /dev/null +++ b/src/Umbraco.Core/Profiling/ProfilerResolver.cs @@ -0,0 +1,39 @@ +using Umbraco.Core.ObjectResolution; + +namespace Umbraco.Core.Profiling +{ + /// + /// A resolver exposing the current profiler + /// + internal class ProfilerResolver : SingleObjectResolverBase + { + /// + /// Constructor + /// + /// + public ProfilerResolver(IProfiler profiler) + : base(profiler) + { + + } + + /// + /// Method allowing to change the profiler during startup + /// + /// + internal void SetProfiler(IProfiler profiler) + { + Value = profiler; + } + + /// + /// Gets the current profiler + /// + public IProfiler Profiler + { + get { return Value; } + } + + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Profiling/WebProfiler.cs b/src/Umbraco.Core/Profiling/WebProfiler.cs new file mode 100644 index 0000000000..56918ff349 --- /dev/null +++ b/src/Umbraco.Core/Profiling/WebProfiler.cs @@ -0,0 +1,161 @@ +using System; +using System.Web; +using StackExchange.Profiling; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Profiling +{ + /// + /// A profiler used for web based activity based on the MiniProfiler framework + /// + internal class WebProfiler : IProfiler + { + + /// + /// Constructor + /// + /// + /// Binds to application events to enable the MiniProfiler + /// + internal WebProfiler() + { + UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit; + } + + /// + /// Handle the Init event o fthe UmbracoApplication which allows us to subscribe to the HttpApplication events + /// + /// + /// + void UmbracoApplicationApplicationInit(object sender, EventArgs e) + { + var app = sender as HttpApplication; + if (app == null) return; + + if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) + { + //If we don't have a high enough trust level we cannot bind to the events + LogHelper.Info("Cannot start the WebProfiler since the application is running in Medium trust"); + } + else + { + app.BeginRequest += UmbracoApplicationBeginRequest; + app.EndRequest += UmbracoApplicationEndRequest; + } + } + + /// + /// Handle the begin request event + /// + /// + /// + void UmbracoApplicationEndRequest(object sender, EventArgs e) + { + if (GlobalSettings.DebugMode == false) return; + var request = TryGetRequest(sender); + if (request.Success == false) return; + if (request.Result.Url.IsClientSideRequest()) return; + if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false) + { + //stop the profiler + Stop(); + } + } + + /// + /// Handle the end request event + /// + /// + /// + void UmbracoApplicationBeginRequest(object sender, EventArgs e) + { + if (GlobalSettings.DebugMode == false) return; + var request = TryGetRequest(sender); + if (request.Success == false) return; + if (request.Result.Url.IsClientSideRequest()) return; + if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false) + { + //start the profiler + Start(); + } + } + + /// + /// Render the UI to display the profiler + /// + /// + /// + /// Generally used for HTML displays + /// + public string Render() + { + return MiniProfiler.RenderIncludes().ToString(); + } + + /// + /// Profile a step + /// + /// + /// + /// + /// Use the 'using(' syntax + /// + public IDisposable Step(string name) + { + if (GlobalSettings.DebugMode == false) return null; + + return MiniProfiler.Current.Step(name); + } + + /// + /// Start the profiler + /// + public void Start() + { + if (GlobalSettings.DebugMode == false) return; + //will not run in medium trust + if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return; + + MiniProfiler.Start(); + } + + /// + /// Start the profiler + /// + /// + /// set discardResults to false when you want to abandon all profiling, this is useful for + /// when someone is not authenticated or you want to clear the results based on some other mechanism. + /// + public void Stop(bool discardResults = false) + { + if (GlobalSettings.DebugMode == false) return; + //will not run in medium trust + if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return; + + MiniProfiler.Stop(discardResults); + } + + /// + /// Gets the request object from the app instance if it is available + /// + /// The application object + /// + private Attempt TryGetRequest(object sender) + { + var app = sender as HttpApplication; + if (app == null) return Attempt.False; + + try + { + var req = app.Request; + return new Attempt(true, new HttpRequestWrapper(req)); + } + catch (HttpException ex) + { + return new Attempt(ex); + } + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 364d38bd9c..6912da28ae 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -65,17 +65,10 @@ namespace Umbraco.Core.Services select doc; var contents = ParseDocumentRootXml(roots, parentId); - var importContent = contents as IContent[] ?? contents.ToArray(); - if (importContent.Any()) - { - _contentService.Save(importContent, userId); + if (contents.Any()) + _contentService.Save(contents, userId); - //Don't just save, also publish - foreach (var content in importContent) - _contentService.Publish(content, userId); - } - - return importContent; + return contents; } var attribute = element.Attribute("isDoc"); @@ -84,18 +77,10 @@ namespace Umbraco.Core.Services //This is a single doc import var elements = new List { element }; var contents = ParseDocumentRootXml(elements, parentId); - var importContent = contents as IContent[] ?? contents.ToArray(); - - if (importContent.Any()) - { - _contentService.Save(importContent, userId); + if (contents.Any()) + _contentService.Save(contents, userId); - //Don't just save, also publish - foreach (var content in importContent) - _contentService.Publish(content, userId); - } - - return importContent; + return contents; } throw new ArgumentException( diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index a0dd3bb4f5..524f786fbb 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -42,6 +42,9 @@ True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll @@ -113,13 +116,15 @@ + - + + @@ -524,6 +529,11 @@ + + + + + @@ -753,7 +763,7 @@ - + diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index 6962acdd07..dd6c3a8103 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -2,6 +2,8 @@ using System.Web; using System.Web.Hosting; using System.Web.Mvc; +using StackExchange.Profiling; +using Umbraco.Core.Configuration; using Umbraco.Core.Logging; namespace Umbraco.Core @@ -20,6 +22,11 @@ namespace Umbraco.Core public static event EventHandler ApplicationStarting; public static event EventHandler ApplicationStarted; + /// + /// Called when the HttpApplication.Init() is fired, allows developers to subscribe to the HttpApplication events + /// + public static event EventHandler ApplicationInit; + /// /// Boots up the Umbraco application /// @@ -45,6 +52,15 @@ namespace Umbraco.Core StartApplication(sender, e); } + /// + /// Override init and raise the event + /// + public override void Init() + { + base.Init(); + OnApplicationInit(this, new EventArgs()); + } + /// /// Developers can override this method to modify objects on startup /// @@ -67,6 +83,17 @@ namespace Umbraco.Core ApplicationStarted(sender, e); } + /// + /// Called to raise the ApplicationInit event + /// + /// + /// + private void OnApplicationInit(object sender, EventArgs e) + { + if (ApplicationInit != null) + ApplicationInit(sender, e); + } + /// /// A method that can be overridden to invoke code when the application has an error. /// diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 87accb9bdd..45088aa1bf 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using System.Linq; using System.Text; namespace Umbraco.Core @@ -8,6 +10,19 @@ namespace Umbraco.Core /// public static class UriExtensions { + /// + /// This is a performance tweak to check if this is a .css, .js or .ico, .jpg, .jpeg, .png, .gif file request since + /// .Net will pass these requests through to the module when in integrated mode. + /// We want to ignore all of these requests immediately. + /// + /// + /// + internal static bool IsClientSideRequest(this Uri url) + { + var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif" }; + return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x)); + } + /// /// Rewrites the path of uri. /// diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config index f820b06b32..f6607eb886 100644 --- a/src/Umbraco.Core/packages.config +++ b/src/Umbraco.Core/packages.config @@ -5,6 +5,7 @@ + diff --git a/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs b/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs index 7b2f8d3dd8..6a83caf407 100644 --- a/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs +++ b/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs @@ -7,29 +7,38 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.ObjectResolution; using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Tests.TestHelpers; using umbraco.interfaces; namespace Umbraco.Tests.BootManagers { [TestFixture] - public class CoreBootManagerTests + public class CoreBootManagerTests : BaseUmbracoApplicationTest { private TestApp _testApp; [SetUp] - public void Setup() + public override void Initialize() { + base.Initialize(); _testApp = new TestApp(); } [TearDown] - public void TearDown() + public override void TearDown() { + base.TearDown(); + _testApp = null; - ApplicationEventsResolver.Reset(); - SqlSyntaxProvidersResolver.Reset(); + //ApplicationEventsResolver.Reset(); + //SqlSyntaxProvidersResolver.Reset(); + } + + protected override void FreezeResolution() + { + //don't freeze resolution, we'll do that in the boot manager } /// diff --git a/src/Umbraco.Tests/IO/FileSystemProviderManagerTests.cs b/src/Umbraco.Tests/IO/FileSystemProviderManagerTests.cs index 28706303d3..48d5819ebb 100644 --- a/src/Umbraco.Tests/IO/FileSystemProviderManagerTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemProviderManagerTests.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.IO [Test] public void Can_Get_Base_File_System() { - var fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media); + var fs = FileSystemProviderManager.Current.GetUnderlyingFileSystemProvider(FileSystemProviderConstants.Media); Assert.NotNull(fs); } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index b7957d17c1..2882b124c2 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.PublishedContent //need to specify a custom callback for unit tests PublishedContentHelper.GetDataTypeCallback = (docTypeAlias, propertyAlias) => { - if (propertyAlias == "content") + if (propertyAlias.InvariantEquals("content")) { //return the rte type id return Guid.Parse(Constants.PropertyEditors.TinyMCEv3); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 274793938a..8582a894d5 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -240,6 +240,10 @@ namespace Umbraco.Tests.PublishedContent var propVal2 = doc.GetPropertyValue("content"); Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal2.GetType())); Assert.AreEqual("
This is some content
", propVal2.ToString()); + + var propVal3 = doc.GetPropertyValue("Content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal3.GetType())); + Assert.AreEqual("
This is some content
", propVal3.ToString()); } [Test] diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index c12538a723..d31e6dbec8 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -88,7 +88,7 @@ namespace Umbraco.Tests.Routing public void Is_Client_Side_Request(string url, bool assert) { var uri = new Uri("http://test.com" + url); - var result = _module.IsClientSideRequest(uri); + var result = uri.IsClientSideRequest(); Assert.AreEqual(assert, result); } diff --git a/src/Umbraco.Tests/TypeFinderTests.cs b/src/Umbraco.Tests/TypeFinderTests.cs index f246f9d951..c77620c11e 100644 --- a/src/Umbraco.Tests/TypeFinderTests.cs +++ b/src/Umbraco.Tests/TypeFinderTests.cs @@ -15,6 +15,7 @@ using NUnit.Framework; using SqlCE4Umbraco; using Umbraco.Core; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Tests; using Umbraco.Tests.TestHelpers; using Umbraco.Web.BaseRest; @@ -69,8 +70,7 @@ namespace Umbraco.Tests } - - [Test] + [Test] public void Find_Class_Of_Type_With_Attribute() { diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c83f0c5f5e..1ffe861698 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -127,6 +127,10 @@ False ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + + False + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + False ..\packages\MySql.Data.6.6.4\lib\net40\MySql.Data.dll @@ -436,6 +440,13 @@ StarterKits.aspx + + editPython.aspx + ASPXCodeBehind + + + editPython.aspx + EditMacro.aspx ASPXCodeBehind @@ -534,6 +545,10 @@ + + + + 404handlers.config @@ -832,9 +847,14 @@ + + + + + @@ -2027,7 +2047,9 @@ - + + Designer + applications.config Designer @@ -2495,6 +2517,7 @@ + @@ -2508,7 +2531,6 @@ - 10.0 diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index b1f3bd7d3b..e5e88a781a 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -140,7 +140,7 @@ true true - Webforms + Mvc diff --git a/src/Umbraco.Web.UI/install/Title.ascx b/src/Umbraco.Web.UI/install/Title.ascx index da622df135..748e05dfe8 100644 --- a/src/Umbraco.Web.UI/install/Title.ascx +++ b/src/Umbraco.Web.UI/install/Title.ascx @@ -1,3 +1,3 @@ <%@ Control Language="C#" AutoEventWireup="True" CodeBehind="Title.ascx.cs" Inherits="Umbraco.Web.UI.Install.Title" %> <%@ Import Namespace="Umbraco.Core.Configuration" %> -Umbraco <%=UmbracoVersion.Current.ToString(3)%> Configuration Wizard \ No newline at end of file +Umbraco <%=UmbracoVersion.Current.ToString(3)%> <%=UmbracoVersion.CurrentComment%> Configuration Wizard \ No newline at end of file diff --git a/src/Umbraco.Web.UI/install/steps/database.ascx b/src/Umbraco.Web.UI/install/steps/database.ascx index 489ad83557..b1b46eeebd 100644 --- a/src/Umbraco.Web.UI/install/steps/database.ascx +++ b/src/Umbraco.Web.UI/install/steps/database.ascx @@ -210,7 +210,7 @@ @@ -69,9 +50,4 @@ OffSetY="55" runat="server" /> - diff --git a/src/Umbraco.Web.UI/umbraco/developer/Xslt/editXslt.aspx b/src/Umbraco.Web.UI/umbraco/developer/Xslt/editXslt.aspx index 5dfbc53f01..a4368ada4c 100644 --- a/src/Umbraco.Web.UI/umbraco/developer/Xslt/editXslt.aspx +++ b/src/Umbraco.Web.UI/umbraco/developer/Xslt/editXslt.aspx @@ -9,54 +9,30 @@ - + + + + @@ -92,15 +67,9 @@ - + - diff --git a/src/Umbraco.Web.UI/umbraco/settings/EditTemplate.aspx.designer.cs b/src/Umbraco.Web.UI/umbraco/settings/EditTemplate.aspx.designer.cs index d77c3b0cfa..956466eac9 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/EditTemplate.aspx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/settings/EditTemplate.aspx.designer.cs @@ -11,5 +11,14 @@ namespace Umbraco.Web.UI.Umbraco.Settings { public partial class EditTemplate { + + /// + /// JsInclude1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude1; } } diff --git a/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx b/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx index be119d814f..5669c799e4 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx @@ -11,162 +11,91 @@ - + @@ -190,7 +119,7 @@ function insertMacro(alias)
- + Insert Inline Razor Macro @@ -205,7 +134,7 @@ function insertMacro(alias)
- + Insert Macro diff --git a/src/Umbraco.Web.UI/umbraco/settings/scripts/editScript.aspx b/src/Umbraco.Web.UI/umbraco/settings/scripts/editScript.aspx index 14d049c27d..d9ee1f6a9f 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/scripts/editScript.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/scripts/editScript.aspx @@ -3,34 +3,39 @@ ValidateRequest="False" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> +<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> + + + @@ -48,9 +53,5 @@ - + diff --git a/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx b/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx index efa825d1ef..8907b64236 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx @@ -8,32 +8,29 @@ diff --git a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx index 54fc190717..2253dae9cc 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx @@ -24,6 +24,8 @@ $(document).ready(function () { //create and assign a new EditView object editViewEditor = new Umbraco.Editors.EditView({ + treeSyncPath: "<%=TemplateTreeSyncPath%>", + currentTreeType: "<%=CurrentTreeType%>", editorType: "<%= EditorType.ToString() %>", originalFileName: "<%=OriginalFileName %>", restServiceLocation: "<%= Url.GetSaveFileServicePath() %>", diff --git a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs index 9d6db3c41a..b0f9b57c7e 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs +++ b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs @@ -45,6 +45,23 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views get { return _template == null ? ViewEditorType.PartialView : ViewEditorType.Template; } } + protected string TemplateTreeSyncPath { get; private set; } + + /// + /// This view is shared between different trees so we'll look for the query string + /// + protected string CurrentTreeType + { + get + { + if (Request.QueryString["treeType"].IsNullOrWhiteSpace()) + { + return TreeDefinitionCollection.Instance.FindTree().Tree.Alias; + } + return Request.QueryString["treeType"]; + } + } + /// /// Returns the original file name that the editor was loaded with /// @@ -89,9 +106,6 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views AliasTxt.Text = _template.Alias; editorSource.Text = _template.Design; - ClientTools - .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) - .SyncTree("-1,init," + _template.Path.Replace("-1,", ""), false); } else { @@ -105,13 +119,13 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views var s = sr.ReadToEnd(); editorSource.Text = s; } - - //string path = DeepLink.GetTreePathFromFilePath(file); - //ClientTools - // .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) - // .SyncTree(path, false); + } } + + ClientTools + .SetActiveTreeType(CurrentTreeType) + .SyncTree(TemplateTreeSyncPath, false); } @@ -122,12 +136,14 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views //check if a templateId is assigned, meaning we are editing a template if (!Request.QueryString["templateID"].IsNullOrWhiteSpace()) { - _template = new Template(int.Parse(Request.QueryString["templateID"])); + _template = new Template(int.Parse(Request.QueryString["templateID"])); + TemplateTreeSyncPath = "-1,init," + _template.Path.Replace("-1,", ""); } else if (!Request.QueryString["file"].IsNullOrWhiteSpace()) { //we are editing a view (i.e. partial view) OriginalFileName = HttpUtility.UrlDecode(Request.QueryString["file"]); + TemplateTreeSyncPath = "-1,init," + Path.GetFileName(OriginalFileName); } else { diff --git a/src/Umbraco.Web.UI/umbraco/umbraco.aspx b/src/Umbraco.Web.UI/umbraco/umbraco.aspx index 1726b5509c..6f6ec216e9 100644 --- a/src/Umbraco.Web.UI/umbraco/umbraco.aspx +++ b/src/Umbraco.Web.UI/umbraco/umbraco.aspx @@ -4,6 +4,9 @@ <%@ Import Namespace="System.Web.Script.Serialization" %> <%@ Register Src="controls/Tree/TreeControl.ascx" TagName="TreeControl" TagPrefix="umbraco" %> +<%@ Import Namespace="StackExchange.Profiling" %> +<%@ Import Namespace="Umbraco.Core.Profiling" %> +<%@ Import Namespace="Umbraco.Web" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> <%@ Register TagPrefix="uc1" TagName="quickSearch" Src="Search/QuickSearch.ascx" %> <%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> @@ -388,5 +391,9 @@ } + <%if(string.IsNullOrEmpty(Request["umbDebug"]) == false && umbraco.GlobalSettings.DebugMode) + { + Response.Write(Html.RenderProfiler()); + }%> diff --git a/src/Umbraco.Web.UI/umbraco/xslt/Web.config b/src/Umbraco.Web.UI/umbraco/xslt/Web.config new file mode 100644 index 0000000000..fd6e3a816a --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/xslt/Web.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditMacroScripts.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditMacroScripts.js new file mode 100644 index 0000000000..8215461336 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditMacroScripts.js @@ -0,0 +1,70 @@ +Umbraco.Sys.registerNamespace("Umbraco.Editors"); + +(function ($) { + + Umbraco.Editors.EditMacroScripts = base2.Base.extend({ + //private methods/variables + _opts: null, + + // Constructor + constructor: function(opts) { + // Merge options with default + this._opts = $.extend({ + + + // Default options go here + }, opts); + }, + + init: function () { + //setup UI elements + var self = this; + + //bind to the save event + this._opts.saveButton.click(function () { + self.doSubmit(); + }); + }, + + doSubmit: function () { + var self = this; + + jQuery('#errorDiv').hide(); + + var fileName = this._opts.nameTxtBox.val(); + var codeVal = this._opts.editorSourceElement.val(); + //if CodeMirror is not defined, then the code editor is disabled. + if (typeof (CodeMirror) != "undefined") { + codeVal = UmbEditor.GetCode(); + } + umbraco.presentation.webservices.codeEditorSave.SaveDLRScript( + fileName, self._opts.originalFileName, codeVal, self._opts.skipTestingCheckBox.is(':checked'), + function (t) { self.submitSucces(t); }, + function (t) { self.submitFailure(t); }); + + }, + + submitSucces: function(t) { + if (t != 'true') { + top.UmbSpeechBubble.ShowMessage('error', 'Saving scripting file failed', ''); + jQuery('#errorDiv').html('

Hide ErrorsError occured

' + t + '

'); + jQuery('#errorDiv').slideDown('fast'); + } + else { + top.UmbSpeechBubble.ShowMessage('save', 'Scripting file saved', ''); + } + + + var newFilePath = this._opts.nameTxtBox.val(); + UmbClientMgr.mainTree().setActiveTreeType('python'); + //we need to pass in the newId parameter so it knows which node to resync after retreival from the server + UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.originalFileName, true, null, newFilePath); + //set the original file path to the new one + this._opts.originalFileName = newFilePath; + }, + + submitFailure: function(t) { + top.UmbSpeechBubble.ShowMessage('warning', 'Scripting file could not be saved', ''); + } + }); +})(jQuery); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditScript.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditScript.js new file mode 100644 index 0000000000..3761c316a9 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditScript.js @@ -0,0 +1,66 @@ +Umbraco.Sys.registerNamespace("Umbraco.Editors"); + +(function ($) { + + Umbraco.Editors.EditScript = base2.Base.extend({ + //private methods/variables + _opts: null, + + // Constructor + constructor: function(opts) { + // Merge options with default + this._opts = $.extend({ + + + // Default options go here + }, opts); + }, + + init: function () { + //setup UI elements + var self = this; + + //bind to the save event + this._opts.saveButton.click(function () { + self.doSubmit(); + }); + }, + + doSubmit: function () { + var self = this; + + var fileName = this._opts.nameTxtBox.val(); + var codeVal = this._opts.editorSourceElement.val(); + //if CodeMirror is not defined, then the code editor is disabled. + if (typeof (CodeMirror) != "undefined") { + codeVal = UmbEditor.GetCode(); + } + umbraco.presentation.webservices.codeEditorSave.SaveScript( + fileName, self._opts.originalFileName, codeVal, + function (t) { self.submitSucces(t); }, + function (t) { self.submitFailure(t); }); + + }, + + submitSucces: function(t) { + if (t != 'true') { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.fileErrorHeader, this._opts.text.fileErrorText); + } + else { + top.UmbSpeechBubble.ShowMessage('save', this._opts.text.fileSavedHeader, this._opts.text.fileSavedText); + } + + + var newFilePath = this._opts.nameTxtBox.val(); + UmbClientMgr.mainTree().setActiveTreeType('scripts'); + //we need to pass in the newId parameter so it knows which node to resync after retreival from the server + UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.originalFileName, true, null, newFilePath); + //set the original file path to the new one + this._opts.originalFileName = newFilePath; + }, + + submitFailure: function(t) { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.fileErrorHeader, this._opts.text.fileErrorText); + } + }); +})(jQuery); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditStyleSheet.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditStyleSheet.js index 1357fa6e0b..b68cc7e2ac 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Editors/EditStyleSheet.js +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditStyleSheet.js @@ -3,64 +3,62 @@ (function ($) { Umbraco.Editors.EditStyleSheet = base2.Base.extend({ - //private methods/variables - _opts: null, + //private methods/variables + _opts: null, - // Constructor - constructor: function(opts) { - // Merge options with default - this._opts = $.extend({ - - // Default options go here - }, opts); - }, - - save: function() { - var self = this; - - umbraco.presentation.webservices.codeEditorSave.SaveCss( - self._opts.fileName, self._opts.oldName, self._opts.codeVal, self._opts.cssId, - function(t) { self.submitSucces(t); }, - function(t) { self.submitFailure(t); }); - - }, - - submitSucces: function(t) { - if (t != 'true') { - top.UmbSpeechBubble.ShowMessage('error', this._opts.text.cssErrorHeader, this._opts.text.cssErrorText); - } - else { - top.UmbSpeechBubble.ShowMessage('save', this._opts.text.cssSavedHeader, this._opts.text.cssSavedText); - } + // Constructor + constructor: function(opts) { + // Merge options with default + this._opts = $.extend({ - UmbClientMgr.mainTree().setActiveTreeType('stylesheets'); - UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.cssId, true); - }, - submitFailure: function(t) { - top.UmbSpeechBubble.ShowMessage('error', this._opts.text.cssErrorHeader, this._opts.text.cssErrorText); - - UmbClientMgr.mainTree().setActiveTreeType('stylesheets'); - UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.cssId, true); - } + // Default options go here + }, opts); }, - { - saveStyleSheet: function(editorSourceClientId, nameTxtClientId, nameTxtValue, cssId) { - //Static method to do the saving - var codeVal = $('#' + editorSourceClientId).val(); - //if CodeMirror is not defined, then the code editor is disabled. - if (typeof(CodeMirror) != "undefined") { - codeVal = UmbEditor.GetCode(); - } + init: function() { + //setup UI elements + var self = this; - var processor = new Umbraco.Editors.EditStyleSheet({ - codeVal: codeVal, - fileName: $('#' + nameTxtClientId).val(), - oldname: nameTxtValue, - cssId: cssId - }); - processor.save(); + //bind to the save event + this._opts.saveButton.click(function() { + self.doSubmit(); + }); + }, + + doSubmit: function() { + var self = this; + + var fileName = this._opts.nameTxtBox.val(); + var codeVal = this._opts.editorSourceElement.val(); + //if CodeMirror is not defined, then the code editor is disabled. + if (typeof(CodeMirror) != "undefined") { + codeVal = UmbEditor.GetCode(); } - }); + umbraco.presentation.webservices.codeEditorSave.SaveCss( + fileName, self._opts.originalFileName, codeVal, self._opts.cssId, + function(t) { self.submitSucces(t); }, + function(t) { self.submitFailure(t); }); + + }, + + submitSucces: function(t) { + if (t != 'true') { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.cssErrorHeader, this._opts.text.cssErrorText); + } + else { + top.UmbSpeechBubble.ShowMessage('save', this._opts.text.cssSavedHeader, this._opts.text.cssSavedText); + } + + UmbClientMgr.mainTree().setActiveTreeType('stylesheets'); + UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.cssId, true); + + //update the originalFileName prop + this._opts.originalFileName = this._opts.nameTxtBox.val(); + }, + + submitFailure: function(t) { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.cssErrorHeader, this._opts.text.cssErrorText); + } + }); })(jQuery); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js new file mode 100644 index 0000000000..d67cd2aae5 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js @@ -0,0 +1,127 @@ +Umbraco.Sys.registerNamespace("Umbraco.Editors"); + +(function ($) { + + Umbraco.Editors.EditTemplate = base2.Base.extend({ + //private methods/variables + _opts: null, + + _openMacroModal: function(alias) { + var t = ""; + if (alias != null && alias != "") { + t = "&alias=" + alias; + } + UmbClientMgr.openModalWindow(this._opts.umbracoPath + '/dialogs/editMacro.aspx?renderingEngine=Webforms&objectId=' + this._opts.editorClientId + t, 'Insert Macro', true, 470, 530, 0, 0, '', ''); + }, + + _insertMacro: function(alias) { + var macroElement = "umbraco:Macro"; + if (!this._opts.useMasterPages) { + macroElement = "?UMBRACO_MACRO"; + } + var cp = macroElement + ' Alias="' + alias + '" runat="server"'; + UmbEditor.Insert('<' + cp + ' />', '', this._opts.editorClientId); + }, + + _insertCodeBlockFromTemplate: function(templateId) { + var self = this; + $.ajax({ + type: "POST", + url: this._opts.umbracoPath + "/webservices/templates.asmx/GetCodeSnippet", + data: "{templateId: '" + templateId + "'}", + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function(msg) { + + var cp = 'umbraco:Macro runat="server" language="cshtml"'; + UmbEditor.Insert('\n<' + cp + '>\n' + msg.d, '\n\n', self._opts.editorClientId); + + } + }); + }, + + _insertCodeBlock: function() { + var snip = this._umbracoInsertSnippet(); + UmbEditor.Insert(snip.BeginTag, snip.EndTag, this._opts.editorClientId); + }, + + _umbracoInsertSnippet: function() { + var snip = new UmbracoCodeSnippet(); + var cp = 'umbraco:Macro runat="server" language="cshtml"'; + snip.BeginTag = '\n<' + cp + '>\n'; + snip.EndTag = '\n<' + '/umbraco:Macro' + '>\n'; + snip.TargetId = this._opts.editorClientId; + return snip; + }, + + // Constructor + constructor: function(opts) { + // Merge options with default + this._opts = $.extend({ + + + // Default options go here + }, opts); + }, + + init: function() { + //Sets up the UI and binds events + + var self = this; + + $("#sb").click(function() { + self._insertCodeBlock(); + }); + $("#sbMacro").click(function() { + self._openMacroModal(); + }); + //macro split button + $('#sbMacro').splitbutton({ menu: '#macroMenu' }); + $("#splitButtonMacro").appendTo("#splitButtonMacroPlaceHolder"); + + ////razor macro split button + $('#sb').splitbutton({ menu: '#codeTemplateMenu' }); + $("#splitButton").appendTo("#splitButtonPlaceHolder"); + + $(".macro").click(function() { + var alias = $(this).attr("rel"); + if ($(this).attr("params") == "1") { + self._openMacroModal(alias); + } + else { + self._insertMacro(alias); + } + }); + + $(".codeTemplate").click(function() { + self._insertCodeBlockFromTemplate($(this).attr("rel")); + }); + }, + + save: function(templateName, templateAlias, codeVal) { + var self = this; + + umbraco.presentation.webservices.codeEditorSave.SaveTemplate( + templateName, templateAlias, codeVal, self._opts.templateId, self._opts.masterTemplateId, + function(t) { self.submitSucces(t); }, + function(t) { self.submitFailure(t); }); + + }, + + submitSucces: function(t) { + if (t != 'true') { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.templateErrorHeader, this._opts.text.templateErrorText); + } + else { + top.UmbSpeechBubble.ShowMessage('save', this._opts.text.templateSavedHeader, this._opts.text.templateSavedText); + } + + UmbClientMgr.mainTree().setActiveTreeType('templates'); + UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true); + }, + + submitFailure: function(t) { + top.UmbSpeechBubble.ShowMessage('error', this._opts.text.templateErrorHeader, this._opts.text.templateErrorText); + } + }); +})(jQuery); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js index 382b70b53a..646890a042 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js @@ -8,6 +8,21 @@ //private methods/variables _opts: null, + _updateNewProperties: function(filePath) { + /// Updates the current treeSyncPath and original file name to have the new file name + + //update the originalFileName prop + this._opts.originalFileName = filePath; + + //re-create the new path + var subPath = this._opts.treeSyncPath.split(","); + //remove the last element + subPath.pop(); + //add the new element + subPath.push(filePath.split("/")[1]); + this._opts.treeSyncPath = subPath.join(); + }, + // Constructor constructor: function (opts) { // Merge options with default @@ -92,10 +107,26 @@ submitSuccess: function (err, header) { top.UmbSpeechBubble.ShowMessage('save', header, err); + + UmbClientMgr.mainTree().setActiveTreeType(this._opts.currentTreeType); + + var newFilePath = this._opts.nameTxtBox.val(); + + if (this._opts.editorType == "Template") { + //templates are different because they are ID based, whereas view files are file based without a static id + UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true); + } + else { + //we need to pass in the newId parameter so it knows which node to resync after retreival from the server + UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true, null, newFilePath.split("/")[1]); + } + + //then we need to update our current tree sync path to represent the new one + this._updateNewProperties(newFilePath); }, submitFailure: function (err, header) { - top.UmbSpeechBubble.ShowMessage('error', header, err); + top.UmbSpeechBubble.ShowMessage('error', header, err); }, changeMasterPageFile: function ( ) { diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.css b/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.css new file mode 100644 index 0000000000..975c68b0c2 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.css @@ -0,0 +1,14 @@ +#errorDiv +{ + margin-bottom: 10px; +} + + #errorDiv a + { + float: right; + } + +.propertyItemheader +{ + width: 200px !important; +} diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.js new file mode 100644 index 0000000000..07cd265c6d --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditXslt.js @@ -0,0 +1,69 @@ +Umbraco.Sys.registerNamespace("Umbraco.Editors"); + +(function ($) { + + Umbraco.Editors.EditXslt = base2.Base.extend({ + //private methods/variables + _opts: null, + + // Constructor + constructor: function(opts) { + // Merge options with default + this._opts = $.extend({ + + + // Default options go here + }, opts); + }, + + init: function () { + //setup UI elements + var self = this; + + //bind to the save event + this._opts.saveButton.click(function () { + self.doSubmit(); + }); + }, + + doSubmit: function () { + var self = this; + + $('#errorDiv').hide(); + + var fileName = this._opts.nameTxtBox.val(); + var codeVal = this._opts.editorSourceElement.val(); + //if CodeMirror is not defined, then the code editor is disabled. + if (typeof (CodeMirror) != "undefined") { + codeVal = UmbEditor.GetCode(); + } + umbraco.presentation.webservices.codeEditorSave.SaveXslt( + fileName, self._opts.originalFileName, codeVal, self._opts.skipTestingCheckBox.is(':checked'), + function (t) { self.submitSucces(t); }, + function (t) { self.submitFailure(t); }); + + }, + + submitSucces: function (t) { + if (t != 'true') { + top.UmbSpeechBubble.ShowMessage('error', 'Saving Xslt file failed', ''); + jQuery('#errorDiv').html('

Hide ErrorsError occured

' + t + '

'); + jQuery('#errorDiv').slideDown('fast'); + } + else { + top.UmbSpeechBubble.ShowMessage('save', 'Xslt file saved', ''); + } + + var newFilePath = this._opts.nameTxtBox.val(); + UmbClientMgr.mainTree().setActiveTreeType('xslt'); + //we need to pass in the newId parameter so it knows which node to resync after retreival from the server + UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.originalFileName, true, null, newFilePath); + //set the original file path to the new one + this._opts.originalFileName = newFilePath; + }, + + submitFailure: function(t) { + top.UmbSpeechBubble.ShowMessage('warning', 'Xslt file could not be saved', ''); + } + }); +})(jQuery); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/Tree/UmbracoTree.js b/src/Umbraco.Web.UI/umbraco_client/Tree/UmbracoTree.js index 71c419337a..cc6e3e5d00 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Tree/UmbracoTree.js +++ b/src/Umbraco.Web.UI/umbraco_client/Tree/UmbracoTree.js @@ -51,7 +51,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); functionToCall: "", nodeKey: "" }; - } + }; Umbraco.Controls.UmbracoTree = function() { /// @@ -100,10 +100,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); if (this._opts.appActions != null) { var _this = this; //wrapped functions maintain scope - this._opts.appActions.addEventHandler("nodeDeleting", function(E) { _this.onNodeDeleting(E) }); - this._opts.appActions.addEventHandler("nodeDeleted", function(E) { _this.onNodeDeleted(E) }); - this._opts.appActions.addEventHandler("nodeRefresh", function(E) { _this.onNodeRefresh(E) }); - this._opts.appActions.addEventHandler("publicError", function(E, err) { _this.onPublicError(E, err) }); + this._opts.appActions.addEventHandler("nodeDeleting", function (E) { _this.onNodeDeleting(E); }); + this._opts.appActions.addEventHandler("nodeDeleted", function (E) { _this.onNodeDeleted(E); }); + this._opts.appActions.addEventHandler("nodeRefresh", function (E) { _this.onNodeRefresh(E); }); + this._opts.appActions.addEventHandler("publicError", function (E, err) { _this.onPublicError(E, err); }); } this._containerId = jItem.attr("id"); @@ -309,19 +309,20 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); } }, - syncTree: function(path, forceReload, supressChildReload) { + syncTree: function(path, forceReload, supressChildReload, newId) { /// /// Syncronizes the tree with the path supplied and makes that node visible/selected. /// /// The path of the node /// If true, will ensure that the node to be synced is synced with data from the server + /// This parameter is only used when we don't have a real unique ID for a node, for example for a file. If a filename changes we don't know what the new one is since we are syncing the tree to the old original path. Once we retreive the results the sync the tree we need to find the result by it's new id and update the node. this._debug("syncTree: " + path + ", " + forceReload); //set the flag so that multiple synces aren't attempted this._isSyncing = true; - this._syncTree.call(this, path, forceReload, null, null, supressChildReload); + this._syncTree.call(this, path, forceReload, null, null, supressChildReload, newId); }, @@ -864,7 +865,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); this._tree.open_branch(liNode, false, callback); }, - _syncTree: function(path, forceReload, numPaths, numAsync, supressChildReload) { + _syncTree: function(path, forceReload, numPaths, numAsync, supressChildReload, newId) { /// /// This is the internal method that will recursively search for the nodes to sync. If an invalid path is /// passed to this method, it will raise an event which can be handled. @@ -873,6 +874,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); /// If true, will ensure that the node to be synced is synced with data from the server /// the number of id's deep to search starting from the end of the path. Used in recursion. /// the number of async calls made so far to sync. Used in recursion and used to determine if the found node has been loaded by ajax. + /// This parameter is only used when we don't have a real unique ID for a node, for example for a file. If a filename changes we don't know what the new one is since we are syncing the tree to the old original path. Once we retreive the results the sync the tree we need to find the result by it's new id and update the node. this._debug("_syncTree"); @@ -917,6 +919,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); this._debug("_syncTree: found! numAsync: " + numAsync + ", forceReload: " + forceReload + ", doReload: " + doReload); if (doReload) { this._actionNode = this.getNodeDef(found); + //we need to change the id if the newId parameter is set + if (newId) { + this._actionNode.nodeId = newId; + } if (supressChildReload === undefined) { this.reloadActionNode(false, true, null); } else { diff --git a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/da.js b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/da.js index 36132d39e2..a93d2e36f2 100644 --- a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/da.js +++ b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/da.js @@ -1,3 +1,3 @@ tinyMCE.addI18n('da.umbracoembed', { - desc: 'Inds\u00E6t ekstern mediefil', + desc: 'Inds\u00E6t ekstern mediefil' }); diff --git a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en.js b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en.js index eb73226c6c..2b086df34e 100644 --- a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en.js +++ b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en.js @@ -1,3 +1,3 @@ tinyMCE.addI18n('en.umbracoembed', { - desc: 'Embed third party media', + desc: 'Embed third party media' }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en_us.js b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en_us.js index 6f9f7fe55f..4698979aab 100644 --- a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en_us.js +++ b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracoembed/langs/en_us.js @@ -1,3 +1,3 @@ tinyMCE.addI18n('en_us.umbracoembed', { - desc: 'Embed third party media', + desc: 'Embed third party media' }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/xslt/Web.config b/src/Umbraco.Web.UI/xslt/Web.config new file mode 100644 index 0000000000..fd6e3a816a --- /dev/null +++ b/src/Umbraco.Web.UI/xslt/Web.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index 2fa8300d46..ecccd126a0 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -10,17 +10,29 @@ using System.Web.Routing; using Umbraco.Core; using Umbraco.Core.Dynamics; using Umbraco.Core.IO; +using Umbraco.Core.Profiling; using Umbraco.Web.Mvc; using umbraco; using umbraco.cms.businesslogic.member; namespace Umbraco.Web { - /// + + /// /// HtmlHelper extensions for use in templates /// public static class HtmlHelperRenderExtensions { + /// + /// Renders the markup for the profiler + /// + /// + /// + public static IHtmlString RenderProfiler(this HtmlHelper helper) + { + return new HtmlString(ProfilerResolver.Current.Profiler.Render()); + } + /// /// Renders a partial view that is found in the specified area /// diff --git a/src/Umbraco.Web/Mvc/ControllerExtensions.cs b/src/Umbraco.Web/Mvc/ControllerExtensions.cs index d17b1f2afe..087f124c6a 100644 --- a/src/Umbraco.Web/Mvc/ControllerExtensions.cs +++ b/src/Umbraco.Web/Mvc/ControllerExtensions.cs @@ -22,6 +22,16 @@ namespace Umbraco.Web.Mvc } /// + /// Return the controller name from the controller instance + /// + /// + /// + internal static string GetControllerName(this IController controllerInstance) + { + return GetControllerName(controllerInstance.GetType()); + } + + /// /// Return the controller name from the controller type /// /// diff --git a/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs b/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs index 5f762b430e..7c5d23ae74 100644 --- a/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs +++ b/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs @@ -1,4 +1,5 @@ using System; +using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; @@ -6,64 +7,65 @@ using Umbraco.Core.Dynamics; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Profiling; using Umbraco.Web.Models; namespace Umbraco.Web.Mvc { - /// - /// The View that front-end templates inherit from - /// - public abstract class UmbracoTemplatePage : UmbracoViewPage - { - protected UmbracoTemplatePage() - { + /// + /// The View that front-end templates inherit from + /// + public abstract class UmbracoTemplatePage : UmbracoViewPage + { + protected UmbracoTemplatePage() + { - } + } - protected override void InitializePage() - { - base.InitializePage(); - //set the model to the current node if it is not set, this is generally not the case - if (Model != null) - { - ////this.ViewData.Model = Model; - //var backingItem = new DynamicBackingItem(Model.CurrentNode); - var dynamicNode = new DynamicPublishedContent(Model.Content); - CurrentPage = dynamicNode.AsDynamic(); - } - } + protected override void InitializePage() + { + base.InitializePage(); + //set the model to the current node if it is not set, this is generally not the case + if (Model != null) + { + ////this.ViewData.Model = Model; + //var backingItem = new DynamicBackingItem(Model.CurrentNode); + var dynamicNode = new DynamicPublishedContent(Model.Content); + CurrentPage = dynamicNode.AsDynamic(); + } + } - protected override void SetViewData(System.Web.Mvc.ViewDataDictionary viewData) - { - //Here we're going to check if the viewData's model is of IPublishedContent, this is basically just a helper for - //syntax on the front-end so we can just pass in an IPublishedContent object to partial views that inherit from - //UmbracoTemplatePage. Then we're going to manually contruct a RenderViewModel to pass back in to SetViewData - if (viewData.Model is IPublishedContent) - { - //change the model to a RenderModel and auto set the culture - viewData.Model = new RenderModel((IPublishedContent)viewData.Model, UmbracoContext.PublishedContentRequest.Culture); - } + protected override void SetViewData(System.Web.Mvc.ViewDataDictionary viewData) + { + //Here we're going to check if the viewData's model is of IPublishedContent, this is basically just a helper for + //syntax on the front-end so we can just pass in an IPublishedContent object to partial views that inherit from + //UmbracoTemplatePage. Then we're going to manually contruct a RenderViewModel to pass back in to SetViewData + if (viewData.Model is IPublishedContent) + { + //change the model to a RenderModel and auto set the culture + viewData.Model = new RenderModel((IPublishedContent)viewData.Model, UmbracoContext.PublishedContentRequest.Culture); + } - base.SetViewData(viewData); - } + base.SetViewData(viewData); + } - /// - /// Returns the a DynamicPublishedContent object - /// - public dynamic CurrentPage { get; private set; } + /// + /// Returns the a DynamicPublishedContent object + /// + public dynamic CurrentPage { get; private set; } - private UmbracoHelper _helper; + private UmbracoHelper _helper; - /// - /// Gets an UmbracoHelper - /// - /// - /// This ensures that the UmbracoHelper is constructed with the content model of this view - /// - public override UmbracoHelper Umbraco - { - get { return _helper ?? (_helper = new UmbracoHelper(UmbracoContext, Model.Content)); } - } + /// + /// Gets an UmbracoHelper + /// + /// + /// This ensures that the UmbracoHelper is constructed with the content model of this view + /// + public override UmbracoHelper Umbraco + { + get { return _helper ?? (_helper = new UmbracoHelper(UmbracoContext, Model.Content)); } + } /// /// This will detect the end /body tag and insert the preview badge if in preview mode @@ -72,26 +74,38 @@ namespace Umbraco.Web.Mvc public override void WriteLiteral(object value) { // filter / add preview banner - if (Response.ContentType.InvariantEquals("text/html") && UmbracoContext.Current.InPreviewMode) // ASP.NET default value + if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value { - var text = value.ToString().ToLowerInvariant(); - int pos = text.IndexOf(""); - if (pos > -1) - { - var htmlBadge = - String.Format(UmbracoSettings.PreviewBadge, - IOHelper.ResolveUrl(SystemDirectories.Umbraco), - IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), - Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); - text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); - base.WriteLiteral(text); - return; + if (UmbracoContext.Current.IsDebug || UmbracoContext.Current.InPreviewMode) + { + var text = value.ToString().ToLowerInvariant(); + int pos = text.IndexOf(""); + if (pos > -1) + { + if (UmbracoContext.Current.InPreviewMode) + { + var htmlBadge = + String.Format(UmbracoSettings.PreviewBadge, + IOHelper.ResolveUrl(SystemDirectories.Umbraco), + IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), + Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); + + text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); + } + else + { + var profilerMarkup = this.Html.RenderProfiler(); + text = text.Substring(0, pos) + profilerMarkup + text.Substring(pos, text.Length - pos); + } + base.WriteLiteral(text); + return; + } } } base.WriteLiteral(value); } - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs index daeaa85cb8..6fc59eb0ed 100644 --- a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs +++ b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs @@ -325,7 +325,7 @@ namespace Umbraco.Web.Routing // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template // some finders may implement caching - using (DisposableTimer.DebugDuration( + using (DisposableTimer.DebugDuration( () => string.Format("{0}Begin finders", tracePrefix), () => string.Format("{0}End finders, {1}", tracePrefix, (_pcr.HasPublishedContent ? "a document was found" : "no document was found")))) { diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index e7551ae2ea..972644ff49 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -379,9 +379,16 @@ namespace Umbraco.Web.Security return encTicket.DecryptWithMachineKey(); } } - catch (HttpException ex) + catch (Exception ex) { - // we swallow this type of exception as it happens if a legacy (pre 4.8.1) cookie is set + if (ex is ArgumentException || ex is FormatException || ex is HttpException) + { + StateHelper.Cookies.UserContext.Clear(); + } + else + { + throw; + } } } return ""; diff --git a/src/Umbraco.Web/Trees/PartialViewMacrosTree.cs b/src/Umbraco.Web/Trees/PartialViewMacrosTree.cs index 777b4cb5db..1278648de5 100644 --- a/src/Umbraco.Web/Trees/PartialViewMacrosTree.cs +++ b/src/Umbraco.Web/Trees/PartialViewMacrosTree.cs @@ -26,9 +26,9 @@ namespace Umbraco.Web.Trees //NOTE: Notice the MacroPartials%2f string below, this is a URLEncoded string of "MacroPartials/" so that the editor knows // to load the file from the correct location javascript.Append( - @" + @" function openMacroPartialView(id) { - UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?file=MacroPartials%2f' + id); + UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?treeType=partialViewMacros&file=MacroPartials%2f' + id); } "); } diff --git a/src/Umbraco.Web/Trees/PartialViewsTree.cs b/src/Umbraco.Web/Trees/PartialViewsTree.cs index dba21b129a..341a906d25 100644 --- a/src/Umbraco.Web/Trees/PartialViewsTree.cs +++ b/src/Umbraco.Web/Trees/PartialViewsTree.cs @@ -28,9 +28,9 @@ namespace Umbraco.Web.Trees //NOTE: Notice the Partials%2f string below, this is a URLEncoded string of "Partials/" so that the editor knows // to load the file from the correct location javascript.Append( - @" + @" function openPartialView(id) { - UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?file=Partials%2f' + id); + UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?treeType=partialViews&file=Partials%2f' + id); } "); } diff --git a/src/Umbraco.Web/UI/Pages/BasePage.cs b/src/Umbraco.Web/UI/Pages/BasePage.cs index fd18b14e71..4fa198f8b6 100644 --- a/src/Umbraco.Web/UI/Pages/BasePage.cs +++ b/src/Umbraco.Web/UI/Pages/BasePage.cs @@ -54,6 +54,18 @@ namespace Umbraco.Web.UI.Pages get { return _url ?? (_url = new UrlHelper(new RequestContext(new HttpContextWrapper(Context), new RouteData()))); } } + private HtmlHelper _html; + /// + /// Returns a HtmlHelper + /// + /// + /// This html helper is created with an empty context and page so it may not have all of the functionality expected. + /// + public HtmlHelper Html + { + get { return _html ?? (_html = new HtmlHelper(new ViewContext(), new ViewPage())); } + } + /// /// Returns the current ApplicationContext /// diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ece5c2a441..9c085ff540 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -126,6 +126,10 @@ False ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + + False + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll @@ -556,6 +560,9 @@ ASPXCodeBehind + + ASPXCodeBehind + ASPXCodeBehind @@ -1185,13 +1192,6 @@ SubmitPackage.aspx - - editPython.aspx - ASPXCodeBehind - - - editPython.aspx - getXsltStatus.asmx Component @@ -1877,9 +1877,6 @@ - - ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 4dd8beaca5..c0a8e366d2 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web } // do not process if client-side request - if (IsClientSideRequest(httpContext.Request.Url)) + if (httpContext.Request.Url.IsClientSideRequest()) return; //write the trace output for diagnostics at the end of the request @@ -66,7 +66,7 @@ namespace Umbraco.Web void ProcessRequest(HttpContextBase httpContext) { // do not process if client-side request - if (IsClientSideRequest(httpContext.Request.Url)) + if (httpContext.Request.Url.IsClientSideRequest()) return; if (UmbracoContext.Current == null) @@ -187,19 +187,6 @@ namespace Umbraco.Web #region Route helper methods - /// - /// This is a performance tweak to check if this is a .css, .js or .ico, .jpg, .jpeg, .png, .gif file request since - /// .Net will pass these requests through to the module when in integrated mode. - /// We want to ignore all of these requests immediately. - /// - /// - /// - internal bool IsClientSideRequest(Uri url) - { - var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif" }; - return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x)); - } - /// /// Checks the current request and ensures that it is routable based on the structure of the request and URI /// diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 719f2861ad..5f376a6e88 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -5,12 +5,14 @@ using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; +using StackExchange.Profiling.MVCHelpers; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Dynamics; using Umbraco.Core.Logging; using Umbraco.Core.ObjectResolution; +using Umbraco.Core.Profiling; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Sync; using Umbraco.Web.Dictionary; @@ -71,13 +73,16 @@ namespace Umbraco.Web new MasterControllerFactory(FilteredControllerFactoriesResolver.Current)); //set the render view engine - ViewEngines.Engines.Add(new RenderViewEngine()); + ViewEngines.Engines.Add(new ProfilingViewEngine(new RenderViewEngine())); //set the plugin view engine - ViewEngines.Engines.Add(new PluginViewEngine()); + ViewEngines.Engines.Add(new ProfilingViewEngine(new PluginViewEngine())); //set model binder ModelBinders.Binders.Add(new KeyValuePair(typeof(RenderModel), new RenderModelBinder())); + //add the profiling action filter + GlobalFilters.Filters.Add(new ProfilingActionFilter()); + return this; } @@ -94,6 +99,17 @@ namespace Umbraco.Web UmbracoContext.EnsureContext(new HttpContextWrapper(UmbracoApplication.Context), ApplicationContext); } + /// + /// Ensure the current profiler is the web profiler + /// + protected override void InitializeProfilerResolver() + { + base.InitializeProfilerResolver(); + + //Set the profiler to be the web profiler + ProfilerResolver.Current.SetProfiler(new WebProfiler()); + } + /// /// Adds custom types to the ApplicationEventsResolver /// diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 8763102da7..547b8010a1 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -15,6 +15,7 @@ + diff --git a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs index c8c04813c5..e4d7c546d6 100644 --- a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs @@ -6,8 +6,10 @@ using System.Web.UI; using System.IO; using System.Xml; using System.Text.RegularExpressions; +using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Logging; +using Umbraco.Core.Profiling; using Umbraco.Web; using Umbraco.Web.Routing; using Umbraco.Core.Configuration; @@ -18,183 +20,196 @@ using umbraco.cms.businesslogic; namespace umbraco { - /// - /// The codebehind class for the main default.aspx page that does the webforms rendering in Umbraco - /// - /// - /// We would move this to the UI project but there is a public API property and some protected properties which people may be using so - /// we cannot move it. - /// - public class UmbracoDefault : Page - { - private page _upage; - private PublishedContentRequest _docRequest; - bool _validateRequest = true; + /// + /// The codebehind class for the main default.aspx page that does the webforms rendering in Umbraco + /// + /// + /// We would move this to the UI project but there is a public API property and some protected properties which people may be using so + /// we cannot move it. + /// + public class UmbracoDefault : Page + { + private page _upage; + private PublishedContentRequest _docRequest; + bool _validateRequest = true; - /// - /// To turn off request validation set this to false before the PageLoad event. This equivalent to the validateRequest page directive - /// and has nothing to do with "normal" validation controls. Default value is true. - /// - public bool ValidateRequest - { - get { return _validateRequest; } - set { _validateRequest = value; } - } + /// + /// To turn off request validation set this to false before the PageLoad event. This equivalent to the validateRequest page directive + /// and has nothing to do with "normal" validation controls. Default value is true. + /// + public bool ValidateRequest + { + get { return _validateRequest; } + set { _validateRequest = value; } + } - protected override void OnPreInit(EventArgs e) - { - base.OnPreInit(e); + protected override void OnPreInit(EventArgs e) + { + base.OnPreInit(e); + using (DisposableTimer.DebugDuration("PreInit")) + { - // handle the infamous umbDebugShowTrace, etc - Page.Trace.IsEnabled &= GlobalSettings.DebugMode && !String.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]); + // handle the infamous umbDebugShowTrace, etc + Page.Trace.IsEnabled &= GlobalSettings.DebugMode && string.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]) == false; - // get the document request and the page - _docRequest = UmbracoContext.Current.PublishedContentRequest; - _upage = _docRequest.UmbracoPage; + // get the document request and the page + _docRequest = UmbracoContext.Current.PublishedContentRequest; + _upage = _docRequest.UmbracoPage; - //we need to check this for backwards compatibility in case people still arent' using master pages - if (UmbracoSettings.UseAspNetMasterPages) - { - var args = new RequestInitEventArgs() - { - Page = _upage, - PageId = _upage.PageID, - Context = Context - }; - FireBeforeRequestInit(args); + //we need to check this for backwards compatibility in case people still arent' using master pages + if (UmbracoSettings.UseAspNetMasterPages) + { + var args = new RequestInitEventArgs() + { + Page = _upage, + PageId = _upage.PageID, + Context = Context + }; + FireBeforeRequestInit(args); - //if we are cancelling then return and don't proceed - if (args.Cancel) return; + //if we are cancelling then return and don't proceed + if (args.Cancel) return; - this.MasterPageFile = template.GetMasterPageName(_upage.Template); + this.MasterPageFile = template.GetMasterPageName(_upage.Template); - // reset the friendly path so it's used by forms, etc. - Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); + // reset the friendly path so it's used by forms, etc. + Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); - //fire the init finished event - FireAfterRequestInit(args); - } - - } + //fire the init finished event + FireAfterRequestInit(args); + } + } + } - protected override void OnInit(EventArgs e) - { - base.OnInit(e); + protected override void OnInit(EventArgs e) + { + using (DisposableTimer.DebugDuration("Init")) + { - //This is only here for legacy if people arent' using master pages... - //TODO: We need to test that this still works!! Or do we ?? - if (!UmbracoSettings.UseAspNetMasterPages) - { - var args = new RequestInitEventArgs() - { - Page = _upage, - PageId = _upage.PageID, - Context = Context - }; - FireBeforeRequestInit(args); + base.OnInit(e); - //if we are cancelling then return and don't proceed - if (args.Cancel) return; + //This is only here for legacy if people arent' using master pages... + //TODO: We need to test that this still works!! Or do we ?? + if (!UmbracoSettings.UseAspNetMasterPages) + { + var args = new RequestInitEventArgs() + { + Page = _upage, + PageId = _upage.PageID, + Context = Context + }; + FireBeforeRequestInit(args); - var pageHolder = new umbraco.layoutControls.umbracoPageHolder - { - ID = "umbPageHolder" - }; - Page.Controls.Add(pageHolder); - _upage.RenderPage(_upage.Template); - var umbPageHolder = (layoutControls.umbracoPageHolder)Page.FindControl("umbPageHolder"); - umbPageHolder.Populate(_upage); + //if we are cancelling then return and don't proceed + if (args.Cancel) return; - //fire the init finished event - FireAfterRequestInit(args); - } - } + var pageHolder = new umbraco.layoutControls.umbracoPageHolder + { + ID = "umbPageHolder" + }; + Page.Controls.Add(pageHolder); + _upage.RenderPage(_upage.Template); + var umbPageHolder = (layoutControls.umbracoPageHolder)Page.FindControl("umbPageHolder"); + umbPageHolder.Populate(_upage); - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); + //fire the init finished event + FireAfterRequestInit(args); + } + } + } - // do not validate when liveEditing because there may be a RTE with markup - var liveEditing = umbraco.presentation.UmbracoContext.Current.LiveEditingContext.Enabled; + protected override void OnLoad(EventArgs e) + { + using (DisposableTimer.DebugDuration("Load")) + { + base.OnLoad(e); - if (!liveEditing && ValidateRequest) - Request.ValidateInput(); - } + // do not validate when liveEditing because there may be a RTE with markup + var liveEditing = umbraco.presentation.UmbracoContext.Current.LiveEditingContext.Enabled; - protected override void Render(HtmlTextWriter writer) - { - // do the original rendering - TextWriter sw = new StringWriter(); - base.Render(new HtmlTextWriter(sw)); - string text = sw.ToString(); + if (!liveEditing && ValidateRequest) + Request.ValidateInput(); + } + } - // filter / parse internal links - although this should be done elsewhere! - text = TemplateUtilities.ParseInternalLinks(text); + protected override void Render(HtmlTextWriter writer) + { + using (DisposableTimer.DebugDuration("Render")) + { - // filter / add preview banner - if (UmbracoContext.Current.InPreviewMode) - { - LogHelper.Debug("Umbraco is running in preview mode.", true); + // do the original rendering + TextWriter sw = new StringWriter(); + base.Render(new HtmlTextWriter(sw)); + string text = sw.ToString(); - if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value - { - int pos = text.ToLower().IndexOf(""); - if (pos > -1) - { - string htmlBadge = - String.Format(UmbracoSettings.PreviewBadge, - IOHelper.ResolveUrl(SystemDirectories.Umbraco), - IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), - Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); + // filter / parse internal links - although this should be done elsewhere! + text = TemplateUtilities.ParseInternalLinks(text); - text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); - } - } - } + // filter / add preview banner + if (UmbracoContext.Current.InPreviewMode) + { + LogHelper.Debug("Umbraco is running in preview mode.", true); - // render - writer.Write(text); - } + if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value + { + int pos = text.ToLower().IndexOf(""); + if (pos > -1) + { + string htmlBadge = + String.Format(UmbracoSettings.PreviewBadge, + IOHelper.ResolveUrl(SystemDirectories.Umbraco), + IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), + Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); - /// - /// The preinit event handler - /// - public delegate void RequestInitEventHandler(object sender, RequestInitEventArgs e); - /// - /// occurs before the umbraco page is initialized for rendering. - /// - public static event RequestInitEventHandler BeforeRequestInit; - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected internal virtual void FireBeforeRequestInit(RequestInitEventArgs e) - { - if (BeforeRequestInit != null) - BeforeRequestInit(this, e); - } + text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); + } + } + } - /// - /// Occurs when [after save]. - /// - public static event RequestInitEventHandler AfterRequestInit; - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void FireAfterRequestInit(RequestInitEventArgs e) - { - if (AfterRequestInit != null) - AfterRequestInit(this, e); + // render + writer.Write(text); + } + } - } - } + /// + /// The preinit event handler + /// + public delegate void RequestInitEventHandler(object sender, RequestInitEventArgs e); + /// + /// occurs before the umbraco page is initialized for rendering. + /// + public static event RequestInitEventHandler BeforeRequestInit; + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected internal virtual void FireBeforeRequestInit(RequestInitEventArgs e) + { + if (BeforeRequestInit != null) + BeforeRequestInit(this, e); + } - public class RequestInitEventArgs : System.ComponentModel.CancelEventArgs - { - public page Page { get; internal set; } - public HttpContext Context { get; internal set; } - public string Url { get; internal set; } - public int PageId { get; internal set; } - } + /// + /// Occurs when [after save]. + /// + public static event RequestInitEventHandler AfterRequestInit; + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected virtual void FireAfterRequestInit(RequestInitEventArgs e) + { + if (AfterRequestInit != null) + AfterRequestInit(this, e); + + } + } + + public class RequestInitEventArgs : System.ComponentModel.CancelEventArgs + { + public page Page { get; internal set; } + public HttpContext Context { get; internal set; } + public string Url { get; internal set; } + public int PageId { get; internal set; } + } } diff --git a/src/Umbraco.Web/umbraco.presentation/helper.cs b/src/Umbraco.Web/umbraco.presentation/helper.cs index 2f0f93a8cd..da93812949 100644 --- a/src/Umbraco.Web/umbraco.presentation/helper.cs +++ b/src/Umbraco.Web/umbraco.presentation/helper.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using System.Web; using Umbraco.Core; using Umbraco.Core.CodeAnnotations; +using Umbraco.Core.Profiling; using umbraco.BusinessLogic; using System.Xml; using umbraco.presentation; diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index fe6c8faea7..1cf5e8ae31 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -2,196 +2,204 @@ using System; using System.Collections; using System.Web; using System.Xml; +using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Profiling; namespace umbraco { - /// - /// - /// - public class item - { - private String _fieldContent = ""; - private readonly String _fieldName; + /// + /// + /// + public class item + { + private String _fieldContent = ""; + private readonly String _fieldName; - public String FieldContent - { - get { return _fieldContent; } - } + public String FieldContent + { + get { return _fieldContent; } + } - public item(string itemValue, IDictionary attributes) - { - _fieldContent = itemValue; - ParseItem(attributes); - } + public item(string itemValue, IDictionary attributes) + { + _fieldContent = itemValue; + ParseItem(attributes); + } - /// - /// Creates a new Legacy item - /// - /// - /// + /// + /// Creates a new Legacy item + /// + /// + /// public item(IDictionary elements, IDictionary attributes) - : this(null, elements, attributes) - { - } + : this(null, elements, attributes) + { + } - /// - /// Creates an Item with a publishedContent item in order to properly recurse and return the value. - /// - /// - /// - /// - /// - /// THIS ENTIRE CLASS WILL BECOME LEGACY, THE FIELD RENDERING NEEDS TO BE REPLACES SO THAT IS WHY THIS - /// CTOR IS INTERNAL. - /// - internal item(IPublishedContent publishedContent, IDictionary elements, IDictionary attributes) - { - _fieldName = helper.FindAttribute(attributes, "field"); + /// + /// Creates an Item with a publishedContent item in order to properly recurse and return the value. + /// + /// + /// + /// + /// + /// THIS ENTIRE CLASS WILL BECOME LEGACY, THE FIELD RENDERING NEEDS TO BE REPLACES SO THAT IS WHY THIS + /// CTOR IS INTERNAL. + /// + internal item(IPublishedContent publishedContent, IDictionary elements, IDictionary attributes) + { + _fieldName = helper.FindAttribute(attributes, "field"); - if (_fieldName.StartsWith("#")) - { - _fieldContent = library.GetDictionaryItem(_fieldName.Substring(1, _fieldName.Length - 1)); - } - else - { - // Loop through XML children we need to find the fields recursive - if (helper.FindAttribute(attributes, "recursive") == "true") - { - if (publishedContent == null) - { - var recursiveVal = GetRecursiveValueLegacy(elements); - _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; - } - else - { - var recursiveVal = publishedContent.GetRecursiveValue(_fieldName); - _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; - } - } - else - { - if (elements[_fieldName] != null && !string.IsNullOrEmpty(elements[_fieldName].ToString())) - { - _fieldContent = elements[_fieldName].ToString().Trim(); - } - else if (!string.IsNullOrEmpty(helper.FindAttribute(attributes, "useIfEmpty"))) - { - if (elements[helper.FindAttribute(attributes, "useIfEmpty")] != null && !string.IsNullOrEmpty(elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString())) - { - _fieldContent = elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString().Trim(); - } - } + if (_fieldName.StartsWith("#")) + { + _fieldContent = library.GetDictionaryItem(_fieldName.Substring(1, _fieldName.Length - 1)); + } + else + { + // Loop through XML children we need to find the fields recursive + if (helper.FindAttribute(attributes, "recursive") == "true") + { + if (publishedContent == null) + { + var recursiveVal = GetRecursiveValueLegacy(elements); + _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; + } + else + { + var recursiveVal = publishedContent.GetRecursiveValue(_fieldName); + _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; + } + } + else + { + if (elements[_fieldName] != null && !string.IsNullOrEmpty(elements[_fieldName].ToString())) + { + _fieldContent = elements[_fieldName].ToString().Trim(); + } + else if (!string.IsNullOrEmpty(helper.FindAttribute(attributes, "useIfEmpty"))) + { + if (elements[helper.FindAttribute(attributes, "useIfEmpty")] != null && !string.IsNullOrEmpty(elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString())) + { + _fieldContent = elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString().Trim(); + } + } - } - } + } + } - ParseItem(attributes); - } + ParseItem(attributes); + } - /// - /// Returns the recursive value using a legacy strategy of looking at the xml cache and the splitPath in the elements collection - /// - /// - /// - private string GetRecursiveValueLegacy(IDictionary elements) - { - var content = ""; + /// + /// Returns the recursive value using a legacy strategy of looking at the xml cache and the splitPath in the elements collection + /// + /// + /// + private string GetRecursiveValueLegacy(IDictionary elements) + { + using (DisposableTimer.DebugDuration("Checking recusively")) + { + var content = ""; - var umbracoXml = presentation.UmbracoContext.Current.GetXml(); + var umbracoXml = presentation.UmbracoContext.Current.GetXml(); - var splitpath = (String[])elements["splitpath"]; - for (int i = 0; i < splitpath.Length - 1; i++) - { - XmlNode element = umbracoXml.GetElementById(splitpath[splitpath.Length - i - 1]); + var splitpath = (String[])elements["splitpath"]; + for (int i = 0; i < splitpath.Length - 1; i++) + { + XmlNode element = umbracoXml.GetElementById(splitpath[splitpath.Length - i - 1]); - if (element == null) - continue; + if (element == null) + continue; - var xpath = UmbracoSettings.UseLegacyXmlSchema ? "./data [@alias = '{0}']" : "./{0}"; - var currentNode = element.SelectSingleNode(string.Format(xpath, _fieldName)); + var xpath = UmbracoSettings.UseLegacyXmlSchema ? "./data [@alias = '{0}']" : "./{0}"; + var currentNode = element.SelectSingleNode(string.Format(xpath, _fieldName)); - //continue if all is null - if (currentNode == null || currentNode.FirstChild == null || string.IsNullOrEmpty(currentNode.FirstChild.Value) || string.IsNullOrEmpty(currentNode.FirstChild.Value.Trim())) - continue; + //continue if all is null + if (currentNode == null || currentNode.FirstChild == null || string.IsNullOrEmpty(currentNode.FirstChild.Value) || string.IsNullOrEmpty(currentNode.FirstChild.Value.Trim())) + continue; - HttpContext.Current.Trace.Write("item.recursive", "Item loaded from " + splitpath[splitpath.Length - i - 1]); - content = currentNode.FirstChild.Value; - break; - } + HttpContext.Current.Trace.Write("item.recursive", "Item loaded from " + splitpath[splitpath.Length - i - 1]); + content = currentNode.FirstChild.Value; + break; + } - return content; - } + return content; + } + } private void ParseItem(IDictionary attributes) - { - HttpContext.Current.Trace.Write("item", "Start parsing '" + _fieldName + "'"); - if(helper.FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") - _fieldContent = helper.FindAttribute(attributes, "textIfEmpty"); + { + using (DisposableTimer.DebugDuration("Start parsing " + _fieldName)) + { + HttpContext.Current.Trace.Write("item", "Start parsing '" + _fieldName + "'"); + if (helper.FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") + _fieldContent = helper.FindAttribute(attributes, "textIfEmpty"); - _fieldContent = _fieldContent.Trim(); + _fieldContent = _fieldContent.Trim(); - // DATE FORMATTING FUNCTIONS - if(helper.FindAttribute(attributes, "formatAsDateWithTime") == "true") - { - if(_fieldContent == "") - _fieldContent = DateTime.Now.ToString(); - _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString() + - helper.FindAttribute(attributes, "formatAsDateWithTimeSeparator") + - Convert.ToDateTime(_fieldContent).ToShortTimeString(); - } - else if(helper.FindAttribute(attributes, "formatAsDate") == "true") - { - if(_fieldContent == "") - _fieldContent = DateTime.Now.ToString(); - _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString(); - } + // DATE FORMATTING FUNCTIONS + if (helper.FindAttribute(attributes, "formatAsDateWithTime") == "true") + { + if (_fieldContent == "") + _fieldContent = DateTime.Now.ToString(); + _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString() + + helper.FindAttribute(attributes, "formatAsDateWithTimeSeparator") + + Convert.ToDateTime(_fieldContent).ToShortTimeString(); + } + else if (helper.FindAttribute(attributes, "formatAsDate") == "true") + { + if (_fieldContent == "") + _fieldContent = DateTime.Now.ToString(); + _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString(); + } - // TODO: Needs revision to check if parameter-tags has attributes - if(helper.FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) - { - _fieldContent = _fieldContent.Trim(); - string fieldContentLower = _fieldContent.ToLower(); + // TODO: Needs revision to check if parameter-tags has attributes + if (helper.FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) + { + _fieldContent = _fieldContent.Trim(); + string fieldContentLower = _fieldContent.ToLower(); // the field starts with an opening p tag - if (fieldContentLower.Substring(0, 3) == "

" - // it ends with a closing p tag - && fieldContentLower.Substring(_fieldContent.Length - 4, 4) == "

" - // it doesn't contain multiple p-tags - && fieldContentLower.IndexOf("

", 1) < 0) - { - _fieldContent = _fieldContent.Substring(3, _fieldContent.Length - 7); + if (fieldContentLower.Substring(0, 3) == "

" + // it ends with a closing p tag + && fieldContentLower.Substring(_fieldContent.Length - 4, 4) == "

" + // it doesn't contain multiple p-tags + && fieldContentLower.IndexOf("

", 1) < 0) + { + _fieldContent = _fieldContent.Substring(3, _fieldContent.Length - 7); + } } - } - // CASING - if (helper.FindAttribute(attributes, "case") == "lower") - _fieldContent = _fieldContent.ToLower(); - else if (helper.FindAttribute(attributes, "case") == "upper") - _fieldContent = _fieldContent.ToUpper(); - else if (helper.FindAttribute(attributes, "case") == "title") - _fieldContent = _fieldContent.ConvertCase(StringAliasCaseType.PascalCase); + // CASING + if (helper.FindAttribute(attributes, "case") == "lower") + _fieldContent = _fieldContent.ToLower(); + else if (helper.FindAttribute(attributes, "case") == "upper") + _fieldContent = _fieldContent.ToUpper(); + else if (helper.FindAttribute(attributes, "case") == "title") + _fieldContent = _fieldContent.ConvertCase(StringAliasCaseType.PascalCase); - // OTHER FORMATTING FUNCTIONS - // If we use masterpages, this is moved to the ItemRenderer to add support for before/after in inline XSLT - if (!UmbracoSettings.UseAspNetMasterPages) - { - if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextBefore") != "") - _fieldContent = HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextBefore")) + - _fieldContent; - if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextAfter") != "") - _fieldContent += HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextAfter")); + // OTHER FORMATTING FUNCTIONS + // If we use masterpages, this is moved to the ItemRenderer to add support for before/after in inline XSLT + if (!UmbracoSettings.UseAspNetMasterPages) + { + if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextBefore") != "") + _fieldContent = HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextBefore")) + + _fieldContent; + if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextAfter") != "") + _fieldContent += HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextAfter")); + } + if (helper.FindAttribute(attributes, "urlEncode") == "true") + _fieldContent = HttpUtility.UrlEncode(_fieldContent); + if (helper.FindAttribute(attributes, "htmlEncode") == "true") + _fieldContent = HttpUtility.HtmlEncode(_fieldContent); + if (helper.FindAttribute(attributes, "convertLineBreaks") == "true") + _fieldContent = _fieldContent.Replace("\n", "
\n"); + + HttpContext.Current.Trace.Write("item", "Done parsing '" + _fieldName + "'"); } - if(helper.FindAttribute(attributes, "urlEncode") == "true") - _fieldContent = HttpUtility.UrlEncode(_fieldContent); - if (helper.FindAttribute(attributes, "htmlEncode") == "true") - _fieldContent = HttpUtility.HtmlEncode(_fieldContent); - if(helper.FindAttribute(attributes, "convertLineBreaks") == "true") - _fieldContent = _fieldContent.Replace("\n", "
\n"); - - HttpContext.Current.Trace.Write("item", "Done parsing '" + _fieldName + "'"); - } - } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index dc0fc04f8b..10fa66fd65 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -17,11 +17,13 @@ using System.Web.UI.WebControls; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; +using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Profiling; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.Macros; @@ -230,203 +232,256 @@ namespace umbraco public Control renderMacro(Hashtable pageElements, int pageId) { - TraceInfo("renderMacro", - string.Format("Rendering started (macro: {0}, type: {1}, cacheRate: {2})", - Name, MacroType, Model.CacheDuration)); + var macroInfo = (Model.MacroType == MacroTypes.Script && Model.Name.IsNullOrWhiteSpace()) + ? string.Format("Render Inline Macro, Cache: {0})", Model.CacheDuration) + : string.Format("Render Macro: {0}, type: {1}, cache: {2})", Name, Model.MacroType, Model.CacheDuration); - StateHelper.SetContextValue(MacrosAddedKey, StateHelper.GetContextValue(MacrosAddedKey) + 1); - - // zb-00037 #29875 : parse attributes here (and before anything else) - foreach (MacroPropertyModel prop in Model.Properties) - prop.Value = helper.parseAttribute(pageElements, prop.Value); - - Model.CacheIdentifier = GetCacheIdentifier(Model, pageElements, pageId); - - string macroHtml; - Control macroControl; - //get the macro from cache if it is there - GetMacroFromCache(out macroHtml, out macroControl); - - // FlorisRobbemont: Empty macroHtml (not null, but "") doesn't mean a re-render is necessary - if (macroHtml == null && macroControl == null) + using (DisposableTimer.DebugDuration(macroInfo)) { - var renderFailed = false; - var macroType = Model.MacroType != MacroTypes.Unknown - ? (int)Model.MacroType - : MacroType; + TraceInfo("renderMacro", macroInfo, excludeProfiling:true); - switch (macroType) + StateHelper.SetContextValue(MacrosAddedKey, StateHelper.GetContextValue(MacrosAddedKey) + 1); + + // zb-00037 #29875 : parse attributes here (and before anything else) + foreach (MacroPropertyModel prop in Model.Properties) + prop.Value = helper.parseAttribute(pageElements, prop.Value); + + Model.CacheIdentifier = GetCacheIdentifier(Model, pageElements, pageId); + + string macroHtml; + Control macroControl; + //get the macro from cache if it is there + GetMacroFromCache(out macroHtml, out macroControl); + + // FlorisRobbemont: Empty macroHtml (not null, but "") doesn't mean a re-render is necessary + if (macroHtml == null && macroControl == null) { - case (int)MacroTypes.PartialView: + var renderFailed = false; + var macroType = Model.MacroType != MacroTypes.Unknown + ? (int) Model.MacroType + : MacroType; - //error handler for partial views, is an action because we need to re-use it twice below - Func handleError = e => - { - LogHelper.WarnWithException("Error loading Partial View (file: " + ScriptFile + ")", true, e); - // Invoke any error handlers for this macro - var macroErrorEventArgs = new MacroErrorEventArgs { Name = Model.Name, Alias = Model.Alias, ItemKey = Model.ScriptName, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour }; - return GetControlForErrorBehavior("Error loading Partial View script (file: " + ScriptFile + ")", macroErrorEventArgs); - }; + switch (macroType) + { + case (int) MacroTypes.PartialView: - TraceInfo("umbracoMacro", "Partial View added (" + Model.TypeName + ")"); - try - { - var result = LoadPartialViewMacro(Model); - macroControl = new LiteralControl(result.Result); - if (result.ResultException != null) - { - renderFailed = true; - Exceptions.Add(result.ResultException); - macroControl = handleError(result.ResultException); - //if it is null, then we are supposed to throw the exception - if (macroControl == null) + //error handler for partial views, is an action because we need to re-use it twice below + Func handleError = e => { - throw result.ResultException; - } - } - } - catch (Exception e) - { - renderFailed = true; - Exceptions.Add(e); - macroControl = handleError(e); - //if it is null, then we are supposed to throw the (original) exception - // see: http://issues.umbraco.org/issue/U4-497 at the end - if (macroControl == null) - { - throw; - } - } + LogHelper.WarnWithException("Error loading Partial View (file: " + ScriptFile + ")", true, e); + // Invoke any error handlers for this macro + var macroErrorEventArgs = + new MacroErrorEventArgs + { + Name = Model.Name, + Alias = Model.Alias, + ItemKey = Model.ScriptName, + Exception = e, + Behaviour = UmbracoSettings.MacroErrorBehaviour + }; + return GetControlForErrorBehavior("Error loading Partial View script (file: " + ScriptFile + ")", macroErrorEventArgs); + }; - break; - case (int)MacroTypes.UserControl: - try - { - TraceInfo("umbracoMacro","Usercontrol added (" + Model.TypeName + ")"); + using (DisposableTimer.DebugDuration("Executing Partial View: " + Model.TypeName)) + { + TraceInfo("umbracoMacro", "Partial View added (" + Model.TypeName + ")", excludeProfiling:true); + try + { + var result = LoadPartialViewMacro(Model); + macroControl = new LiteralControl(result.Result); + if (result.ResultException != null) + { + renderFailed = true; + Exceptions.Add(result.ResultException); + macroControl = handleError(result.ResultException); + //if it is null, then we are supposed to throw the exception + if (macroControl == null) + { + throw result.ResultException; + } + } + } + catch (Exception e) + { + renderFailed = true; + Exceptions.Add(e); + macroControl = handleError(e); + //if it is null, then we are supposed to throw the (original) exception + // see: http://issues.umbraco.org/issue/U4-497 at the end + if (macroControl == null) + { + throw; + } + } + + break; + } + case (int) MacroTypes.UserControl: + + using (DisposableTimer.DebugDuration("Executing UserControl: " + Model.TypeName)) + { + try + { + TraceInfo("umbracoMacro", "Usercontrol added (" + Model.TypeName + ")", excludeProfiling:true); + + // Add tilde for v4 defined macros + if (string.IsNullOrEmpty(Model.TypeName) == false && + Model.TypeName.StartsWith("~") == false) + Model.TypeName = "~/" + Model.TypeName; + + macroControl = loadUserControl(ScriptType, Model, pageElements); + break; + } + catch (Exception e) + { + renderFailed = true; + Exceptions.Add(e); + LogHelper.WarnWithException("Error loading userControl (" + Model.TypeName + ")", true, e); + + // Invoke any error handlers for this macro + var macroErrorEventArgs = new MacroErrorEventArgs + { + Name = Model.Name, + Alias = Model.Alias, + ItemKey = Model.TypeName, + Exception = e, + Behaviour = UmbracoSettings.MacroErrorBehaviour + }; + + macroControl = GetControlForErrorBehavior("Error loading userControl '" + Model.TypeName + "'", macroErrorEventArgs); + //if it is null, then we are supposed to throw the (original) exception + // see: http://issues.umbraco.org/issue/U4-497 at the end + if (macroControl == null) + { + throw; + } + + break; + } + } - // Add tilde for v4 defined macros - if (string.IsNullOrEmpty(Model.TypeName) == false && Model.TypeName.StartsWith("~") == false) - Model.TypeName = "~/" + Model.TypeName; + case (int) MacroTypes.CustomControl: - macroControl = loadUserControl(ScriptType, Model, pageElements); - break; - } - catch (Exception e) - { - renderFailed = true; - Exceptions.Add(e); - LogHelper.WarnWithException("Error loading userControl (" + Model.TypeName + ")", true, e); - - // Invoke any error handlers for this macro - var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, ItemKey = Model.TypeName, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; - - macroControl = GetControlForErrorBehavior("Error loading userControl '" + Model.TypeName + "'", macroErrorEventArgs); - //if it is null, then we are supposed to throw the (original) exception - // see: http://issues.umbraco.org/issue/U4-497 at the end - if (macroControl == null) + using (DisposableTimer.DebugDuration("Executing CustomControl: " + Model.TypeName + "." + Model.TypeAssembly)) { - throw; - } - - break; - } - case (int)MacroTypes.CustomControl: - try - { - TraceInfo("umbracoMacro", "Custom control added (" + Model.TypeName + ")"); - TraceInfo("umbracoMacro", "ScriptAssembly (" + Model.TypeAssembly + ")"); - macroControl = loadControl(Model.TypeAssembly, ScriptType, Model, pageElements); - break; - } - catch (Exception e) - { - renderFailed = true; - Exceptions.Add(e); - - LogHelper.WarnWithException("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'", true, e); - - // Invoke any error handlers for this macro - var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, ItemKey = Model.TypeAssembly, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; - - macroControl = GetControlForErrorBehavior("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'", macroErrorEventArgs); - //if it is null, then we are supposed to throw the (original) exception - // see: http://issues.umbraco.org/issue/U4-497 at the end - if (macroControl == null) - { - throw; - } - - break; - } - case (int)MacroTypes.XSLT: - macroControl = LoadMacroXslt(this, Model, pageElements, true); - break; - case (int)MacroTypes.Script: - - //error handler for partial views, is an action because we need to re-use it twice below - Func handleMacroScriptError = e => - { - LogHelper.WarnWithException("Error loading MacroEngine script (file: " + ScriptFile + ", Type: '" + Model.TypeName + "'", true, e); - - // Invoke any error handlers for this macro - var macroErrorEventArgs = new MacroErrorEventArgs { Name = Model.Name, Alias = Model.Alias, ItemKey = ScriptFile, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour }; - - return GetControlForErrorBehavior("Error loading MacroEngine script (file: " + ScriptFile + ")", macroErrorEventArgs); - }; - - try - { - TraceInfo("umbracoMacro", "MacroEngine script added (" + ScriptFile + ")"); - ScriptingMacroResult result = loadMacroScript(Model); - macroControl = new LiteralControl(result.Result); - if (result.ResultException != null) - { - renderFailed = true; - Exceptions.Add(result.ResultException); - macroControl = handleMacroScriptError(result.ResultException); - //if it is null, then we are supposed to throw the exception - if (macroControl == null) + try { - throw result.ResultException; + TraceInfo("umbracoMacro", "Custom control added (" + Model.TypeName + "), ScriptAssembly: " + Model.TypeAssembly, excludeProfiling: true); + macroControl = loadControl(Model.TypeAssembly, ScriptType, Model, pageElements); + break; + } + catch (Exception e) + { + renderFailed = true; + Exceptions.Add(e); + + LogHelper.WarnWithException( + "Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + + Model.TypeName + "'", true, e); + + // Invoke any error handlers for this macro + var macroErrorEventArgs = new MacroErrorEventArgs + { + Name = Model.Name, + Alias = Model.Alias, + ItemKey = Model.TypeAssembly, + Exception = e, + Behaviour = UmbracoSettings.MacroErrorBehaviour + }; + + macroControl = GetControlForErrorBehavior("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'", macroErrorEventArgs); + //if it is null, then we are supposed to throw the (original) exception + // see: http://issues.umbraco.org/issue/U4-497 at the end + if (macroControl == null) + { + throw; + } + + break; } } - break; - } - catch (Exception e) - { - renderFailed = true; - Exceptions.Add(e); + case (int) MacroTypes.XSLT: + macroControl = LoadMacroXslt(this, Model, pageElements, true); + break; + case (int) MacroTypes.Script: - macroControl = handleMacroScriptError(e); - //if it is null, then we are supposed to throw the (original) exception - // see: http://issues.umbraco.org/issue/U4-497 at the end - if (macroControl == null) + //error handler for partial views, is an action because we need to re-use it twice below + Func handleMacroScriptError = e => + { + LogHelper.WarnWithException("Error loading MacroEngine script (file: " + ScriptFile + ", Type: '" + Model.TypeName + "'", true, e); + + // Invoke any error handlers for this macro + var macroErrorEventArgs = + new MacroErrorEventArgs + { + Name = Model.Name, + Alias = Model.Alias, + ItemKey = ScriptFile, + Exception = e, + Behaviour = UmbracoSettings.MacroErrorBehaviour + }; + + return GetControlForErrorBehavior("Error loading MacroEngine script (file: " + ScriptFile + ")", macroErrorEventArgs); + }; + + using (DisposableTimer.DebugDuration("Executing MacroEngineScript: " + ScriptFile)) { - throw; + try + { + TraceInfo("umbracoMacro", "MacroEngine script added (" + ScriptFile + ")", excludeProfiling: true); + ScriptingMacroResult result = loadMacroScript(Model); + macroControl = new LiteralControl(result.Result); + if (result.ResultException != null) + { + renderFailed = true; + Exceptions.Add(result.ResultException); + macroControl = handleMacroScriptError(result.ResultException); + //if it is null, then we are supposed to throw the exception + if (macroControl == null) + { + throw result.ResultException; + } + } + break; + } + catch (Exception e) + { + renderFailed = true; + Exceptions.Add(e); + + macroControl = handleMacroScriptError(e); + //if it is null, then we are supposed to throw the (original) exception + // see: http://issues.umbraco.org/issue/U4-497 at the end + if (macroControl == null) + { + throw; + } + break; + } + } + case (int) MacroTypes.Unknown: + default: + if (GlobalSettings.DebugMode) + { + macroControl = new LiteralControl("<Macro: " + Name + " (" + ScriptAssembly + "," + ScriptType + ")>"); } - break; - } - case (int)MacroTypes.Unknown: - default: - if (GlobalSettings.DebugMode) - macroControl = new LiteralControl("<Macro: " + Name + " (" + ScriptAssembly + "," + ScriptType + ")>"); - break; - } + } - //add to cache if render is successful - if (!renderFailed) + //add to cache if render is successful + if (renderFailed == false) + { + macroControl = AddMacroResultToCache(macroControl); + } + + } + else if (macroControl == null) { - macroControl = AddMacroResultToCache(macroControl); + macroControl = new LiteralControl(macroHtml); } + return macroControl; } - else if (macroControl == null) - { - macroControl = new LiteralControl(macroHtml); - } - - return macroControl; } ///

@@ -446,57 +501,63 @@ namespace umbraco { string dateAddedCacheKey; - // NH: Scripts and XSLT can be generated as strings, but not controls as page events wouldn't be hit (such as Page_Load, etc) - if (CacheMacroAsString(Model)) + using (DisposableTimer.DebugDuration("Saving MacroContent To Cache: " + Model.CacheIdentifier)) { - var outputCacheString = ""; - using (var sw = new StringWriter()) + // NH: Scripts and XSLT can be generated as strings, but not controls as page events wouldn't be hit (such as Page_Load, etc) + if (CacheMacroAsString(Model)) { - var hw = new HtmlTextWriter(sw); - macroControl.RenderControl(hw); + var outputCacheString = ""; - outputCacheString = sw.ToString(); + using (var sw = new StringWriter()) + { + var hw = new HtmlTextWriter(sw); + macroControl.RenderControl(hw); + + outputCacheString = sw.ToString(); + } + + //insert the cache string result + ApplicationContext.Current.ApplicationCache.InsertCacheItem( + CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier, + CacheItemPriority.NotRemovable, + new TimeSpan(0, 0, Model.CacheDuration), + () => outputCacheString); + + dateAddedCacheKey = CacheKeys.MacroHtmlDateAddedCacheKey + Model.CacheIdentifier; + + // zb-00003 #29470 : replace by text if not already text + // otherwise it is rendered twice + if (!(macroControl is LiteralControl)) + macroControl = new LiteralControl(outputCacheString); + + TraceInfo("renderMacro", + string.Format("Macro Content saved to cache '{0}'.", Model.CacheIdentifier)); + } + else + { + //insert the cache control result + ApplicationContext.Current.ApplicationCache.InsertCacheItem( + CacheKeys.MacroControlCacheKey + Model.CacheIdentifier, + CacheItemPriority.NotRemovable, + new TimeSpan(0, 0, Model.CacheDuration), + () => new MacroCacheContent(macroControl, macroControl.ID)); + + dateAddedCacheKey = CacheKeys.MacroControlDateAddedCacheKey + Model.CacheIdentifier; + + TraceInfo("renderMacro", + string.Format("Macro Control saved to cache '{0}'.", Model.CacheIdentifier)); } - //insert the cache string result + //insert the date inserted (so we can check file modification date) ApplicationContext.Current.ApplicationCache.InsertCacheItem( - CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier, + dateAddedCacheKey, CacheItemPriority.NotRemovable, new TimeSpan(0, 0, Model.CacheDuration), - () => outputCacheString); - - dateAddedCacheKey = CacheKeys.MacroHtmlDateAddedCacheKey + Model.CacheIdentifier; - - // zb-00003 #29470 : replace by text if not already text - // otherwise it is rendered twice - if (!(macroControl is LiteralControl)) - macroControl = new LiteralControl(outputCacheString); - - TraceInfo("renderMacro", - string.Format("Macro Content saved to cache '{0}'.", Model.CacheIdentifier)); - } - else - { - //insert the cache control result - ApplicationContext.Current.ApplicationCache.InsertCacheItem( - CacheKeys.MacroControlCacheKey + Model.CacheIdentifier, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => new MacroCacheContent(macroControl, macroControl.ID)); - - dateAddedCacheKey = CacheKeys.MacroControlDateAddedCacheKey + Model.CacheIdentifier; + () => DateTime.Now); - TraceInfo("renderMacro", - string.Format("Macro Control saved to cache '{0}'.", Model.CacheIdentifier)); } - - //insert the date inserted (so we can check file modification date) - ApplicationContext.Current.ApplicationCache.InsertCacheItem( - dateAddedCacheKey, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => DateTime.Now); + } } } @@ -519,7 +580,7 @@ namespace umbraco macroHtml = null; macroControl = null; - if (!UmbracoContext.Current.InPreviewMode && Model.CacheDuration > 0) + if (UmbracoContext.Current.InPreviewMode == false && Model.CacheDuration > 0) { var macroFile = GetMacroFile(Model); var fileInfo = new FileInfo(HttpContext.Current.Server.MapPath(macroFile)); @@ -764,7 +825,13 @@ namespace umbraco // will pick XmlDocument or Navigator mode depending on the capabilities of the published caches internal Control LoadMacroXslt(macro macro, MacroModel model, Hashtable pageElements, bool throwError) { - if (XsltFile.Trim() != string.Empty) + if (XsltFile.Trim() == string.Empty) + { + TraceWarn("macro", "Xslt is empty"); + return new LiteralControl(string.Empty); + } + + using (DisposableTimer.DebugDuration("Executing XSLT: " + XsltFile)) { XmlDocument macroXml = null; @@ -793,37 +860,31 @@ namespace umbraco { var xsltFile = getXslt(XsltFile); - try + using (DisposableTimer.DebugDuration("Performing transformation")) { - var transformed = GetXsltTransformResult(macroXml, xsltFile); - var result = CreateControlsFromText(transformed); - - TraceInfo("umbracoMacro", "After performing transformation"); - - return result; - } - catch (Exception e) - { - Exceptions.Add(e); - LogHelper.WarnWithException("Error parsing XSLT file", e); - // inner exception code by Daniel Lindstr?m from SBBS.se - Exception ie = e; - while (ie != null) + try { - TraceWarn("umbracoMacro InnerException", ie.Message, ie); - ie = ie.InnerException; - } + var transformed = GetXsltTransformResult(macroXml, xsltFile); + var result = CreateControlsFromText(transformed); - var macroErrorEventArgs = new MacroErrorEventArgs { Name = Model.Name, Alias = Model.Alias, ItemKey = Model.Xslt, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour }; - var macroControl = GetControlForErrorBehavior("Error parsing XSLT file: \\xslt\\" + XsltFile, macroErrorEventArgs); - //if it is null, then we are supposed to throw the (original) exception - // see: http://issues.umbraco.org/issue/U4-497 at the end - if (macroControl == null && throwError) - { - throw; + return result; } - return macroControl; - } + catch (Exception e) + { + Exceptions.Add(e); + LogHelper.WarnWithException("Error parsing XSLT file", e); + + var macroErrorEventArgs = new MacroErrorEventArgs { Name = Model.Name, Alias = Model.Alias, ItemKey = Model.Xslt, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour }; + var macroControl = GetControlForErrorBehavior("Error parsing XSLT file: \\xslt\\" + XsltFile, macroErrorEventArgs); + //if it is null, then we are supposed to throw the (original) exception + // see: http://issues.umbraco.org/issue/U4-497 at the end + if (macroControl == null && throwError) + { + throw; + } + return macroControl; + } + } } catch (Exception e) { @@ -841,10 +902,7 @@ namespace umbraco } return macroControl; } - } - - TraceWarn("macro", "Xslt is empty"); - return new LiteralControl(string.Empty); + } } // gets the control for the macro, using GetXsltTransform methods for execution @@ -922,13 +980,15 @@ namespace umbraco { TextWriter tw = new StringWriter(); - TraceInfo("umbracoMacro", "Before adding extensions"); XsltArgumentList xslArgs; - xslArgs = AddXsltExtensions(); - var lib = new library(); - xslArgs.AddExtensionObject("urn:umbraco.library", lib); - TraceInfo("umbracoMacro", "After adding extensions"); + using (DisposableTimer.DebugDuration("Adding XSLT Extensions")) + { + xslArgs = AddXsltExtensions(); + var lib = new library(); + xslArgs.AddExtensionObject("urn:umbraco.library", lib); + } + // Add parameters if (parameters == null || !parameters.ContainsKey("currentPage")) { @@ -941,8 +1001,10 @@ namespace umbraco } // Do transformation - TraceInfo("umbracoMacro", "Before performing transformation"); - xslt.Transform(macroXml.CreateNavigator(), xslArgs, tw); + using (DisposableTimer.DebugDuration("Executing XSLT transform")) + { + xslt.Transform(macroXml.CreateNavigator(), xslArgs, tw); + } return TemplateUtilities.ResolveUrlsFromTextString(tw.ToString()); } @@ -959,11 +1021,13 @@ namespace umbraco { TextWriter tw = new StringWriter(); - TraceInfo("umbracoMacro", "Before adding extensions"); - XsltArgumentList xslArgs = AddXsltExtensions(); - var lib = new library(); - xslArgs.AddExtensionObject("urn:umbraco.library", lib); - TraceInfo("umbracoMacro", "After adding extensions"); + XsltArgumentList xslArgs; + using (DisposableTimer.DebugDuration("Adding XSLT Extensions")) + { + xslArgs = AddXsltExtensions(); + var lib = new library(); + xslArgs.AddExtensionObject("urn:umbraco.library", lib); + } // Add parameters if (parameters == null || !parameters.ContainsKey("currentPage")) @@ -978,8 +1042,10 @@ namespace umbraco } // Do transformation - TraceInfo("umbracoMacro", "Before performing transformation"); - xslt.Transform(macroNavigator, xslArgs, tw); + using (DisposableTimer.DebugDuration("Executing XSLT transform")) + { + xslt.Transform(macroNavigator, xslArgs, tw); + } return TemplateUtilities.ResolveUrlsFromTextString(tw.ToString()); } @@ -1238,7 +1304,6 @@ namespace umbraco internal ScriptingMacroResult LoadPartialViewMacro(MacroModel macro) { var retVal = new ScriptingMacroResult(); - TraceInfo("umbracoMacro", "Rendering Partial View Macro"); IMacroEngine engine = null; engine = MacroEngineFactory.GetEngine(PartialViewMacroEngine.EngineName); @@ -1253,7 +1318,6 @@ namespace umbraco retVal.ResultException = result.ResultException; } } - TraceInfo("umbracoMacro", "Rendering Partial View Macro [done]"); retVal.Result = ret; return retVal; } @@ -1261,7 +1325,6 @@ namespace umbraco public ScriptingMacroResult loadMacroScript(MacroModel macro) { var retVal = new ScriptingMacroResult(); - TraceInfo("umbracoMacro", "Loading IMacroEngine script"); string ret = String.Empty; IMacroEngine engine = null; if (!String.IsNullOrEmpty(macro.ScriptCode)) @@ -1287,7 +1350,6 @@ namespace umbraco retVal.ResultException = result.ResultException; } } - TraceInfo("umbracoMacro", "Loading IMacroEngine script [done]"); retVal.Result = ret; return retVal; } @@ -1296,7 +1358,6 @@ namespace umbraco public DLRMacroResult loadMacroDLR(MacroModel macro) { var retVal = new DLRMacroResult(); - TraceInfo("umbracoMacro", "Loading IMacroEngine script"); var ret = new LiteralControl(); IMacroEngine engine = null; if (!String.IsNullOrEmpty(macro.ScriptCode)) @@ -1322,7 +1383,6 @@ namespace umbraco retVal.ResultException = result.ResultException; } } - TraceInfo("umbracoMacro", "Loading IMacroEngine script [done]"); retVal.Control = ret; return retVal; } @@ -1595,22 +1655,46 @@ namespace umbraco } } - private static void TraceInfo(string category, string message) + private static void TraceInfo(string category, string message, bool excludeProfiling = false) { if (HttpContext.Current != null) HttpContext.Current.Trace.Write(category, message); + + //Trace out to profiling... doesn't actually profile, just for informational output. + if (excludeProfiling == false) + { + using (ProfilerResolver.Current.Profiler.Step(string.Format("{0}", message))) + { + } + } } - private static void TraceWarn(string category, string message) + private static void TraceWarn(string category, string message, bool excludeProfiling = false) { if (HttpContext.Current != null) HttpContext.Current.Trace.Warn(category, message); + + //Trace out to profiling... doesn't actually profile, just for informational output. + if (excludeProfiling == false) + { + using (ProfilerResolver.Current.Profiler.Step(string.Format("Warning: {0}", message))) + { + } + } } - private static void TraceWarn(string category, string message, Exception ex) + private static void TraceWarn(string category, string message, Exception ex, bool excludeProfiling = false) { if (HttpContext.Current != null) HttpContext.Current.Trace.Warn(category, message, ex); + + //Trace out to profiling... doesn't actually profile, just for informational output. + if (excludeProfiling == false) + { + using (ProfilerResolver.Current.Profiler.Step(string.Format("{0}, Error: {1}", message, ex))) + { + } + } } public static string renderMacroStartTag(Hashtable attributes, int pageId, Guid versionId) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs index caadca5caa..3ea88f38b8 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs @@ -494,8 +494,11 @@ namespace umbraco.cms.presentation.Trees /// The instance containing the event data. protected virtual void OnBeforeNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e) { - if (BeforeNodeRender != null) - BeforeNodeRender(ref sender, ref node, e); + if (node != null && node != null) + { + if (BeforeNodeRender != null) + BeforeNodeRender(ref sender, ref node, e); + } } /// diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs index 84514d3a39..a78ad6d0fc 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs @@ -8,7 +8,7 @@ using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.IO; -using umbraco.IO; +using Umbraco.Core.IO; namespace umbraco.cms.presentation.Trees { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs index ad1feb1c69..aaa75f750d 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs @@ -52,7 +52,7 @@ namespace umbraco } function openView(id) { - UmbClientMgr.contentFrame('settings/views/editView.aspx?templateID=' + id); + UmbClientMgr.contentFrame('settings/views/editView.aspx?treeType=templates&templateID=' + id); } function openSkin(id) { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Macros/editMacro.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Macros/editMacro.aspx.cs index d420dae7da..c215002270 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Macros/editMacro.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Macros/editMacro.aspx.cs @@ -80,6 +80,10 @@ namespace umbraco.cms.presentation.developer { int macroID = Convert.ToInt32(Request.QueryString["macroID"]); + ClientTools + .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) + .SyncTree("-1,init," + m_macro.Id.ToString(), true); //true forces the reload + string tempMacroAssembly = macroAssembly.Text; string tempMacroType = macroType.Text; string tempCachePeriod = cachePeriod.Text; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs index dc57f13324..4975783f97 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs @@ -10,6 +10,7 @@ using umbraco.cms.businesslogic.language; using umbraco.cms.businesslogic.macro; using umbraco.cms.businesslogic.template; using umbraco.cms.businesslogic.web; +using umbraco.cms.presentation.Trees; using umbraco.controls; using umbraco.IO; @@ -33,10 +34,11 @@ namespace umbraco.presentation.developer.packages protected ContentPicker cp; private cms.businesslogic.packager.PackageInstance pack; private cms.businesslogic.packager.CreatedPackage createdPackage; - + protected void Page_Load(object sender, EventArgs e) { - if (Request.QueryString["id"] != null) { + if (Request.QueryString["id"] != null) + { createdPackage = cms.businesslogic.packager.CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); pack = createdPackage.Data; @@ -46,18 +48,26 @@ namespace umbraco.presentation.developer.packages content.Controls.Add(cp); bt_submitButton.Attributes.Add("onClick", "window.location = 'submitpackage.aspx?id=" + pack.Id.ToString() + "'; return false;"); - - if (!String.IsNullOrEmpty(pack.PackagePath)) { + + if (string.IsNullOrEmpty(pack.PackagePath) == false) + { packageUmbFile.Text = "   Download"; if (cms.businesslogic.packager.repositories.Repository.getAll().Count > 0) - bt_submitButton.Visible = true; + bt_submitButton.Visible = true; - } else { + } + else + { packageUmbFile.Text = "This package is not published"; } - if (!Page.IsPostBack) { + if (Page.IsPostBack == false) + { + ClientTools + .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) + .SyncTree("-1,init," + loadPackages.PACKAGE_TREE_PREFIX + createdPackage.Data.Id, false); + packageAuthorName.Text = pack.Author; packageAuthorUrl.Text = pack.AuthorUrl; packageLicenseName.Text = pack.License; @@ -71,26 +81,28 @@ namespace umbraco.presentation.developer.packages tb_actions.Text = pack.Actions; cp.Value = pack.ContentNodeId.ToString(); - + //startNode.Value = pack.ContentNodeId.ToString(); packageContentSubdirs.Checked = pack.ContentLoadChildNodes; - + /*TEMPLATES */ Template[] umbTemplates = Template.GetAllAsList().ToArray(); - foreach (Template tmp in umbTemplates) { + foreach (Template tmp in umbTemplates) + { ListItem li = new ListItem(tmp.Text, tmp.Id.ToString()); - if(pack.Templates.Contains(tmp.Id.ToString())) + if (pack.Templates.Contains(tmp.Id.ToString())) li.Selected = true; - + templates.Items.Add(li); } /* DOC TYPES */ DocumentType[] docs = DocumentType.GetAllAsList().ToArray(); - foreach (DocumentType dc in docs) { + foreach (DocumentType dc in docs) + { ListItem li = new ListItem(dc.Text, dc.Id.ToString()); if (pack.Documenttypes.Contains(dc.Id.ToString())) li.Selected = true; @@ -100,7 +112,8 @@ namespace umbraco.presentation.developer.packages /*Stylesheets */ StyleSheet[] sheets = StyleSheet.GetAll(); - foreach (StyleSheet st in sheets) { + foreach (StyleSheet st in sheets) + { ListItem li = new ListItem(st.Text, st.Id.ToString()); if (pack.Stylesheets.Contains(st.Id.ToString())) li.Selected = true; @@ -110,7 +123,8 @@ namespace umbraco.presentation.developer.packages } /* MACROS */ Macro[] umbMacros = Macro.GetAll(); - foreach (Macro m in umbMacros) { + foreach (Macro m in umbMacros) + { ListItem li = new ListItem(m.Name, m.Id.ToString()); if (pack.Macros.Contains(m.Id.ToString())) li.Selected = true; @@ -120,7 +134,8 @@ namespace umbraco.presentation.developer.packages /*Langauges */ Language[] umbLanguages = Language.getAll; - foreach (Language l in umbLanguages) { + foreach (Language l in umbLanguages) + { ListItem li = new ListItem(l.FriendlyName, l.id.ToString()); if (pack.Languages.Contains(l.id.ToString())) li.Selected = true; @@ -130,7 +145,8 @@ namespace umbraco.presentation.developer.packages /*Dictionary Items*/ Dictionary.DictionaryItem[] umbDictionary = Dictionary.getTopMostItems; - foreach (Dictionary.DictionaryItem d in umbDictionary) { + foreach (Dictionary.DictionaryItem d in umbDictionary) + { string liName = d.key; if (d.hasChildren) @@ -146,7 +162,8 @@ namespace umbraco.presentation.developer.packages /*Data types */ cms.businesslogic.datatype.DataTypeDefinition[] umbDataType = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); - foreach (cms.businesslogic.datatype.DataTypeDefinition umbDtd in umbDataType) { + foreach (cms.businesslogic.datatype.DataTypeDefinition umbDtd in umbDataType) + { ListItem li = new ListItem(umbDtd.Text, umbDtd.Id.ToString()); @@ -162,6 +179,12 @@ namespace umbraco.presentation.developer.packages packageControlPath.Text = pack.LoadControl; } + else + { + ClientTools + .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) + .SyncTree("-1,init," + loadPackages.PACKAGE_TREE_PREFIX + createdPackage.Data.Id, true); + } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx deleted file mode 100644 index f1c3b6d617..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx +++ /dev/null @@ -1,77 +0,0 @@ -<%@ Page ValidateRequest="false" Language="c#" MasterPageFile="../../masterpages/umbracoPage.Master" - CodeBehind="editPython.aspx.cs" AutoEventWireup="True" Inherits="umbraco.cms.presentation.developer.editPython" %> - -<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs index 0d7f73d607..ccbcd6fb6d 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -17,6 +17,7 @@ using Umbraco.Core.IO; using umbraco.cms.businesslogic.macro; using umbraco.cms.presentation.Trees; using umbraco.cms.helpers; +using umbraco.uicontrols; namespace umbraco.cms.presentation.developer { @@ -28,12 +29,16 @@ namespace umbraco.cms.presentation.developer } - private List allowedExtensions = new List(); - protected PlaceHolder buttons; - protected uicontrols.CodeArea CodeArea1; + protected MenuIconI SaveButton; - private void Page_Load(object sender, System.EventArgs e) + private readonly List _allowedExtensions = new List(); + protected PlaceHolder buttons; + protected CodeArea CodeArea1; + + protected override void OnLoad(EventArgs e) { + base.OnLoad(e); + UmbracoPanel1.hasMenu = true; if (!IsPostBack) @@ -48,28 +53,26 @@ namespace umbraco.cms.presentation.developer private List validScriptingExtensions() { - if (allowedExtensions.Count == 0) + if (_allowedExtensions.Count == 0) { foreach (MacroEngineLanguage lang in MacroEngineFactory.GetSupportedUILanguages()) { - if (!allowedExtensions.Contains(lang.Extension)) - allowedExtensions.Add(lang.Extension); + if (!_allowedExtensions.Contains(lang.Extension)) + _allowedExtensions.Add(lang.Extension); } } - return allowedExtensions; + return _allowedExtensions; } protected override void OnInit(EventArgs e) { - InitializeComponent(); base.OnInit(e); - uicontrols.MenuIconI save = UmbracoPanel1.Menu.NewIcon(); - save.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; - save.OnClickCommand = "doSubmit()"; - save.AltText = "Save scripting File"; - save.ID = "save"; + SaveButton = UmbracoPanel1.Menu.NewIcon(); + SaveButton.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; + SaveButton.AltText = "Save scripting File"; + SaveButton.ID = "save"; // Add source and filename String file = IOHelper.MapPath(SystemDirectories.MacroScripts + "/" + Request.QueryString["file"]); @@ -89,17 +92,84 @@ namespace umbraco.cms.presentation.developer pythonSource.Text = S; } - private void InitializeComponent() - { - this.Load += new System.EventHandler(this.Page_Load); - } - protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/codeEditorSave.asmx")); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/legacyAjaxCalls.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/legacyAjaxCalls.asmx")); } + + /// + /// UmbracoPanel1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.UmbracoPanel UmbracoPanel1; + + /// + /// Pane1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane1; + + /// + /// pp_filename control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_filename; + + /// + /// pythonFileName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox pythonFileName; + + /// + /// pp_testing control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_testing; + + /// + /// SkipTesting control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBox SkipTesting; + + /// + /// pp_errorMsg control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_errorMsg; + + /// + /// pythonSource control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.CodeArea pythonSource; } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.designer.cs deleted file mode 100644 index 253bfa28fd..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.designer.cs +++ /dev/null @@ -1,87 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace umbraco.cms.presentation.developer { - - - public partial class editPython { - - /// - /// UmbracoPanel1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.UmbracoPanel UmbracoPanel1; - - /// - /// Pane1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane1; - - /// - /// pp_filename control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_filename; - - /// - /// pythonFileName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox pythonFileName; - - /// - /// pp_testing control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_testing; - - /// - /// SkipTesting control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBox SkipTesting; - - /// - /// pp_errorMsg control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_errorMsg; - - /// - /// pythonSource control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.CodeArea pythonSource; - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Xslt/editXslt.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Xslt/editXslt.aspx.cs index 0715b1457b..1f926b4cca 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Xslt/editXslt.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Xslt/editXslt.aspx.cs @@ -7,11 +7,11 @@ using System.Web.UI; using System.Web.UI.WebControls; using System.Xml; using System.Xml.Xsl; +using Umbraco.Core.IO; using umbraco.BasePages; using umbraco.uicontrols; using System.Net; using umbraco.cms.presentation.Trees; -using umbraco.IO; using umbraco.cms.helpers; namespace umbraco.cms.presentation.developer @@ -25,9 +25,10 @@ namespace umbraco.cms.presentation.developer { CurrentApp = BusinessLogic.DefaultApps.developer.ToString(); } + protected PlaceHolder buttons; - + protected MenuIconI SaveButton; protected void Page_Load(object sender, EventArgs e) { @@ -44,28 +45,20 @@ namespace umbraco.cms.presentation.developer } - #region Web Form Designer generated code - protected override void OnInit(EventArgs e) - { - // - // CODEGEN: This call is required by the ASP.NET Web Form Designer. - // - InitializeComponent(); + { base.OnInit(e); - - - uicontrols.MenuIconI save = UmbracoPanel1.Menu.NewIcon(); - save.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; - save.OnClickCommand = "doSubmit()"; - save.AltText = "Save Xslt File"; - save.ID = "save"; + + SaveButton = UmbracoPanel1.Menu.NewIcon(); + SaveButton.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; + SaveButton.AltText = "Save Xslt File"; + SaveButton.ID = "save"; UmbracoPanel1.Menu.InsertSplitter(); - uicontrols.MenuIconI tmp = UmbracoPanel1.Menu.NewIcon(); - tmp.ImageURL = umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/images/editor/insField.GIF"; - tmp.OnClickCommand = ClientTools.Scripts.OpenModalWindow(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/developer/xslt/xsltinsertvalueof.aspx?objectId=" + editorSource.ClientID, "Insert value", 750, 250); + var tmp = UmbracoPanel1.Menu.NewIcon(); + tmp.ImageURL = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/images/editor/insField.GIF"; + tmp.OnClickCommand = ClientTools.Scripts.OpenModalWindow(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/developer/xslt/xsltinsertvalueof.aspx?objectId=" + editorSource.ClientID, "Insert value", 750, 250); //"umbracoInsertField(document.getElementById('editorSource'), 'xsltInsertValueOf', '','felt', 750, 230, '');"; tmp.AltText = "Insert xslt:value-of"; @@ -104,7 +97,7 @@ namespace umbraco.cms.presentation.developer // Add source and filename - String file = IOHelper.MapPath(SystemDirectories.Xslt + "/" + Request.QueryString["file"]); + var file = IOHelper.MapPath(SystemDirectories.Xslt + "/" + Request.QueryString["file"]); // validate file IOHelper.ValidateEditPath(file, SystemDirectories.Xslt); @@ -129,19 +122,10 @@ namespace umbraco.cms.presentation.developer { base.OnPreRender(e); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.Webservices) + "/codeEditorSave.asmx")); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.Webservices) + "/legacyAjaxCalls.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/codeEditorSave.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/legacyAjaxCalls.asmx")); } - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - } - - #endregion /// /// JsInclude1 control. diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs index fc1b3827ef..2bb660c817 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs @@ -1,6 +1,10 @@ using System; using System.Diagnostics; +using System.Web.Mvc; using System.Web.UI; +using StackExchange.Profiling; +using Umbraco.Core.Profiling; +using Umbraco.Web; using umbraco.presentation.LiveEditing; using umbraco.presentation.LiveEditing.Controls; using System.IO; @@ -23,11 +27,32 @@ namespace umbraco.presentation.masterpages } } + protected override void OnPreRender(EventArgs e) + { + base.OnPreRender(e); + } + protected override void Render(HtmlTextWriter writer) { - if (!m_LiveEditingContext.Enabled) + if (m_LiveEditingContext.Enabled == false) { - base.Render(writer); + // profiling + if (string.IsNullOrEmpty(Request.QueryString["umbDebug"]) == false && GlobalSettings.DebugMode) + { + var baseWriter = new StringWriter(); + base.Render(new HtmlTextWriter(baseWriter)); + var baseOutput = baseWriter.ToString(); + + var htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage()); + baseOutput = baseOutput.Replace("", htmlHelper.RenderProfiler() + ""); + writer.Write(baseOutput); + } + + else + { + + base.Render(writer); + } } else { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs index 0f400055d0..e3d6bfe82a 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs @@ -1,213 +1,237 @@ using System; using System.Collections.Generic; +using System.IO; using System.Web; +using System.Web.Mvc; using System.Web.UI; using System.Web.UI.WebControls; //This is only in case an upgrade goes wrong and the the /masterpages/ files are not copied over //which would result in an error. so we have kept the old namespaces intact with references to new ones +using StackExchange.Profiling; +using Umbraco.Core.Profiling; +using Umbraco.Web; using mp = umbraco.presentation.masterpages; namespace umbraco.presentation.umbraco.masterpages { - public class umbracoPage : mp.umbracoPage { } - public class umbracoDialog : mp.umbracoDialog { } + public class umbracoPage : mp.umbracoPage { } + public class umbracoDialog : mp.umbracoDialog { } } namespace umbraco.presentation.masterpages { - public delegate void MasterPageLoadHandler(object sender, System.EventArgs e); + public delegate void MasterPageLoadHandler(object sender, System.EventArgs e); - public partial class umbracoPage : System.Web.UI.MasterPage - { + public partial class umbracoPage : System.Web.UI.MasterPage + { - public new static event MasterPageLoadHandler Load; - public new static event MasterPageLoadHandler Init; + public new static event MasterPageLoadHandler Load; + public new static event MasterPageLoadHandler Init; - protected void Page_Load(object sender, EventArgs e) - { - ClientLoader.DataBind(); - FireOnLoad(e); - } - - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - - if (Init != null) - { - Init(this, e); - } - } + protected void Page_Load(object sender, EventArgs e) + { + ClientLoader.DataBind(); + FireOnLoad(e); + } - protected virtual void FireOnLoad(EventArgs e) - { - if (Load != null) - { - Load(this, e); - } - } + protected override void Render(HtmlTextWriter writer) + { + // get base output + var baseWriter = new StringWriter(); + base.Render(new HtmlTextWriter(baseWriter)); + var baseOutput = baseWriter.ToString(); - /// - /// ClientLoader control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.UmbracoClientDependencyLoader ClientLoader; + // profiling + if (string.IsNullOrEmpty(Request.QueryString["umbDebug"]) == false && GlobalSettings.DebugMode) + { + var htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage()); + baseOutput = baseOutput.Replace("", htmlHelper.RenderProfiler() + ""); + } - /// - /// CssInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude1; + // write modified output + writer.Write(baseOutput); + } - /// - /// CssInclude2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude2; + protected override void OnInit(EventArgs e) + { + base.OnInit(e); - /// - /// JsInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude1; + if (Init != null) + { + Init(this, e); + } + } - /// - /// JsInclude2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude2; - /// - /// JsInclude8 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude8; + protected virtual void FireOnLoad(EventArgs e) + { + if (Load != null) + { + Load(this, e); + } + } - /// - /// JsInclude9 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude9; + /// + /// ClientLoader control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.UmbracoClientDependencyLoader ClientLoader; - /// - /// JsInclude4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude4; + /// + /// CssInclude1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.CssInclude CssInclude1; - /// - /// JsInclude5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude5; + /// + /// CssInclude2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.CssInclude CssInclude2; - /// - /// JsInclude6 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude6; + /// + /// JsInclude1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude1; - /// - /// JsInclude7 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude7; + /// + /// JsInclude2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude2; - /// - /// JsInclude3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude3; + /// + /// JsInclude8 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude8; - /// - /// JsIncludeHotkeys control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsIncludeHotkeys; + /// + /// JsInclude9 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude9; - /// - /// head control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder head; + /// + /// JsInclude4 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude4; - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; + /// + /// JsInclude5 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude5; - /// - /// ScriptManager1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.ScriptManager ScriptManager1; + /// + /// JsInclude6 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude6; - /// - /// body control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder body; + /// + /// JsInclude7 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude7; - /// - /// footer control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder footer; - } + /// + /// JsInclude3 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsInclude3; + + /// + /// JsIncludeHotkeys control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::ClientDependency.Core.Controls.JsInclude JsIncludeHotkeys; + + /// + /// head control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder head; + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// + /// ScriptManager1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.ScriptManager ScriptManager1; + + /// + /// body control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder body; + + /// + /// footer control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder footer; + } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/editTemplate.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/editTemplate.aspx.cs index ae84aac0dc..d7b9396350 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/editTemplate.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/editTemplate.aspx.cs @@ -38,11 +38,14 @@ namespace umbraco.cms.presentation.settings new ServiceReference(IOHelper.ResolveUrl(SystemDirectories.Webservices + "/legacyAjaxCalls.asmx"))); } + protected string TemplateTreeSyncPath { get; private set; } protected void Page_Load(object sender, EventArgs e) { MasterTemplate.Attributes.Add("onchange", "changeMasterPageFile()"); + TemplateTreeSyncPath = "-1,init," + _template.Path.Replace("-1,", ""); + if (!IsPostBack) { MasterTemplate.Items.Add(new ListItem(ui.Text("none"), "0")); @@ -71,7 +74,7 @@ namespace umbraco.cms.presentation.settings ClientTools .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) - .SyncTree("-1,init," + _template.Path.Replace("-1,", ""), false); + .SyncTree(TemplateTreeSyncPath, false); LoadScriptingTemplates(); LoadMacros(); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/scripts/editScript.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/scripts/editScript.aspx.cs index 213e4b6a4f..e0b6f2dfa0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/scripts/editScript.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/scripts/editScript.aspx.cs @@ -11,10 +11,11 @@ using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.IO; using Umbraco.Core; +using Umbraco.Core.IO; using umbraco.cms.presentation.Trees; -using umbraco.IO; using System.Linq; using umbraco.cms.helpers; +using umbraco.uicontrols; namespace umbraco.cms.presentation.settings.scripts { @@ -36,18 +37,20 @@ namespace umbraco.cms.presentation.settings.scripts protected umbraco.uicontrols.PropertyPanel pp_name; protected umbraco.uicontrols.PropertyPanel pp_path; + protected MenuIconI SaveButton; + private string file; - protected void Page_Load(object sender, System.EventArgs e) + protected override void OnLoad(EventArgs e) { - + base.OnLoad(e); NameTxt.Text = file; string path = ""; if (file.StartsWith("~/")) - path = Umbraco.Core.IO.IOHelper.ResolveUrl(file); + path = Umbraco.Core.IO.IOHelper.ResolveUrl(file); else - path = Umbraco.Core.IO.IOHelper.ResolveUrl(Umbraco.Core.IO.SystemDirectories.Scripts + "/" + file); + path = Umbraco.Core.IO.IOHelper.ResolveUrl(Umbraco.Core.IO.SystemDirectories.Scripts + "/" + file); lttPath.Text = "" + path + ""; @@ -60,19 +63,19 @@ namespace umbraco.cms.presentation.settings.scripts } var dirs = Umbraco.Core.IO.SystemDirectories.Scripts; - if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc) + if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc) dirs += "," + Umbraco.Core.IO.SystemDirectories.MvcViews; // validate file - Umbraco.Core.IO.IOHelper.ValidateEditPath(Umbraco.Core.IO.IOHelper.MapPath(path), dirs.Split(',')); - + Umbraco.Core.IO.IOHelper.ValidateEditPath(Umbraco.Core.IO.IOHelper.MapPath(path), dirs.Split(',')); + // validate extension - Umbraco.Core.IO.IOHelper.ValidateFileExtension(Umbraco.Core.IO.IOHelper.MapPath(path), exts); + Umbraco.Core.IO.IOHelper.ValidateFileExtension(Umbraco.Core.IO.IOHelper.MapPath(path), exts); StreamReader SR; string S; - SR = File.OpenText(Umbraco.Core.IO.IOHelper.MapPath(path)); + SR = File.OpenText(Umbraco.Core.IO.IOHelper.MapPath(path)); S = SR.ReadToEnd(); SR.Close(); @@ -91,25 +94,22 @@ namespace umbraco.cms.presentation.settings.scripts } } - - - #region Web Form Designer generated code override protected void OnInit(EventArgs e) { + base.OnInit(e); file = Request.QueryString["file"].TrimStart('/'); //need to change the editor type if it is XML if (file.EndsWith("xml")) - editorSource.CodeBase = umbraco.uicontrols.CodeArea.EditorType.XML; + editorSource.CodeBase = uicontrols.CodeArea.EditorType.XML; else if (file.EndsWith("master")) - editorSource.CodeBase = umbraco.uicontrols.CodeArea.EditorType.HTML; + editorSource.CodeBase = uicontrols.CodeArea.EditorType.HTML; - uicontrols.MenuIconI save = Panel1.Menu.NewIcon(); - save.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; - save.OnClickCommand = "doSubmit()"; - save.AltText = "Save File"; - save.ID = "save"; + SaveButton = Panel1.Menu.NewIcon(); + SaveButton.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; + SaveButton.AltText = "Save File"; + SaveButton.ID = "save"; if (editorSource.CodeBase == uicontrols.CodeArea.EditorType.HTML) { @@ -117,19 +117,19 @@ namespace umbraco.cms.presentation.settings.scripts Panel1.Menu.InsertSplitter(); uicontrols.MenuIconI umbField = Panel1.Menu.NewIcon(); umbField.ImageURL = UmbracoPath + "/images/editor/insField.gif"; - umbField.OnClickCommand = umbraco.BasePages.ClientTools.Scripts.OpenModalWindow(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" + editorSource.ClientID + "&tagName=UMBRACOGETDATA", ui.Text("template", "insertPageField"), 640, 550); + umbField.OnClickCommand = BasePages.ClientTools.Scripts.OpenModalWindow(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" + editorSource.ClientID + "&tagName=UMBRACOGETDATA", ui.Text("template", "insertPageField"), 640, 550); umbField.AltText = ui.Text("template", "insertPageField"); // TODO: Update icon uicontrols.MenuIconI umbDictionary = Panel1.Menu.NewIcon(); umbDictionary.ImageURL = GlobalSettings.Path + "/images/editor/dictionaryItem.gif"; - umbDictionary.OnClickCommand = umbraco.BasePages.ClientTools.Scripts.OpenModalWindow(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" + editorSource.ClientID + "&tagName=UMBRACOGETDICTIONARY", ui.Text("template", "insertDictionaryItem"), 640, 550); + umbDictionary.OnClickCommand = BasePages.ClientTools.Scripts.OpenModalWindow(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" + editorSource.ClientID + "&tagName=UMBRACOGETDICTIONARY", ui.Text("template", "insertDictionaryItem"), 640, 550); umbDictionary.AltText = "Insert umbraco dictionary item"; uicontrols.MenuIconI umbMacro = Panel1.Menu.NewIcon(); umbMacro.ImageURL = UmbracoPath + "/images/editor/insMacro.gif"; umbMacro.AltText = ui.Text("template", "insertMacro"); - umbMacro.OnClickCommand = umbraco.BasePages.ClientTools.Scripts.OpenModalWindow(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/dialogs/editMacro.aspx?objectId=" + editorSource.ClientID, ui.Text("template", "insertMacro"), 470, 530); + umbMacro.OnClickCommand = BasePages.ClientTools.Scripts.OpenModalWindow(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/dialogs/editMacro.aspx?objectId=" + editorSource.ClientID, ui.Text("template", "insertMacro"), 470, 530); // Help Panel1.Menu.InsertSplitter(); @@ -141,23 +141,8 @@ namespace umbraco.cms.presentation.settings.scripts } - - this.Load += new System.EventHandler(Page_Load); - InitializeComponent(); - base.OnInit(e); - } - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - - } - - + protected override void OnPreRender(EventArgs e) { @@ -165,7 +150,6 @@ namespace umbraco.cms.presentation.settings.scripts ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/codeEditorSave.asmx")); ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/legacyAjaxCalls.asmx")); } - #endregion } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs index f03c2c360f..d430000b36 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs @@ -17,20 +17,26 @@ namespace umbraco.cms.presentation.settings.stylesheet { private StyleSheet stylesheet; + protected MenuIconI SaveButton; + public editstylesheet() { CurrentApp = DefaultApps.settings.ToString(); } - protected void Page_Load(object sender, EventArgs e) - { - var save = Panel1.Menu.NewIcon(); - save.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; + protected override void OnInit(EventArgs e) + { + base.OnInit(e); - save.OnClickCommand = "Umbraco.Editors.EditStyleSheet.save('" + editorSource.ClientID + "', '" + NameTxt.ClientID + "', '" + NameTxt.Text + "', '" + Request.QueryString["id"] + "')"; + SaveButton = Panel1.Menu.NewIcon(); + SaveButton.ImageURL = SystemDirectories.Umbraco + "/images/editor/save.gif"; + SaveButton.AltText = "Save stylesheet"; + SaveButton.ID = "save"; + } + + protected void Page_Load(object sender, EventArgs e) + { - save.AltText = "Save stylesheet"; - save.ID = "save"; Panel1.Text = ui.Text("stylesheet", "editstylesheet", UmbracoUser); pp_name.Text = ui.Text("name", UmbracoUser); pp_path.Text = ui.Text("path", UmbracoUser); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index 0116b2f781..37f6d4ad2f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -8,9 +8,11 @@ using System.Web; using System.Web.Caching; using System.Web.UI; using System.Xml; +using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Macros; +using Umbraco.Core.Profiling; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.XmlPublishedCache; @@ -23,269 +25,276 @@ using umbraco.IO; namespace umbraco.presentation.templateControls { - public class ItemRenderer - { - public readonly static ItemRenderer Instance = new ItemRenderer(); - /// - /// Initializes a new instance of the class. - /// - protected ItemRenderer() - { } + public class ItemRenderer + { + public readonly static ItemRenderer Instance = new ItemRenderer(); + /// + /// Initializes a new instance of the class. + /// + protected ItemRenderer() + { } - /// - /// Renders the specified item. - /// - /// The item. - /// The writer. - public virtual void Render(Item item, HtmlTextWriter writer) - { - if (item.DebugMode) - { - writer.AddAttribute(HtmlTextWriterAttribute.Title, string.Format("Field Tag: '{0}'", item.Field)); - writer.AddAttribute("style", "border: 1px solid #fc6;"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - } + /// + /// Renders the specified item. + /// + /// The item. + /// The writer. + public virtual void Render(Item item, HtmlTextWriter writer) + { + if (item.DebugMode) + { + writer.AddAttribute(HtmlTextWriterAttribute.Title, string.Format("Field Tag: '{0}'", item.Field)); + writer.AddAttribute("style", "border: 1px solid #fc6;"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + } - try - { - StringWriter renderOutputWriter = new StringWriter(); - HtmlTextWriter htmlWriter = new HtmlTextWriter(renderOutputWriter); - foreach (Control control in item.Controls) - { - try - { - control.RenderControl(htmlWriter); - } - catch (Exception renderException) - { - // TODO: Validate that the current control is within the scope of a form control - // Even controls that are inside this scope, can produce this error in async postback. - HttpContext.Current.Trace.Warn("ItemRenderer", - String.Format("Error rendering control {0} of {1}.", control.ClientID, item), renderException); - } - } + try + { + StringWriter renderOutputWriter = new StringWriter(); + HtmlTextWriter htmlWriter = new HtmlTextWriter(renderOutputWriter); + foreach (Control control in item.Controls) + { + try + { + control.RenderControl(htmlWriter); + } + catch (Exception renderException) + { + // TODO: Validate that the current control is within the scope of a form control + // Even controls that are inside this scope, can produce this error in async postback. + HttpContext.Current.Trace.Warn("ItemRenderer", + String.Format("Error rendering control {0} of {1}.", control.ClientID, item), renderException); + } + } - // parse macros and execute the XSLT transformation on the result if not empty - string renderOutput = renderOutputWriter.ToString(); - string xsltTransformedOutput = renderOutput.Trim().Length == 0 - ? String.Empty - : XsltTransform(item.Xslt, renderOutput, item.XsltDisableEscaping); - // handle text before/after - xsltTransformedOutput = AddBeforeAfterText(xsltTransformedOutput, helper.FindAttribute(item.LegacyAttributes, "insertTextBefore"), helper.FindAttribute(item.LegacyAttributes, "insertTextAfter")); - string finalResult = xsltTransformedOutput.Trim().Length > 0 ? xsltTransformedOutput : GetEmptyText(item); - writer.Write(TemplateUtilities.ResolveUrlsFromTextString(finalResult)); - } - catch (Exception renderException) - { - HttpContext.Current.Trace.Warn("ItemRenderer", String.Format("Error rendering {0}.", item), renderException); - } - finally - { - if (item.DebugMode) - { - writer.RenderEndTag(); - } - } - } + // parse macros and execute the XSLT transformation on the result if not empty + string renderOutput = renderOutputWriter.ToString(); + string xsltTransformedOutput = renderOutput.Trim().Length == 0 + ? String.Empty + : XsltTransform(item.Xslt, renderOutput, item.XsltDisableEscaping); + // handle text before/after + xsltTransformedOutput = AddBeforeAfterText(xsltTransformedOutput, helper.FindAttribute(item.LegacyAttributes, "insertTextBefore"), helper.FindAttribute(item.LegacyAttributes, "insertTextAfter")); + string finalResult = xsltTransformedOutput.Trim().Length > 0 ? xsltTransformedOutput : GetEmptyText(item); + writer.Write(TemplateUtilities.ResolveUrlsFromTextString(finalResult)); + } + catch (Exception renderException) + { + HttpContext.Current.Trace.Warn("ItemRenderer", String.Format("Error rendering {0}.", item), renderException); + } + finally + { + if (item.DebugMode) + { + writer.RenderEndTag(); + } + } + } - /// - /// Renders the field contents. - /// Checks via the NodeId attribute whether to fetch data from another page than the current one. - /// - /// A string of field contents (macros not parsed) - protected virtual string GetFieldContents(Item item) - { - var tempElementContent = string.Empty; + /// + /// Renders the field contents. + /// Checks via the NodeId attribute whether to fetch data from another page than the current one. + /// + /// A string of field contents (macros not parsed) + protected virtual string GetFieldContents(Item item) + { + var tempElementContent = string.Empty; - // if a nodeId is specified we should get the data from another page than the current one - if (string.IsNullOrEmpty(item.NodeId) == false) - { - var tempNodeId = item.GetParsedNodeId(); - if (tempNodeId != null && tempNodeId.Value != 0) - { + // if a nodeId is specified we should get the data from another page than the current one + if (string.IsNullOrEmpty(item.NodeId) == false) + { + var tempNodeId = item.GetParsedNodeId(); + if (tempNodeId != null && tempNodeId.Value != 0) + { //moved the following from the catch block up as this will allow fallback options alt text etc to work - var cache = Umbraco.Web.UmbracoContext.Current.ContentCache.InnerCache as PublishedContentCache; + var cache = Umbraco.Web.UmbracoContext.Current.ContentCache.InnerCache as PublishedContentCache; if (cache == null) throw new InvalidOperationException("Unsupported IPublishedContentCache, only the Xml one is supported."); - var xml = cache.GetXml(Umbraco.Web.UmbracoContext.Current, Umbraco.Web.UmbracoContext.Current.InPreviewMode); + var xml = cache.GetXml(Umbraco.Web.UmbracoContext.Current, Umbraco.Web.UmbracoContext.Current.InPreviewMode); var itemPage = new page(xml.GetElementById(tempNodeId.ToString())); tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; - } - } - else - { - // gets the field content from the current page (via the PageElements collection) - tempElementContent = new item(item.PageElements, item.LegacyAttributes).FieldContent; - } + } + } + else + { + // gets the field content from the current page (via the PageElements collection) + tempElementContent = new item(item.PageElements, item.LegacyAttributes).FieldContent; + } - return tempElementContent; - } + return tempElementContent; + } - /// - /// Inits the specified item. To be called from the OnInit method of Item. - /// - /// The item. - public virtual void Init(Item item) - { } + /// + /// Inits the specified item. To be called from the OnInit method of Item. + /// + /// The item. + public virtual void Init(Item item) + { } - /// - /// Loads the specified item. To be called from the OnLoad method of Item. - /// - /// The item. - public virtual void Load(Item item) - { - ParseMacros(item); - } + /// + /// Loads the specified item. To be called from the OnLoad method of Item. + /// + /// The item. + public virtual void Load(Item item) + { + using (DisposableTimer.DebugDuration(string.Format("Item: {0}", item.Field))) + { + ParseMacros(item); + } + } - /// - /// Parses the macros inside the text, by creating child elements for each item. - /// - /// The item. - protected virtual void ParseMacros(Item item) - { - // do nothing if the macros have already been rendered - if (item.Controls.Count > 0) - return; + /// + /// Parses the macros inside the text, by creating child elements for each item. + /// + /// The item. + protected virtual void ParseMacros(Item item) + { + // do nothing if the macros have already been rendered + if (item.Controls.Count > 0) + return; - string elementText = GetFieldContents(item); + string elementText = GetFieldContents(item); - MacroTagParser.ParseMacros( - elementText, + using (DisposableTimer.DebugDuration("Parsing Macros")) + { - //callback for when a text block is parsed - textBlock => item.Controls.Add(new LiteralControl(textBlock)), + MacroTagParser.ParseMacros( + elementText, - //callback for when a macro is parsed: - (macroAlias, attributes) => - { - var macroControl = new Macro - { - Alias = macroAlias - }; - foreach (var i in attributes.Where(i => macroControl.Attributes[i.Key] == null)) - { - macroControl.Attributes.Add(i.Key, i.Value); - } - item.Controls.Add(macroControl); - }); - } + //callback for when a text block is parsed + textBlock => item.Controls.Add(new LiteralControl(textBlock)), - /// - /// Transforms the content using the XSLT attribute, if provided. - /// - /// The xpath expression. - /// The item's rendered content. - /// if set to true, escaping is disabled. - /// The transformed content if the XSLT attribute is present, otherwise the original content. - protected virtual string XsltTransform(string xpath, string itemData, bool disableEscaping) - { - if (!String.IsNullOrEmpty(xpath)) - { - // XML-encode the expression and add the itemData parameter to it - string xpathEscaped = xpath.Replace("<", "<").Replace(">", ">").Replace("\"", """); - string xpathExpression = string.Format(xpathEscaped, "$itemData"); + //callback for when a macro is parsed: + (macroAlias, attributes) => + { + var macroControl = new Macro + { + Alias = macroAlias + }; + foreach (var i in attributes.Where(i => macroControl.Attributes[i.Key] == null)) + { + macroControl.Attributes.Add(i.Key, i.Value); + } + item.Controls.Add(macroControl); + }); + } + } - // prepare support for XSLT extensions - StringBuilder namespaceList = new StringBuilder(); - StringBuilder namespaceDeclaractions = new StringBuilder(); - foreach (KeyValuePair extension in macro.GetXsltExtensions()) - { - namespaceList.Append(extension.Key).Append(' '); - namespaceDeclaractions.AppendFormat("xmlns:{0}=\"urn:{0}\" ", extension.Key); - } + /// + /// Transforms the content using the XSLT attribute, if provided. + /// + /// The xpath expression. + /// The item's rendered content. + /// if set to true, escaping is disabled. + /// The transformed content if the XSLT attribute is present, otherwise the original content. + protected virtual string XsltTransform(string xpath, string itemData, bool disableEscaping) + { + if (!String.IsNullOrEmpty(xpath)) + { + // XML-encode the expression and add the itemData parameter to it + string xpathEscaped = xpath.Replace("<", "<").Replace(">", ">").Replace("\"", """); + string xpathExpression = string.Format(xpathEscaped, "$itemData"); - // add the XSLT expression into the full XSLT document, together with the needed parameters + // prepare support for XSLT extensions + StringBuilder namespaceList = new StringBuilder(); + StringBuilder namespaceDeclaractions = new StringBuilder(); + foreach (KeyValuePair extension in macro.GetXsltExtensions()) + { + namespaceList.Append(extension.Key).Append(' '); + namespaceDeclaractions.AppendFormat("xmlns:{0}=\"urn:{0}\" ", extension.Key); + } + + // add the XSLT expression into the full XSLT document, together with the needed parameters string xslt = string.Format(Umbraco.Web.umbraco.presentation.umbraco.templateControls.Resources.InlineXslt, xpathExpression, disableEscaping ? "yes" : "no", - namespaceList, namespaceDeclaractions); + namespaceList, namespaceDeclaractions); - // create the parameter - Dictionary parameters = new Dictionary(1); - parameters.Add("itemData", itemData); + // create the parameter + Dictionary parameters = new Dictionary(1); + parameters.Add("itemData", itemData); - // apply the XSLT transformation - XmlTextReader xslReader = new XmlTextReader(new StringReader(xslt)); - System.Xml.Xsl.XslCompiledTransform xsl = macro.CreateXsltTransform(xslReader, false); - itemData = macro.GetXsltTransformResult(new XmlDocument(), xsl, parameters); - xslReader.Close(); - } - return itemData; - } + // apply the XSLT transformation + XmlTextReader xslReader = new XmlTextReader(new StringReader(xslt)); + System.Xml.Xsl.XslCompiledTransform xsl = macro.CreateXsltTransform(xslReader, false); + itemData = macro.GetXsltTransformResult(new XmlDocument(), xsl, parameters); + xslReader.Close(); + } + return itemData; + } - protected string AddBeforeAfterText(string text, string before, string after) - { - if (!String.IsNullOrEmpty(text)) - { - if (!String.IsNullOrEmpty(before)) - text = String.Format("{0}{1}", HttpContext.Current.Server.HtmlDecode(before), text); - if (!String.IsNullOrEmpty(after)) - text = String.Format("{0}{1}", text, HttpContext.Current.Server.HtmlDecode(after)); - } + protected string AddBeforeAfterText(string text, string before, string after) + { + if (!String.IsNullOrEmpty(text)) + { + if (!String.IsNullOrEmpty(before)) + text = String.Format("{0}{1}", HttpContext.Current.Server.HtmlDecode(before), text); + if (!String.IsNullOrEmpty(after)) + text = String.Format("{0}{1}", text, HttpContext.Current.Server.HtmlDecode(after)); + } - return text; - } + return text; + } - /// - /// Gets the text to display if the field contents are empty. - /// - /// The item. - /// The text to display. - protected virtual string GetEmptyText(Item item) - { - return item.TextIfEmpty; - } + /// + /// Gets the text to display if the field contents are empty. + /// + /// The item. + /// The text to display. + protected virtual string GetEmptyText(Item item) + { + return item.TextIfEmpty; + } - /// - /// Gets the field content from database instead of the published XML via the APIs. - /// - /// - /// The node id. - /// The field that should be fetched. - /// The contents of the from the content object - [Obsolete("This is no longer used in the codebase and will be removed in future versions")] + /// + /// Gets the field content from database instead of the published XML via the APIs. + /// + /// + /// The node id. + /// The field that should be fetched. + /// The contents of the from the content object + [Obsolete("This is no longer used in the codebase and will be removed in future versions")] protected virtual string GetContentFromDatabase(AttributeCollectionAdapter itemAttributes, int nodeIdInt, string currentField) - { - var c = new Content(nodeIdInt); + { + var c = new Content(nodeIdInt); - var property = c.getProperty(currentField); - if (property == null) - throw new ArgumentException(String.Format("Could not find property {0} of node {1}.", currentField, nodeIdInt)); + var property = c.getProperty(currentField); + if (property == null) + throw new ArgumentException(String.Format("Could not find property {0} of node {1}.", currentField, nodeIdInt)); - var umbItem = new item(property.Value.ToString(), itemAttributes); - var tempElementContent = umbItem.FieldContent; + var umbItem = new item(property.Value.ToString(), itemAttributes); + var tempElementContent = umbItem.FieldContent; - // If the current content object is a document object, we'll only output it if it's published - if (c.nodeObjectType == Document._objectType) - { - try - { - var d = (Document)c; - if (!d.Published) - tempElementContent = ""; - } - catch { } - } + // If the current content object is a document object, we'll only output it if it's published + if (c.nodeObjectType == Document._objectType) + { + try + { + var d = (Document)c; + if (!d.Published) + tempElementContent = ""; + } + catch { } + } - // Add the content to the cache - if (!string.IsNullOrEmpty(tempElementContent)) - { - ApplicationContext.Current.ApplicationCache.InsertCacheItem( - string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, currentField), - CacheItemPriority.Default, () => tempElementContent); - } - return tempElementContent; - } + // Add the content to the cache + if (!string.IsNullOrEmpty(tempElementContent)) + { + ApplicationContext.Current.ApplicationCache.InsertCacheItem( + string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, currentField), + CacheItemPriority.Default, () => tempElementContent); + } + return tempElementContent; + } - /// - /// Gets the content from cache. - /// - /// The node id. - /// The field. + /// + /// Gets the content from cache. + /// + /// The node id. + /// The field. /// The cached contents of the from the content object [Obsolete("This is no longer used in the codebase and will be removed in future versions")] - protected virtual object GetContentFromCache(int nodeIdInt, string field) - { - var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( + protected virtual object GetContentFromCache(int nodeIdInt, string field) + { + var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, field)); - return content; - } - } + return content; + } + } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Document.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Document.cs index 894acebc79..b205b0612b 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Document.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Document.cs @@ -136,7 +136,10 @@ namespace umbraco foreach (var document in documents) { - dictionary.Add(document.Id, document.Text); + if (document != null && document.Id != -1) // to compensate for the root document now throwing a null error on it's .Text property + { + dictionary.Add(document.Id, document.Text); + } } return dictionary; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Media.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Media.cs index c56b086012..a2b3e1a163 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Media.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Media.cs @@ -149,7 +149,10 @@ namespace umbraco foreach (var mediaItem in media) { - dictionary.Add(mediaItem.Id, mediaItem.Text); + if (mediaItem != null && mediaItem.Id != -1) + { + dictionary.Add(mediaItem.Id, mediaItem.Text); + } } return dictionary; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Members.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Members.cs index 1a99a2bde2..4b300e2142 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Members.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery-Members.cs @@ -137,7 +137,10 @@ namespace umbraco foreach (var member in members) { - dictionary.Add(member.Id, member.LoginName); + if (member != null) + { + dictionary.Add(member.Id, member.LoginName); + } } return dictionary; diff --git a/src/packages/repositories.config b/src/packages/repositories.config index 92b69bdd51..077bedd09b 100644 --- a/src/packages/repositories.config +++ b/src/packages/repositories.config @@ -9,7 +9,6 @@ - diff --git a/src/umbraco.businesslogic/BasePages/BasePage.cs b/src/umbraco.businesslogic/BasePages/BasePage.cs index 8e2eb59e97..e44a92c30b 100644 --- a/src/umbraco.businesslogic/BasePages/BasePage.cs +++ b/src/umbraco.businesslogic/BasePages/BasePage.cs @@ -267,9 +267,16 @@ namespace umbraco.BasePages return encTicket.DecryptWithMachineKey(); } } - catch (HttpException ex) + catch (Exception ex) { - // we swallow this type of exception as it happens if a legacy (pre 4.8.1) cookie is set + if (ex is ArgumentException || ex is FormatException || ex is HttpException) + { + StateHelper.Cookies.UserContext.Clear(); + } + else + { + throw; + } } } return ""; diff --git a/src/umbraco.businesslogic/Log.cs b/src/umbraco.businesslogic/Log.cs index 7de12ab617..18349b1f56 100644 --- a/src/umbraco.businesslogic/Log.cs +++ b/src/umbraco.businesslogic/Log.cs @@ -211,7 +211,7 @@ namespace umbraco.BusinessLogic return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", - SqlHelper.CreateParameter("@logHeader", type), + SqlHelper.CreateParameter("@logHeader", type.ToString()), SqlHelper.CreateParameter("@dateStamp", sinceDate))); } @@ -243,7 +243,7 @@ namespace umbraco.BusinessLogic return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", - SqlHelper.CreateParameter("@logHeader", type), + SqlHelper.CreateParameter("@logHeader", type.ToString()), SqlHelper.CreateParameter("@user", user.Id), SqlHelper.CreateParameter("@dateStamp", sinceDate))); } diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 9db987c68f..ebacf89fa1 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -147,7 +147,8 @@ namespace umbraco.cms.businesslogic public static Guid GetDataType(string contentTypeAlias, string propertyTypeAlias) { - var key = new System.Tuple(contentTypeAlias, propertyTypeAlias); + //propertyTypeAlias needs to be invariant, so we will store uppercase + var key = new System.Tuple(contentTypeAlias, propertyTypeAlias.ToUpper()); return PropertyTypeCache.GetOrAdd( diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 406463c8d4..3ddfd31d18 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -859,7 +859,7 @@ namespace umbraco.cms.businesslogic.web public bool PublishWithChildrenWithResult(User u) { var result = ((ContentService)ApplicationContext.Current.Services.ContentService) - .PublishWithChildrenInternal(Content, u.Id); + .PublishWithChildrenInternal(Content, u.Id, true); //This used to just return false only when the parent content failed, otherwise would always return true so we'll // do the same thing for the moment return result.Single(x => x.Result.ContentItem.Id == Id).Success;