Removes booting.aspx and creates embedded html pages for booting and failed (if those are ever seen ), renames some classes and namespaces, removes old cdf bundle classes

This commit is contained in:
Shannon
2019-01-29 23:05:59 +11:00
parent e7b0e43d98
commit eef86689c8
54 changed files with 383 additions and 376 deletions

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using ClientDependency.Core;
using ClientDependency.Core.Config;
using Umbraco.Web.Composing;
using Umbraco.Web.PropertyEditors;
namespace Umbraco.Web.JavaScript
{
internal abstract class AssetInitialization
{
protected IEnumerable<string> ScanPropertyEditors(ClientDependencyType assetType, HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
var attributes = Current.PropertyEditors
.SelectMany(x => x.GetType().GetCustomAttributes<PropertyEditorAssetAttribute>(false))
.Where(x => x.AssetType == assetType)
.Select(x => x.DependencyFile)
.ToList();
var renderer = ClientDependencySettings.Instance.MvcRendererCollection["Umbraco.DependencyPathRenderer"];
renderer.RegisterDependencies(attributes, new HashSet<IClientDependencyPath>(), out var scripts, out var stylesheets, httpContext);
var toParse = assetType == ClientDependencyType.Javascript ? scripts : stylesheets;
return toParse.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries);
}
internal static IEnumerable<string> OptimizeAssetCollection(IEnumerable<string> assets, ClientDependencyType assetType, HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
var requestUrl = httpContext.Request.Url;
if (requestUrl == null) throw new ArgumentException("HttpContext.Request.Url is null.", nameof(httpContext));
var dependencies = assets.Select(x =>
{
// most declarations with be made relative to the /umbraco folder, so things
// like lib/blah/blah.js so we need to turn them into absolutes here
if (x.StartsWith("/") == false && Uri.IsWellFormedUriString(x, UriKind.Relative))
{
return new BasicFile(assetType) { FilePath = new Uri(requestUrl, x).AbsolutePath };
}
return assetType == ClientDependencyType.Javascript
? new JavascriptFile(x)
: (IClientDependencyFile) new CssFile(x);
}).ToList();
// get the output string for these registrations which will be processed by CDF correctly to stagger the output based
// on internal vs external resources. The output will be delimited based on our custom Umbraco.Web.UI.JavaScript.DependencyPathRenderer
var renderer = ClientDependencySettings.Instance.MvcRendererCollection["Umbraco.DependencyPathRenderer"];
renderer.RegisterDependencies(dependencies, new HashSet<IClientDependencyPath>(), out var scripts, out var stylesheets, httpContext);
var urls = assetType == ClientDependencyType.Javascript
? scripts.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries)
: stylesheets.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries);
return urls;
}
}
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml.Linq;
using ClientDependency.Core.CompositeFiles.Providers;
using ClientDependency.Core.Config;
using Semver;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Web.JavaScript
{
/// <summary>
/// A utility class for working with CDF config and cache files - use sparingly!
/// </summary>
public class ClientDependencyConfiguration
{
private readonly ILogger _logger;
private readonly string _fileName;
public ClientDependencyConfiguration(ILogger logger)
{
if (logger == null) throw new ArgumentNullException("logger");
_logger = logger;
_fileName = IOHelper.MapPath(string.Format("{0}/ClientDependency.config", SystemDirectories.Config));
}
/// <summary>
/// Changes the version number in ClientDependency.config to a hashed value for the version and the DateTime.Day
/// </summary>
/// <param name="version">The <see cref="SemVersion">version</see> of Umbraco we're upgrading to</param>
/// <param name="date">A <see cref="DateTime">date</see> value to use in the hash to prevent this method from updating the version on each startup</param>
/// <param name="dateFormat">Allows the developer to specify the <see cref="string">date precision</see> for the hash (i.e. "yyyyMMdd" would be a precision for the day)</param>
/// <returns>Boolean to indicate successful update of the ClientDependency.config file</returns>
public bool UpdateVersionNumber(SemVersion version, DateTime date, string dateFormat)
{
var byteContents = Encoding.Unicode.GetBytes(version + date.ToString(dateFormat));
//This is a way to convert a string to a long
//see https://www.codeproject.com/Articles/34309/Convert-String-to-bit-Integer
//We could much more easily use MD5 which would create us an INT but since that is not compliant with
//hashing standards we have to use SHA
int intHash;
using (var hash = SHA256.Create())
{
var bytes = hash.ComputeHash(byteContents);
var longResult = new[] { 0, 8, 16, 24 }
.Select(i => BitConverter.ToInt64(bytes, i))
.Aggregate((x, y) => x ^ y);
//CDF requires an INT, and although this isn't fail safe, it will work for our purposes. We are not hashing for crypto purposes
//so there could be some collisions with this conversion but it's not a problem for our purposes
//It's also important to note that the long.GetHashCode() implementation in .NET is this: return (int) this ^ (int) (this >> 32);
//which means that this value will not change per AppDomain like some GetHashCode implementations.
intHash = longResult.GetHashCode();
}
try
{
var clientDependencyConfigXml = XDocument.Load(_fileName, LoadOptions.PreserveWhitespace);
if (clientDependencyConfigXml.Root != null)
{
var versionAttribute = clientDependencyConfigXml.Root.Attribute("version");
//Set the new version to the hashcode of now
var oldVersion = versionAttribute.Value;
var newVersion = Math.Abs(intHash).ToString();
//don't update if it's the same version
if (oldVersion == newVersion)
return false;
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>("Updated version number from {OldVersion} to {NewVersion}", oldVersion, newVersion);
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>(ex, "Couldn't update ClientDependency version number");
}
return false;
}
/// <summary>
/// Clears the temporary files stored for the ClientDependency folder
/// </summary>
/// <param name="currentHttpContext"></param>
public bool ClearTempFiles(HttpContextBase currentHttpContext)
{
var cdfTempDirectories = new HashSet<string>();
foreach (BaseCompositeFileProcessingProvider provider in ClientDependencySettings.Instance
.CompositeFileProcessingProviderCollection)
{
var path = provider.CompositeFilePath.FullName;
cdfTempDirectories.Add(path);
}
try
{
var fullPath = currentHttpContext.Server.MapPath(XmlFileMapper.FileMapDefaultFolder);
if (fullPath != null)
{
cdfTempDirectories.Add(fullPath);
}
}
catch (Exception ex)
{
//invalid path format or something... try/catch to be safe
_logger.Error<ClientDependencyConfiguration>(ex, "Could not get path from ClientDependency.config");
}
var success = true;
foreach (var directory in cdfTempDirectories)
{
var directoryInfo = new DirectoryInfo(directory);
if (directoryInfo.Exists == false)
continue;
try
{
directoryInfo.Delete(true);
}
catch (Exception ex)
{
// Something could be locking the directory or the was another error, making sure we don't break the upgrade installer
_logger.Error<ClientDependencyConfiguration>(ex, "Could not clear temp files");
success = false;
}
}
return success;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using ClientDependency.Core;
using Umbraco.Core.Manifest;
namespace Umbraco.Web.JavaScript
{
internal class CssInitialization : AssetInitialization
{
private readonly ManifestParser _parser;
public CssInitialization(ManifestParser parser)
{
_parser = parser;
}
/// <summary>
/// Processes all found manifest files, and outputs css inject calls for all css files found in all manifests.
/// </summary>
public string GetStylesheetInitialization(HttpContextBase httpContext)
{
var files = GetStylesheetFiles(httpContext);
return WriteScript(files);
}
public IEnumerable<string> GetStylesheetFiles(HttpContextBase httpContext)
{
var stylesheets = new HashSet<string>();
var optimizedManifest = OptimizeAssetCollection(_parser.Manifest.Stylesheets, ClientDependencyType.Css, httpContext);
foreach (var stylesheet in optimizedManifest)
stylesheets.Add(stylesheet);
foreach (var stylesheet in ScanPropertyEditors(ClientDependencyType.Css, httpContext))
stylesheets.Add(stylesheet);
return stylesheets.ToArray();
}
internal static string WriteScript(IEnumerable<string> files)
{
var sb = new StringBuilder();
foreach (var file in files)
sb.AppendFormat("{0}LazyLoad.css('{1}');", Environment.NewLine, file);
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,50 @@
using System.Collections.Generic;
using System.Web;
using ClientDependency.Core;
using ClientDependency.Core.FileRegistration.Providers;
namespace Umbraco.Web.JavaScript
{
/// <summary>
/// A custom renderer that only outputs a dependency path instead of script tags - for use with the js loader with yepnope
/// </summary>
public class DependencyPathRenderer : StandardRenderer
{
public override string Name
{
get { return "Umbraco.DependencyPathRenderer"; }
}
/// <summary>
/// Used to delimit each dependency so we can split later
/// </summary>
public const string Delimiter = "||||";
/// <summary>
/// Override because the StandardRenderer replaces & with &amp; but we don't want that so we'll reverse it
/// </summary>
/// <param name="allDependencies"></param>
/// <param name="paths"></param>
/// <param name="jsOutput"></param>
/// <param name="cssOutput"></param>
/// <param name="http"></param>
public override void RegisterDependencies(List<IClientDependencyFile> allDependencies, HashSet<IClientDependencyPath> paths, out string jsOutput, out string cssOutput, HttpContextBase http)
{
base.RegisterDependencies(allDependencies, paths, out jsOutput, out cssOutput, http);
jsOutput = jsOutput.Replace("&amp;", "&");
cssOutput = cssOutput.Replace("&amp;", "&");
}
protected override string RenderSingleJsFile(string js, IDictionary<string, string> htmlAttributes)
{
return js + Delimiter;
}
protected override string RenderSingleCssFile(string css, IDictionary<string, string> htmlAttributes)
{
return css + Delimiter;
}
}
}

View File

@@ -0,0 +1,153 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using ClientDependency.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.Manifest;
namespace Umbraco.Web.JavaScript
{
/// <summary>
/// Reads from all defined manifests and ensures that any of their initialization is output with the
/// main Umbraco initialization output.
/// </summary>
internal class JsInitialization : AssetInitialization
{
private readonly ManifestParser _parser;
public JsInitialization(ManifestParser parser)
{
_parser = parser;
}
// deal with javascript functions inside of json (not a supported json syntax)
private const string PrefixJavaScriptObject = "@@@@";
private static readonly Regex JsFunctionParser = new Regex($"(\"{PrefixJavaScriptObject}(.*?)\")+",
RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);
// replace tokens in the js main
private static readonly Regex Token = new Regex("(\"##\\w+?##\")", RegexOptions.Compiled);
/// <summary>
/// Gets the JS initialization script to boot the back office application
/// </summary>
/// <param name="httpContext"></param>
/// <param name="scripts"></param>
/// <param name="angularModule">
/// The angular module name to boot
/// </param>
/// <returns></returns>
public static string GetJavascriptInitialization(HttpContextBase httpContext, IEnumerable<string> scripts, string angularModule)
{
var jarray = new StringBuilder();
jarray.AppendLine("[");
var first = true;
foreach (var file in scripts)
{
if (first) first = false;
else jarray.AppendLine(",");
jarray.Append("\"");
jarray.Append(file);
jarray.Append("\"");
}
jarray.Append("]");
return WriteScript(jarray.ToString(), IOHelper.ResolveUrl(SystemDirectories.Umbraco), angularModule);
}
/// <summary>
/// Returns a list of optimized script paths for the back office
/// </summary>
/// <param name="httpContext"></param>
/// <param name="umbracoInit"></param>
/// <param name="additionalJsFiles"></param>
/// <returns>
/// Cache busted/optimized script paths for the back office including manifest and property editor scripts
/// </returns>
/// <remarks>
/// Used to cache bust and optimize script paths for the back office
/// </remarks>
public IEnumerable<string> OptimizeBackOfficeScriptFiles(HttpContextBase httpContext, IEnumerable<string> umbracoInit, IEnumerable<string> additionalJsFiles = null)
{
var scripts = new HashSet<string>();
foreach (var script in umbracoInit)
scripts.Add(script);
foreach (var script in _parser.Manifest.Scripts)
scripts.Add(script);
if (additionalJsFiles != null)
foreach (var script in additionalJsFiles)
scripts.Add(script);
scripts = new HashSet<string>(OptimizeAssetCollection(scripts, ClientDependencyType.Javascript, httpContext));
foreach (var script in ScanPropertyEditors(ClientDependencyType.Javascript, httpContext))
scripts.Add(script);
return scripts.ToArray();
}
/// <summary>
/// Returns a list of optimized script paths
/// </summary>
/// <param name="httpContext"></param>
/// <param name="scriptFiles"></param>
/// <returns></returns>
/// <remarks>
/// Used to cache bust and optimize script paths
/// </remarks>
public static IEnumerable<string> OptimizeScriptFiles(HttpContextBase httpContext, IEnumerable<string> scriptFiles)
{
var scripts = new HashSet<string>();
foreach (var script in scriptFiles)
scripts.Add(script);
scripts = new HashSet<string>(OptimizeAssetCollection(scripts, ClientDependencyType.Javascript, httpContext));
return scripts.ToArray();
}
/// <summary>
/// Returns the default config as a JArray
/// </summary>
/// <returns></returns>
internal static IEnumerable<string> GetDefaultInitialization()
{
var resources = JsonConvert.DeserializeObject<JArray>(Resources.JsInitialize);
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
}
/// <summary>
/// Returns the default config as a JArray
/// </summary>
/// <returns></returns>
internal static IEnumerable<string> GetPreviewInitialization()
{
var resources = JsonConvert.DeserializeObject<JArray>(Resources.PreviewInitialize);
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
}
/// <summary>
/// Parses the JsResources.Main and replaces the replacement tokens accordingly.
/// </summary>
/// <param name="replacements"></param>
/// <returns></returns>
internal static string WriteScript(string scripts, string umbracoPath, string angularModule)
{
var count = 0;
var replacements = new[] { scripts, umbracoPath, angularModule };
// replace, catering for the special syntax when we have
// js function() objects contained in the json
return Token.Replace(Resources.Main, match =>
{
var replacement = replacements[count++];
return JsFunctionParser.Replace(replacement, "$2");
});
}
}
}

View File

@@ -0,0 +1,45 @@
[
'lib/jquery/jquery.min.js',
'lib/jquery-ui/jquery-ui.min.js',
'lib/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js',
'lib/angular/angular.js',
'lib/underscore/underscore-min.js',
'lib/moment/moment.min.js',
'lib/flatpickr/flatpickr.js',
'lib/animejs/anime.min.js',
'lib/angular-route/angular-route.js',
'lib/angular-cookies/angular-cookies.js',
'lib/angular-touch/angular-touch.js',
'lib/angular-sanitize/angular-sanitize.js',
'lib/angular-animate/angular-animate.js',
'lib/angular-messages/angular-messages.js',
'lib/angular-ui-sortable/sortable.js',
'lib/angular-dynamic-locale/tmhDynamicLocale.min.js',
'lib/ng-file-upload/ng-file-upload.min.js',
'lib/angular-local-storage/angular-local-storage.min.js',
'lib/chart.js/chart.min.js',
'lib/angular-chart.js/angular-chart.min.js',
'lib/umbraco/Extensions.js',
'lib/umbraco/NamespaceManager.js',
'lib/umbraco/LegacySpeechBubble.js',
'js/app.js',
'js/umbraco.resources.js',
'js/umbraco.directives.js',
'js/umbraco.filters.js',
'js/umbraco.services.js',
'js/umbraco.interceptors.js',
'js/umbraco.controllers.js',
'js/routes.js',
'js/init.js'
]

View File

@@ -0,0 +1,12 @@
LazyLoad.js("##JsInitialize##", function () {
//we need to set the legacy UmbClientMgr path
if ((typeof UmbClientMgr) !== "undefined") {
UmbClientMgr.setUmbracoPath('"##UmbracoPath##"');
}
jQuery(document).ready(function () {
angular.bootstrap(document, ['"##AngularModule##"']);
});
});

View File

@@ -0,0 +1,14 @@
[
'../lib/jquery/jquery.min.js',
'../lib/angular/angular.js',
'../lib/underscore/underscore-min.js',
'../lib/umbraco/Extensions.js',
'../js/app.js',
'../js/umbraco.resources.js',
'../js/umbraco.services.js',
'../js/umbraco.interceptors.js',
'../ServerVariables',
'../lib/signalr/jquery.signalR.js',
'../BackOffice/signalr/hubs',
'../js/umbraco.preview.js'
]

View File

@@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.JavaScript {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Web.JavaScript.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to [
/// &apos;lib/jquery/jquery.min.js&apos;,
/// &apos;lib/jquery-ui/jquery-ui.min.js&apos;,
/// &apos;lib/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js&apos;,
///
/// &apos;lib/angular/angular.js&apos;,
/// &apos;lib/underscore/underscore-min.js&apos;,
///
/// &apos;lib/moment/moment.min.js&apos;,
/// &apos;lib/flatpickr/flatpickr.js&apos;,
///
/// &apos;lib/animejs/anime.min.js&apos;,
///
/// &apos;lib/angular-route/angular-route.js&apos;,
/// &apos;lib/angular-cookies/angular-cookies.js&apos;,
/// &apos;lib/angular-touch/angular-touch.js&apos;,
/// &apos;lib/angular-sanitize/angular-sanitize.js&apos;,
/// &apos;lib/an [rest of string was truncated]&quot;;.
/// </summary>
internal static string JsInitialize {
get {
return ResourceManager.GetString("JsInitialize", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to LazyLoad.js(&quot;##JsInitialize##&quot;, function () {
/// //we need to set the legacy UmbClientMgr path
/// if ((typeof UmbClientMgr) !== &quot;undefined&quot;) {
/// UmbClientMgr.setUmbracoPath(&apos;&quot;##UmbracoPath##&quot;&apos;);
/// }
///
/// jQuery(document).ready(function () {
///
/// angular.bootstrap(document, [&apos;&quot;##AngularModule##&quot;&apos;]);
///
/// });
///});
///.
/// </summary>
internal static string Main {
get {
return ResourceManager.GetString("Main", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [
/// &apos;../lib/jquery/jquery.min.js&apos;,
/// &apos;../lib/angular/angular.js&apos;,
/// &apos;../lib/underscore/underscore-min.js&apos;,
/// &apos;../lib/umbraco/Extensions.js&apos;,
/// &apos;../js/app.js&apos;,
/// &apos;../js/umbraco.resources.js&apos;,
/// &apos;../js/umbraco.services.js&apos;,
/// &apos;../js/umbraco.interceptors.js&apos;,
/// &apos;../ServerVariables&apos;,
/// &apos;../lib/signalr/jquery.signalR.js&apos;,
/// &apos;../BackOffice/signalr/hubs&apos;,
/// &apos;../js/umbraco.preview.js&apos;
///]
///.
/// </summary>
internal static string PreviewInitialize {
get {
return ResourceManager.GetString("PreviewInitialize", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to // TODO: This would be nicer as an angular module so it can be injected into stuff... that&apos;d be heaps nicer, but
///// how to do that when this is not a regular JS file, it is a server side JS file and RequireJS seems to only want
///// to force load JS files ?
///
/////create the namespace (NOTE: This loads before any dependencies so we don&apos;t have a namespace mgr so we just create it manually)
///var Umbraco = {};
///Umbraco.Sys = {};
/////define a global static object
///Umbraco.Sys.ServerVariables = ##Variables## ;.
/// </summary>
internal static string ServerVariables {
get {
return ResourceManager.GetString("ServerVariables", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to stop persisting the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="JsInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>jsinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Main" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Main.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="PreviewInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>previewinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="ServerVariables" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>servervariables.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@@ -0,0 +1,9 @@
// TODO: This would be nicer as an angular module so it can be injected into stuff... that'd be heaps nicer, but
// how to do that when this is not a regular JS file, it is a server side JS file and RequireJS seems to only want
// to force load JS files ?
//create the namespace (NOTE: This loads before any dependencies so we don't have a namespace mgr so we just create it manually)
var Umbraco = {};
Umbraco.Sys = {};
//define a global static object
Umbraco.Sys.ServerVariables = ##Variables## ;

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
namespace Umbraco.Web.JavaScript
{
public sealed class ServerVariablesParser
{
/// <summary>
/// Allows developers to add custom variables on parsing
/// </summary>
public static event EventHandler<Dictionary<string, object>> Parsing;
internal const string Token = "##Variables##";
internal static string Parse(Dictionary<string, object> items)
{
var vars = Resources.ServerVariables;
//Raise event for developers to add custom variables
if (Parsing != null)
{
Parsing(null, items);
}
var json = JObject.FromObject(items);
return vars.Replace(Token, json.ToString());
}
}
}

View File

@@ -0,0 +1,43 @@
using System.Web.UI;
using ClientDependency.Core.Controls;
using ClientDependency.Core.FileRegistration.Providers;
using Umbraco.Core.IO;
namespace Umbraco.Web.JavaScript
{
/// <summary>
/// Used to load in all client dependencies for Umbraco.
/// Ensures that both UmbracoClient and UmbracoRoot paths are added to the loader.
/// </summary>
public class UmbracoClientDependencyLoader : ClientDependencyLoader
{
/// <summary>
/// Set the defaults
/// </summary>
public UmbracoClientDependencyLoader()
: base()
{
this.AddPath("UmbracoRoot", IOHelper.ResolveUrl(SystemDirectories.Umbraco));
this.ProviderName = LoaderControlProvider.DefaultName;
}
public static ClientDependencyLoader TryCreate(Control parent, out bool isNew)
{
if (ClientDependencyLoader.Instance == null)
{
var loader = new UmbracoClientDependencyLoader();
parent.Controls.Add(loader);
isNew = true;
return loader;
}
else
{
isNew = false;
return ClientDependencyLoader.Instance;
}
}
}
}