322 lines
13 KiB
C#
322 lines
13 KiB
C#
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Net;
|
|||
|
|
using System.Net.Http;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Web.Http;
|
|||
|
|
using AutoMapper;
|
|||
|
|
using Umbraco.Web.Models.ContentEditing;
|
|||
|
|
using Umbraco.Web.Mvc;
|
|||
|
|
using umbraco;
|
|||
|
|
using Umbraco.Web.WebApi;
|
|||
|
|
using System;
|
|||
|
|
using System.Net.Http.Headers;
|
|||
|
|
using System.Web;
|
|||
|
|
using System.IO;
|
|||
|
|
using Umbraco.Core;
|
|||
|
|
using Umbraco.Core.Models;
|
|||
|
|
using Umbraco.Core.Services;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text.RegularExpressions;
|
|||
|
|
|
|||
|
|
namespace Umbraco.Web
|
|||
|
|
{
|
|||
|
|
internal static class TuningUtility
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
internal static string assetBasePath = HttpContext.Current.Server.MapPath(@"\Umbraco\assets\less\");
|
|||
|
|
internal static string tuningDefaultLessPath = assetBasePath + @"tuning.defaultStyle.less";
|
|||
|
|
internal static string tuningGridRowStyle = assetBasePath + @"tuning.gridRowStyle.less";
|
|||
|
|
internal static string tuningStylePath = "/Css/tuning/";
|
|||
|
|
internal static string resultLessPath = tuningStylePath + @"{0}.less";
|
|||
|
|
internal static string resultCssPath = tuningStylePath + @"{0}.css";
|
|||
|
|
internal static string frontBasePath = HttpContext.Current.Server.MapPath(@"\Css\tuning\");
|
|||
|
|
|
|||
|
|
// return the list of all grid's rows' guid for the current page
|
|||
|
|
internal static String[] GetGridRows(int pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
List<string> result = new List<string>();
|
|||
|
|
|
|||
|
|
// Load current page
|
|||
|
|
var contentService = ApplicationContext.Current.Services.ContentService;
|
|||
|
|
IContent content = contentService.GetById(pageId);
|
|||
|
|
|
|||
|
|
// Look after grid properies into the current page
|
|||
|
|
foreach (var property in content.Properties)
|
|||
|
|
{
|
|||
|
|
if (property.PropertyType.PropertyEditorAlias == "Umbraco.Grid" && !string.IsNullOrEmpty(property.Value.ToString()))
|
|||
|
|
{
|
|||
|
|
dynamic grid = Newtonsoft.Json.Linq.JObject.Parse(property.Value.ToString());
|
|||
|
|
foreach (var column in grid.columns)
|
|||
|
|
{
|
|||
|
|
foreach (var row in column.rows)
|
|||
|
|
{
|
|||
|
|
if (row.uniqueId != null)
|
|||
|
|
result.Add(row.uniqueId.Value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result.ToArray();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// get style box by tag
|
|||
|
|
internal static String GetStyleBlock(string source, string name)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
string startTag = string.Format("/***start-{0}***/", name);
|
|||
|
|
string endTag = string.Format("/***end-{0}***/", name);
|
|||
|
|
|
|||
|
|
int indexStartTag = source.IndexOf(startTag);
|
|||
|
|
int indexEndTag = source.IndexOf(endTag);
|
|||
|
|
|
|||
|
|
if (indexStartTag >= 0 && indexEndTag >= 0)
|
|||
|
|
return source.Substring(indexStartTag, indexEndTag - indexStartTag).Replace(startTag, "").Replace(endTag, "");
|
|||
|
|
else
|
|||
|
|
return "";
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Create a new grid block
|
|||
|
|
internal static string NewGridRowBlock(string name)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
string lessGridRowModel = string.Empty;
|
|||
|
|
using (System.IO.StreamReader sr = new System.IO.StreamReader(tuningGridRowStyle))
|
|||
|
|
{
|
|||
|
|
lessGridRowModel = sr.ReadToEnd();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
string newTag = "gridrow_" + name;
|
|||
|
|
|
|||
|
|
return lessGridRowModel.Replace("-ID-", newTag);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get less parameters from lessPath file, both general parameters and grid parameters
|
|||
|
|
internal static string GetLessParameters(string lessPath, int pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// Get all parameters
|
|||
|
|
string paramBlock = string.Empty;
|
|||
|
|
if (System.IO.File.Exists(lessPath))
|
|||
|
|
{
|
|||
|
|
using (System.IO.StreamReader sr = new System.IO.StreamReader(lessPath))
|
|||
|
|
{
|
|||
|
|
string lessContent = sr.ReadToEnd();
|
|||
|
|
paramBlock = GetStyleBlock(lessContent, "lessParam");
|
|||
|
|
foreach (var gridRow in GetGridRows(pageId))
|
|||
|
|
{
|
|||
|
|
paramBlock = paramBlock + GetStyleBlock(lessContent, "lessParam-" + "gridrow_" + gridRow);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return paramBlock;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get inherited pageId with tuning
|
|||
|
|
internal static int GetParentOrSelfTunedPageId(string[] path, bool preview)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
string styleTuning = preview ? @"{0}{1}.less" : "{0}{1}.css";
|
|||
|
|
foreach (var page in path.OrderByDescending(r => path.IndexOf(r)))
|
|||
|
|
{
|
|||
|
|
string stylePath = HttpContext.Current.Server.MapPath(string.Format(styleTuning, tuningStylePath, page));
|
|||
|
|
if (System.IO.File.Exists(stylePath))
|
|||
|
|
{
|
|||
|
|
return int.Parse(page);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return int.Parse(path[path.Length - 1]);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get stylesheet path for current page
|
|||
|
|
internal static string GetStylesheetPath(string[] path, bool preview)
|
|||
|
|
{
|
|||
|
|
string styleTuning = preview ? @"{0}{1}.less" : "{0}{1}.css";
|
|||
|
|
return string.Format(styleTuning, tuningStylePath, GetParentOrSelfTunedPageId(path, preview));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Create new less file
|
|||
|
|
internal static string CreateOrUpdateLessFile(string[] path, int pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
string lessPath = GetStylesheetPath(path, true);
|
|||
|
|
|
|||
|
|
// If less file exist, Load its content
|
|||
|
|
string lessContent = string.Empty;
|
|||
|
|
using (System.IO.StreamReader sr = new System.IO.StreamReader(System.IO.File.Exists(HttpContext.Current.Server.MapPath(lessPath))
|
|||
|
|
? HttpContext.Current.Server.MapPath(lessPath) : tuningDefaultLessPath))
|
|||
|
|
{
|
|||
|
|
lessContent = sr.ReadToEnd();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Update with grid row style needs
|
|||
|
|
string[] gridRows = TuningUtility.GetGridRows(pageId);
|
|||
|
|
string parametersToAdd = string.Empty;
|
|||
|
|
string styleToAdd = string.Empty;
|
|||
|
|
foreach (var gridRow in gridRows)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(GetStyleBlock(lessContent, "gridStyle-" + "gridrow_" + gridRow)))
|
|||
|
|
{
|
|||
|
|
parametersToAdd += NewGridRowBlock(gridRow);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save less file
|
|||
|
|
if (string.IsNullOrEmpty(lessPath)) lessPath = string.Format("{0}{1}.less", tuningStylePath, pageId);
|
|||
|
|
lessContent = lessContent + Environment.NewLine + parametersToAdd;
|
|||
|
|
using (System.IO.StreamWriter file = new System.IO.StreamWriter(HttpContext.Current.Server.MapPath(lessPath)))
|
|||
|
|
{
|
|||
|
|
file.Write(lessContent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return lessPath;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save and publish less style
|
|||
|
|
internal static void SaveAndPublishStyle(string parameters, string parametersGrid, int pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// Get inherited tuned pageId and path
|
|||
|
|
var contentService = ApplicationContext.Current.Services.ContentService;
|
|||
|
|
IContent content = contentService.GetById(pageId);
|
|||
|
|
int inheritedTunedPageId = TuningUtility.GetParentOrSelfTunedPageId(content.Path.Split(','), true);
|
|||
|
|
|
|||
|
|
// Load inherited Less content
|
|||
|
|
string inheritedLessContent = string.Empty;
|
|||
|
|
using (System.IO.StreamReader sr = new System.IO.StreamReader(HttpContext.Current.Server.MapPath(string.Format(resultLessPath, inheritedTunedPageId))))
|
|||
|
|
{
|
|||
|
|
inheritedLessContent = sr.ReadToEnd();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Update pageId if parameters have changed
|
|||
|
|
if (inheritedTunedPageId != pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// Parse inherited less parameters
|
|||
|
|
Dictionary<string, string> dicInheritedParameters = new Dictionary<string, string>();
|
|||
|
|
foreach (Match m in Regex.Matches(GetStyleBlock(inheritedLessContent,"lessParam"), @"@([^:\s\n]*?):([^@;\n]*?);"))
|
|||
|
|
{
|
|||
|
|
if (m.Groups.Count > 2)
|
|||
|
|
{
|
|||
|
|
dicInheritedParameters.Add(m.Groups[1].Value, m.Groups[2].Value.Replace("''", string.Empty));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Read new parameters
|
|||
|
|
Dictionary<string, string> dicNewParameters = new Dictionary<string, string>();
|
|||
|
|
foreach (string parameter in parameters.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
|
|||
|
|
{
|
|||
|
|
if (parameter.IndexOf("@import") < 0)
|
|||
|
|
{
|
|||
|
|
string name = parameter.Substring(1, parameter.IndexOf(":")).Replace("@", string.Empty).Replace(":", string.Empty);
|
|||
|
|
string value = parameter.Substring(parameter.IndexOf(":") + 1);
|
|||
|
|
dicNewParameters.Add(name, value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Compare if parameters have changed
|
|||
|
|
bool noChange = true;
|
|||
|
|
foreach (string keys in dicNewParameters.Keys)
|
|||
|
|
{
|
|||
|
|
if (!dicInheritedParameters.Keys.Where(r => r == keys).Any() || dicNewParameters[keys] != dicInheritedParameters[keys])
|
|||
|
|
{
|
|||
|
|
noChange = false;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (noChange)
|
|||
|
|
pageId = inheritedTunedPageId;
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Compare if parameters have changed
|
|||
|
|
if (dicInheritedParameters.OrderBy(r => r.Key).SequenceEqual(dicNewParameters.OrderBy(r => r.Key)))
|
|||
|
|
pageId = inheritedTunedPageId;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Create front directory if necesary
|
|||
|
|
if (!Directory.Exists(frontBasePath))
|
|||
|
|
Directory.CreateDirectory(frontBasePath);
|
|||
|
|
|
|||
|
|
// Prepare parameters and gf block and replace with the new value
|
|||
|
|
string newParamBlock = string.Empty;
|
|||
|
|
string newGfBlock = string.Empty;
|
|||
|
|
foreach (string parameter in parameters.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
|
|||
|
|
{
|
|||
|
|
if (parameter.IndexOf("@import") < 0)
|
|||
|
|
{
|
|||
|
|
newParamBlock += (parameter + ";").Replace(":;", ":'';") + Environment.NewLine;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
newGfBlock += parameter + ";" + Environment.NewLine;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
inheritedLessContent = inheritedLessContent.Replace(GetStyleBlock(inheritedLessContent, "lessParam"), Environment.NewLine + newParamBlock);
|
|||
|
|
inheritedLessContent = inheritedLessContent.Replace(GetStyleBlock(inheritedLessContent, "gf"), Environment.NewLine + newGfBlock);
|
|||
|
|
|
|||
|
|
// Prepare grid parameters
|
|||
|
|
string newGridParamBlock = string.Empty;
|
|||
|
|
foreach (string parameter in parametersGrid.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
|
|||
|
|
{
|
|||
|
|
string name = parameter.Substring(0, parameter.IndexOf(":"));
|
|||
|
|
string value = parameter.Substring(parameter.IndexOf(":") + 1);
|
|||
|
|
if (string.IsNullOrEmpty(value)) value = "''";
|
|||
|
|
inheritedLessContent = Regex.Replace(inheritedLessContent, string.Format("{0}:([^;\n]*);", name), string.Format("{0}:{1};", name, value));
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save less file
|
|||
|
|
using (System.IO.StreamWriter file = new System.IO.StreamWriter(HttpContext.Current.Server.MapPath(string.Format(resultLessPath, pageId))))
|
|||
|
|
{
|
|||
|
|
file.Write(inheritedLessContent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Compile the Less file
|
|||
|
|
string compiledStyle = GetCssFromLessString(inheritedLessContent, false, true, true).Replace("@import", "@IMPORT");
|
|||
|
|
|
|||
|
|
// Save compiled file
|
|||
|
|
using (System.IO.StreamWriter file = new System.IO.StreamWriter(HttpContext.Current.Server.MapPath(string.Format(resultCssPath, pageId))))
|
|||
|
|
{
|
|||
|
|
file.Write(compiledStyle);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Delete tuning style
|
|||
|
|
internal static void DeleteStyle(int pageId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// Path to the less and css files
|
|||
|
|
string newResultLessPath = HttpContext.Current.Server.MapPath(string.Format(resultLessPath, pageId));
|
|||
|
|
string newResultCssPath = HttpContext.Current.Server.MapPath(string.Format(resultCssPath, pageId));
|
|||
|
|
|
|||
|
|
// Delete all style file for this page
|
|||
|
|
System.IO.File.Delete(newResultLessPath);
|
|||
|
|
System.IO.File.Delete(newResultCssPath);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Compile and compress less style
|
|||
|
|
private static string GetCssFromLessString(string css, Boolean cacheEnabled, Boolean minifyOutput, Boolean disableVariableRedefines)
|
|||
|
|
{
|
|||
|
|
var config = dotless.Core.configuration.DotlessConfiguration.GetDefaultWeb();
|
|||
|
|
config.DisableVariableRedefines = disableVariableRedefines;
|
|||
|
|
config.CacheEnabled = cacheEnabled;
|
|||
|
|
config.MinifyOutput = minifyOutput;
|
|||
|
|
return dotless.Core.LessWeb.Parse(css, config);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|