");
+ }
+
+ string protocol = GlobalSettings.UseSSL ? "https" : "http";
+
+
+ string[] subjectVars = {
+ http.Request.ServerVariables["SERVER_NAME"] + ":" +
+ http.Request.Url.Port +
+ IOHelper.ResolveUrl(SystemDirectories.Umbraco),
+ actionName,
+ content.Name
+ };
+ string[] bodyVars = {
+ mailingUser.Name,
+ actionName,
+ content.Name,
+ performingUser.Name,
+ http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port + IOHelper.ResolveUrl(SystemDirectories.Umbraco),
+ content.Id.ToString(CultureInfo.InvariantCulture), summary.ToString(),
+ string.Format("{2}://{0}/{1}",
+ http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port,
+ //TODO: RE-enable this so we can have a nice url
+ /*umbraco.library.NiceUrl(documentObject.Id))*/
+ content.Id + ".aspx",
+ protocol)
+
+ };
+
+ // create the mail message
+ var mail = new MailMessage(UmbracoSettings.NotificationEmailSender, mailingUser.Email);
+
+ // populate the message
+ mail.Subject = createSubject(mailingUser, subjectVars);
+ //mail.Subject = ui.Text("notifications", "mailSubject", subjectVars, mailingUser);
+ if (UmbracoSettings.NotificationDisableHtmlEmail)
+ {
+ mail.IsBodyHtml = false;
+ //mail.Body = ui.Text("notifications", "mailBody", bodyVars, mailingUser);
+ mail.Body = createBody(mailingUser, bodyVars);
+ }
+ else
+ {
+ mail.IsBodyHtml = true;
+ mail.Body =
+ @"
+
+
+" + createBody(mailingUser, bodyVars);
+ //ui.Text("notifications", "mailBodyHtml", bodyVars, mailingUser) + "";
+ }
+
+ // nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here
+ // adding the server name to make sure we don't replace external links
+ if (GlobalSettings.UseSSL && string.IsNullOrEmpty(mail.Body) == false)
+ {
+ string serverName = http.Request.ServerVariables["SERVER_NAME"];
+ mail.Body = mail.Body.Replace(
+ string.Format("http://{0}", serverName),
+ string.Format("https://{0}", serverName));
+ }
+
+ // send it
+ var sender = new SmtpClient();
+ sender.Send(mail);
+ }
+
+ private static string ReplaceLinks(string text, HttpRequestBase request)
+ {
+ string domain = GlobalSettings.UseSSL ? "https://" : "http://";
+ domain += request.ServerVariables["SERVER_NAME"] + ":" + request.Url.Port + "/";
+ text = text.Replace("href=\"/", "href=\"" + domain);
+ text = text.Replace("src=\"/", "src=\"" + domain);
+ return text;
+ }
+
+ ///
+ /// Replaces the HTML symbols with the character equivalent.
+ ///
+ /// The old string.
+ private static void ReplaceHtmlSymbols(ref string oldString)
+ {
+ oldString = oldString.Replace(" ", " ");
+ oldString = oldString.Replace("’", "'");
+ oldString = oldString.Replace("&", "&");
+ oldString = oldString.Replace("“", "“");
+ oldString = oldString.Replace("”", "”");
+ oldString = oldString.Replace(""", "\"");
+ }
+
+ ///
+ /// Compares the text.
+ ///
+ /// The old text.
+ /// The new text.
+ /// if set to true [display inserted text].
+ /// if set to true [display deleted text].
+ /// The inserted style.
+ /// The deleted style.
+ ///
+ private static string CompareText(string oldText, string newText, bool displayInsertedText,
+ bool displayDeletedText, string insertedStyle, string deletedStyle)
+ {
+ var sb = new StringBuilder();
+ var diffs = Diff.DiffText1(oldText, newText);
+
+ int pos = 0;
+ for (int n = 0; n < diffs.Length; n++)
+ {
+ Diff.Item it = diffs[n];
+
+ // write unchanged chars
+ while ((pos < it.StartB) && (pos < newText.Length))
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+
+ // write deleted chars
+ if (displayDeletedText && it.DeletedA > 0)
+ {
+ sb.Append(deletedStyle);
+ for (int m = 0; m < it.DeletedA; m++)
+ {
+ sb.Append(oldText[it.StartA + m]);
+ } // for
+ sb.Append("");
+ }
+
+ // write inserted chars
+ if (displayInsertedText && pos < it.StartB + it.InsertedB)
+ {
+ sb.Append(insertedStyle);
+ while (pos < it.StartB + it.InsertedB)
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+ sb.Append("");
+ } // if
+ } // while
+
+ // write rest of unchanged chars
+ while (pos < newText.Length)
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+
+ return sb.ToString();
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index ffce7b42ba..c57081f51a 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Services
//private Lazy _sectionService;
//private Lazy _macroService;
private Lazy _memberTypeService;
+ private Lazy _notificationService;
///
/// public ctor - will generally just be used for unit testing
@@ -98,6 +99,9 @@ namespace Umbraco.Core.Services
var provider = dbUnitOfWorkProvider;
var fileProvider = fileUnitOfWorkProvider;
+ if (_notificationService == null)
+ _notificationService = new Lazy(() => new NotificationService(provider, _userService.Value, _contentService.Value));
+
if (_serverRegistrationService == null)
_serverRegistrationService = new Lazy(() => new ServerRegistrationService(provider, repositoryFactory.Value));
@@ -148,6 +152,14 @@ namespace Umbraco.Core.Services
}
+ ///
+ /// Gets the
+ ///
+ internal INotificationService NotificationService
+ {
+ get { return _notificationService.Value; }
+ }
+
///
/// Gets the
///
diff --git a/src/Umbraco.Core/Strings/Diff.cs b/src/Umbraco.Core/Strings/Diff.cs
new file mode 100644
index 0000000000..ed381d4f6f
--- /dev/null
+++ b/src/Umbraco.Core/Strings/Diff.cs
@@ -0,0 +1,510 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Umbraco.Core.Strings
+{
+ ///
+ /// This Class implements the Difference Algorithm published in
+ /// "An O(ND) Difference Algorithm and its Variations" by Eugene Myers
+ /// Algorithmica Vol. 1 No. 2, 1986, p 251.
+ ///
+ /// The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
+ /// each line is converted into a (hash) number. See DiffText().
+ ///
+ /// diff.cs: A port of the algorithm to C#
+ /// Copyright (c) by Matthias Hertel, http://www.mathertel.de
+ /// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
+ ///
+ internal class Diff
+ {
+ /// Data on one input file being compared.
+ ///
+ internal class DiffData
+ {
+
+ /// Number of elements (lines).
+ internal int Length;
+
+ /// Buffer of numbers that will be compared.
+ internal int[] Data;
+
+ ///
+ /// Array of booleans that flag for modified data.
+ /// This is the result of the diff.
+ /// This means deletedA in the first Data or inserted in the second Data.
+ ///
+ internal bool[] Modified;
+
+ ///
+ /// Initialize the Diff-Data buffer.
+ ///
+ /// reference to the buffer
+ internal DiffData(int[] initData)
+ {
+ Data = initData;
+ Length = initData.Length;
+ Modified = new bool[Length + 2];
+ } // DiffData
+
+ } // class DiffData
+
+ /// details of one difference.
+ public struct Item
+ {
+ /// Start Line number in Data A.
+ public int StartA;
+ /// Start Line number in Data B.
+ public int StartB;
+
+ /// Number of changes in Data A.
+ public int DeletedA;
+ /// Number of changes in Data B.
+ public int InsertedB;
+ } // Item
+
+ ///
+ /// Shortest Middle Snake Return Data
+ ///
+ private struct Smsrd
+ {
+ internal int X, Y;
+ // internal int u, v; // 2002.09.20: no need for 2 points
+ }
+
+ ///
+ /// Find the difference in 2 texts, comparing by textlines.
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText(string textA, string textB)
+ {
+ return (DiffText(textA, textB, false, false, false));
+ } // DiffText
+
+ ///
+ /// Find the difference in 2 texts, comparing by textlines.
+ /// This method uses the DiffInt internally by 1st converting the string into char codes
+ /// then uses the diff int method
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText1(string textA, string textB)
+ {
+ return DiffInt(DiffCharCodes(textA, false), DiffCharCodes(textB, false));
+ }
+
+
+ ///
+ /// Find the difference in 2 text documents, comparing by textlines.
+ /// The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
+ /// each line is converted into a (hash) number. This hash-value is computed by storing all
+ /// textlines into a common hashtable so i can find dublicates in there, and generating a
+ /// new number each time a new textline is inserted.
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// When set to true, all leading and trailing whitespace characters are stripped out before the comparation is done.
+ /// When set to true, all whitespace characters are converted to a single space character before the comparation is done.
+ /// When set to true, all characters are converted to their lowercase equivivalence before the comparation is done.
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText(string textA, string textB, bool trimSpace, bool ignoreSpace, bool ignoreCase)
+ {
+ // prepare the input-text and convert to comparable numbers.
+ var h = new Hashtable(textA.Length + textB.Length);
+
+ // The A-Version of the data (original data) to be compared.
+ var dataA = new DiffData(DiffCodes(textA, h, trimSpace, ignoreSpace, ignoreCase));
+
+ // The B-Version of the data (modified data) to be compared.
+ var dataB = new DiffData(DiffCodes(textB, h, trimSpace, ignoreSpace, ignoreCase));
+
+ h = null; // free up hashtable memory (maybe)
+
+ var max = dataA.Length + dataB.Length + 1;
+ // vector for the (0,0) to (x,y) search
+ var downVector = new int[2 * max + 2];
+ // vector for the (u,v) to (N,M) search
+ var upVector = new int[2 * max + 2];
+
+ Lcs(dataA, 0, dataA.Length, dataB, 0, dataB.Length, downVector, upVector);
+
+ Optimize(dataA);
+ Optimize(dataB);
+ return CreateDiffs(dataA, dataB);
+ } // DiffText
+
+
+ ///
+ /// Diffs the char codes.
+ ///
+ /// A text.
+ /// if set to true [ignore case].
+ ///
+ private static int[] DiffCharCodes(string aText, bool ignoreCase)
+ {
+ if (ignoreCase)
+ aText = aText.ToUpperInvariant();
+
+ var codes = new int[aText.Length];
+
+ for (int n = 0; n < aText.Length; n++)
+ codes[n] = (int)aText[n];
+
+ return (codes);
+ } // DiffCharCodes
+
+ ///
+ /// If a sequence of modified lines starts with a line that contains the same content
+ /// as the line that appends the changes, the difference sequence is modified so that the
+ /// appended line and not the starting line is marked as modified.
+ /// This leads to more readable diff sequences when comparing text files.
+ ///
+ /// A Diff data buffer containing the identified changes.
+ private static void Optimize(DiffData data)
+ {
+ var startPos = 0;
+ while (startPos < data.Length)
+ {
+ while ((startPos < data.Length) && (data.Modified[startPos] == false))
+ startPos++;
+ int endPos = startPos;
+ while ((endPos < data.Length) && (data.Modified[endPos] == true))
+ endPos++;
+
+ if ((endPos < data.Length) && (data.Data[startPos] == data.Data[endPos]))
+ {
+ data.Modified[startPos] = false;
+ data.Modified[endPos] = true;
+ }
+ else
+ {
+ startPos = endPos;
+ } // if
+ } // while
+ } // Optimize
+
+
+ ///
+ /// Find the difference in 2 arrays of integers.
+ ///
+ /// A-version of the numbers (usualy the old one)
+ /// B-version of the numbers (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffInt(int[] arrayA, int[] arrayB)
+ {
+ // The A-Version of the data (original data) to be compared.
+ var dataA = new DiffData(arrayA);
+
+ // The B-Version of the data (modified data) to be compared.
+ var dataB = new DiffData(arrayB);
+
+ var max = dataA.Length + dataB.Length + 1;
+ // vector for the (0,0) to (x,y) search
+ var downVector = new int[2 * max + 2];
+ // vector for the (u,v) to (N,M) search
+ var upVector = new int[2 * max + 2];
+
+ Lcs(dataA, 0, dataA.Length, dataB, 0, dataB.Length, downVector, upVector);
+ return CreateDiffs(dataA, dataB);
+ } // Diff
+
+
+ ///
+ /// This function converts all textlines of the text into unique numbers for every unique textline
+ /// so further work can work only with simple numbers.
+ ///
+ /// the input text
+ /// This extern initialized hashtable is used for storing all ever used textlines.
+ /// ignore leading and trailing space characters
+ ///
+ ///
+ /// a array of integers.
+ private static int[] DiffCodes(string aText, IDictionary h, bool trimSpace, bool ignoreSpace, bool ignoreCase)
+ {
+ // get all codes of the text
+ var lastUsedCode = h.Count;
+
+ // strip off all cr, only use lf as textline separator.
+ aText = aText.Replace("\r", "");
+ var lines = aText.Split('\n');
+
+ var codes = new int[lines.Length];
+
+ for (int i = 0; i < lines.Length; ++i)
+ {
+ string s = lines[i];
+ if (trimSpace)
+ s = s.Trim();
+
+ if (ignoreSpace)
+ {
+ s = Regex.Replace(s, "\\s+", " "); // TODO: optimization: faster blank removal.
+ }
+
+ if (ignoreCase)
+ s = s.ToLower();
+
+ object aCode = h[s];
+ if (aCode == null)
+ {
+ lastUsedCode++;
+ h[s] = lastUsedCode;
+ codes[i] = lastUsedCode;
+ }
+ else
+ {
+ codes[i] = (int)aCode;
+ } // if
+ } // for
+ return (codes);
+ } // DiffCodes
+
+
+ ///
+ /// This is the algorithm to find the Shortest Middle Snake (SMS).
+ ///
+ /// sequence A
+ /// lower bound of the actual range in DataA
+ /// upper bound of the actual range in DataA (exclusive)
+ /// sequence B
+ /// lower bound of the actual range in DataB
+ /// upper bound of the actual range in DataB (exclusive)
+ /// a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+ /// a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+ /// a MiddleSnakeData record containing x,y and u,v
+ private static Smsrd Sms(DiffData dataA, int lowerA, int upperA, DiffData dataB, int lowerB, int upperB, int[] downVector, int[] upVector)
+ {
+ int max = dataA.Length + dataB.Length + 1;
+
+ int downK = lowerA - lowerB; // the k-line to start the forward search
+ int upK = upperA - upperB; // the k-line to start the reverse search
+
+ int delta = (upperA - lowerA) - (upperB - lowerB);
+ bool oddDelta = (delta & 1) != 0;
+
+ // The vectors in the publication accepts negative indexes. the vectors implemented here are 0-based
+ // and are access using a specific offset: UpOffset UpVector and DownOffset for DownVektor
+ int downOffset = max - downK;
+ int upOffset = max - upK;
+
+ int maxD = ((upperA - lowerA + upperB - lowerB) / 2) + 1;
+
+ // Debug.Write(2, "SMS", String.Format("Search the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
+
+ // init vectors
+ downVector[downOffset + downK + 1] = lowerA;
+ upVector[upOffset + upK - 1] = upperA;
+
+ for (int d = 0; d <= maxD; d++)
+ {
+
+ // Extend the forward path.
+ Smsrd ret;
+ for (int k = downK - d; k <= downK + d; k += 2)
+ {
+ // Debug.Write(0, "SMS", "extend forward path " + k.ToString());
+
+ // find the only or better starting point
+ int x, y;
+ if (k == downK - d)
+ {
+ x = downVector[downOffset + k + 1]; // down
+ }
+ else
+ {
+ x = downVector[downOffset + k - 1] + 1; // a step to the right
+ if ((k < downK + d) && (downVector[downOffset + k + 1] >= x))
+ x = downVector[downOffset + k + 1]; // down
+ }
+ y = x - k;
+
+ // find the end of the furthest reaching forward D-path in diagonal k.
+ while ((x < upperA) && (y < upperB) && (dataA.Data[x] == dataB.Data[y]))
+ {
+ x++; y++;
+ }
+ downVector[downOffset + k] = x;
+
+ // overlap ?
+ if (oddDelta && (upK - d < k) && (k < upK + d))
+ {
+ if (upVector[upOffset + k] <= downVector[downOffset + k])
+ {
+ ret.X = downVector[downOffset + k];
+ ret.Y = downVector[downOffset + k] - k;
+ // ret.u = UpVector[UpOffset + k]; // 2002.09.20: no need for 2 points
+ // ret.v = UpVector[UpOffset + k] - k;
+ return (ret);
+ } // if
+ } // if
+
+ } // for k
+
+ // Extend the reverse path.
+ for (int k = upK - d; k <= upK + d; k += 2)
+ {
+ // Debug.Write(0, "SMS", "extend reverse path " + k.ToString());
+
+ // find the only or better starting point
+ int x, y;
+ if (k == upK + d)
+ {
+ x = upVector[upOffset + k - 1]; // up
+ }
+ else
+ {
+ x = upVector[upOffset + k + 1] - 1; // left
+ if ((k > upK - d) && (upVector[upOffset + k - 1] < x))
+ x = upVector[upOffset + k - 1]; // up
+ } // if
+ y = x - k;
+
+ while ((x > lowerA) && (y > lowerB) && (dataA.Data[x - 1] == dataB.Data[y - 1]))
+ {
+ x--; y--; // diagonal
+ }
+ upVector[upOffset + k] = x;
+
+ // overlap ?
+ if (!oddDelta && (downK - d <= k) && (k <= downK + d))
+ {
+ if (upVector[upOffset + k] <= downVector[downOffset + k])
+ {
+ ret.X = downVector[downOffset + k];
+ ret.Y = downVector[downOffset + k] - k;
+ // ret.u = UpVector[UpOffset + k]; // 2002.09.20: no need for 2 points
+ // ret.v = UpVector[UpOffset + k] - k;
+ return (ret);
+ } // if
+ } // if
+
+ } // for k
+
+ } // for D
+
+ throw new ApplicationException("the algorithm should never come here.");
+ } // SMS
+
+
+ ///
+ /// This is the divide-and-conquer implementation of the longes common-subsequence (LCS)
+ /// algorithm.
+ /// The published algorithm passes recursively parts of the A and B sequences.
+ /// To avoid copying these arrays the lower and upper bounds are passed while the sequences stay constant.
+ ///
+ /// sequence A
+ /// lower bound of the actual range in DataA
+ /// upper bound of the actual range in DataA (exclusive)
+ /// sequence B
+ /// lower bound of the actual range in DataB
+ /// upper bound of the actual range in DataB (exclusive)
+ /// a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+ /// a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+ private static void Lcs(DiffData dataA, int lowerA, int upperA, DiffData dataB, int lowerB, int upperB, int[] downVector, int[] upVector)
+ {
+ // Debug.Write(2, "LCS", String.Format("Analyse the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
+
+ // Fast walkthrough equal lines at the start
+ while (lowerA < upperA && lowerB < upperB && dataA.Data[lowerA] == dataB.Data[lowerB])
+ {
+ lowerA++; lowerB++;
+ }
+
+ // Fast walkthrough equal lines at the end
+ while (lowerA < upperA && lowerB < upperB && dataA.Data[upperA - 1] == dataB.Data[upperB - 1])
+ {
+ --upperA; --upperB;
+ }
+
+ if (lowerA == upperA)
+ {
+ // mark as inserted lines.
+ while (lowerB < upperB)
+ dataB.Modified[lowerB++] = true;
+
+ }
+ else if (lowerB == upperB)
+ {
+ // mark as deleted lines.
+ while (lowerA < upperA)
+ dataA.Modified[lowerA++] = true;
+
+ }
+ else
+ {
+ // Find the middle snakea and length of an optimal path for A and B
+ Smsrd smsrd = Sms(dataA, lowerA, upperA, dataB, lowerB, upperB, downVector, upVector);
+ // Debug.Write(2, "MiddleSnakeData", String.Format("{0},{1}", smsrd.x, smsrd.y));
+
+ // The path is from LowerX to (x,y) and (x,y) to UpperX
+ Lcs(dataA, lowerA, smsrd.X, dataB, lowerB, smsrd.Y, downVector, upVector);
+ Lcs(dataA, smsrd.X, upperA, dataB, smsrd.Y, upperB, downVector, upVector); // 2002.09.20: no need for 2 points
+ }
+ } // LCS()
+
+
+ /// Scan the tables of which lines are inserted and deleted,
+ /// producing an edit script in forward order.
+ ///
+ /// dynamic array
+ private static Item[] CreateDiffs(DiffData dataA, DiffData dataB)
+ {
+ ArrayList a = new ArrayList();
+ Item aItem;
+ Item[] result;
+
+ int lineA = 0;
+ int lineB = 0;
+ while (lineA < dataA.Length || lineB < dataB.Length)
+ {
+ if ((lineA < dataA.Length) && (!dataA.Modified[lineA])
+ && (lineB < dataB.Length) && (!dataB.Modified[lineB]))
+ {
+ // equal lines
+ lineA++;
+ lineB++;
+
+ }
+ else
+ {
+ // maybe deleted and/or inserted lines
+ int startA = lineA;
+ int startB = lineB;
+
+ while (lineA < dataA.Length && (lineB >= dataB.Length || dataA.Modified[lineA]))
+ // while (LineA < DataA.Length && DataA.modified[LineA])
+ lineA++;
+
+ while (lineB < dataB.Length && (lineA >= dataA.Length || dataB.Modified[lineB]))
+ // while (LineB < DataB.Length && DataB.modified[LineB])
+ lineB++;
+
+ if ((startA < lineA) || (startB < lineB))
+ {
+ // store a new difference-item
+ aItem = new Item();
+ aItem.StartA = startA;
+ aItem.StartB = startB;
+ aItem.DeletedA = lineA - startA;
+ aItem.InsertedB = lineB - startB;
+ a.Add(aItem);
+ } // if
+ } // if
+ } // while
+
+ result = new Item[a.Count];
+ a.CopyTo(result);
+
+ return (result);
+ }
+
+ } // class Diff
+
+
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index de971f6269..4c26172f17 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -789,6 +789,7 @@
+
diff --git a/src/umbraco.cms/businesslogic/workflow/Diff.cs b/src/umbraco.cms/businesslogic/workflow/Diff.cs
index e4e4d505a9..39cbc1d2c3 100644
--- a/src/umbraco.cms/businesslogic/workflow/Diff.cs
+++ b/src/umbraco.cms/businesslogic/workflow/Diff.cs
@@ -18,7 +18,7 @@ namespace umbraco.cms.businesslogic.workflow
/// Copyright (c) by Matthias Hertel, http://www.mathertel.de
/// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
///
-
+ [Obsolete("This class will be removed from the codebase in the future")]
public class Diff
{
@@ -489,6 +489,7 @@ namespace umbraco.cms.businesslogic.workflow
/// Data on one input file being compared.
///
+ [Obsolete("This class will be removed from the codebase in the future, logic has moved to the Core project")]
internal class DiffData
{
diff --git a/src/umbraco.cms/businesslogic/workflow/Notification.cs b/src/umbraco.cms/businesslogic/workflow/Notification.cs
index 29fc8ed319..e70077d118 100644
--- a/src/umbraco.cms/businesslogic/workflow/Notification.cs
+++ b/src/umbraco.cms/businesslogic/workflow/Notification.cs
@@ -71,7 +71,7 @@ namespace umbraco.cms.businesslogic.workflow
}
}
- ///TODO: Include update with html mail notification and document contents
+ //TODO: Include update with html mail notification and document contents
private static void SendNotification(User performingUser, User mailingUser, Document documentObject, IAction action)
{
// retrieve previous version of the document
From 44bc365fddff47ad67f223d5fab7b9d1c39b0c67 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Mon, 13 Jan 2014 13:50:30 +1100
Subject: [PATCH 010/100] Moves all notification sending logic to the
notification service, improves performance during any action when
notifications are to be sent, ensures emails are sent out async to not block
up the current request.
---
.../Services/NotificationService.cs | 45 ++--
.../businesslogic/utilities/Diff.cs | 2 +
.../businesslogic/workflow/Notification.cs | 212 +-----------------
3 files changed, 41 insertions(+), 218 deletions(-)
diff --git a/src/Umbraco.Core/Services/NotificationService.cs b/src/Umbraco.Core/Services/NotificationService.cs
index 609b6316d8..4ddde70e86 100644
--- a/src/Umbraco.Core/Services/NotificationService.cs
+++ b/src/Umbraco.Core/Services/NotificationService.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Net.Mail;
using System.Text;
+using System.Threading;
using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
@@ -53,6 +54,8 @@ namespace Umbraco.Core.Services
throw new NotSupportedException();
}
var content = (IContent) entity;
+ //we'll lazily get these if we need to send notifications
+ IContent[] allVersions = null;
int totalUsers;
var allUsers = _userService.GetAllMembers(0, int.MaxValue, out totalUsers);
@@ -63,9 +66,15 @@ namespace Umbraco.Core.Services
var notificationForAction = userNotifications.FirstOrDefault(x => x.Action == action);
if (notificationForAction != null)
{
+ //lazy load versions if notifications are required
+ if (allVersions == null)
+ {
+ allVersions = _contentService.GetVersions(entity.Id).ToArray();
+ }
+
try
{
- SendNotification(operatingUser, u, content, actionName, http, createSubject, createBody);
+ SendNotification(operatingUser, u, content, allVersions, actionName, http, createSubject, createBody);
LogHelper.Debug(string.Format("Notification type: {0} sent to {1} ({2})", action, u.Name, u.Email));
}
catch (Exception ex)
@@ -101,10 +110,7 @@ namespace Umbraco.Core.Services
{
var userNotifications = GetUserNotifications(user).ToArray();
var pathParts = path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
- var result = pathParts
- .Select(part => userNotifications.FirstOrDefault(x => x.EntityId.ToString(CultureInfo.InvariantCulture) == part))
- .Where(notification => notification != null)
- .ToList();
+ var result = userNotifications.Where(r => pathParts.InvariantContains(r.EntityId.ToString(CultureInfo.InvariantCulture))).ToList();
return result;
}
@@ -175,27 +181,25 @@ namespace Umbraco.Core.Services
///
///
///
+ ///
/// The action readable name - currently an action is just a single letter, this is the name associated with the letter
///
/// Callback to create the mail subject
/// Callback to create the mail body
- private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, string actionName, HttpContextBase http,
+ private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IContent[] allVersions, string actionName, HttpContextBase http,
Func createSubject,
Func createBody)
{
if (performingUser == null) throw new ArgumentNullException("performingUser");
if (mailingUser == null) throw new ArgumentNullException("mailingUser");
if (content == null) throw new ArgumentNullException("content");
+ if (allVersions == null) throw new ArgumentNullException("allVersions");
if (http == null) throw new ArgumentNullException("http");
if (createSubject == null) throw new ArgumentNullException("createSubject");
if (createBody == null) throw new ArgumentNullException("createBody");
- // retrieve previous version of the document
- var versions = _contentService.GetVersions(content.Id).ToArray();
-
- int versionCount = (versions.Length > 1) ? (versions.Length - 2) : (versions.Length - 1);
- var oldDoc = _contentService.GetByVersion(versions[versionCount].Version);
- //var oldDoc = new Document(documentObject.Id, versions[versionCount].Version);
+ int versionCount = (allVersions.Length > 1) ? (allVersions.Length - 2) : (allVersions.Length - 1);
+ var oldDoc = _contentService.GetByVersion(allVersions[versionCount].Version);
// build summary
var summary = new StringBuilder();
@@ -313,9 +317,20 @@ namespace Umbraco.Core.Services
string.Format("https://{0}", serverName));
}
- // send it
- var sender = new SmtpClient();
- sender.Send(mail);
+
+ // send it asynchronously, we don't want to got up all of the request time to send emails!
+ ThreadPool.QueueUserWorkItem(state =>
+ {
+ try
+ {
+ var sender = new SmtpClient();
+ sender.Send(mail);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.Error("An error occurred sending notification", ex);
+ }
+ });
}
private static string ReplaceLinks(string text, HttpRequestBase request)
diff --git a/src/umbraco.cms/businesslogic/utilities/Diff.cs b/src/umbraco.cms/businesslogic/utilities/Diff.cs
index 62397f2495..3aa159de7e 100644
--- a/src/umbraco.cms/businesslogic/utilities/Diff.cs
+++ b/src/umbraco.cms/businesslogic/utilities/Diff.cs
@@ -3,6 +3,8 @@ using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
+//TODO: We've alraedy moved most of this logic to Core.Strings - need to review this as it has slightly more functionality but should be moved to core and obsoleted!
+
namespace umbraco.cms.businesslogic.utilities {
///
/// This Class implements the Difference Algorithm published in
diff --git a/src/umbraco.cms/businesslogic/workflow/Notification.cs b/src/umbraco.cms/businesslogic/workflow/Notification.cs
index e70077d118..4ebd48e7f2 100644
--- a/src/umbraco.cms/businesslogic/workflow/Notification.cs
+++ b/src/umbraco.cms/businesslogic/workflow/Notification.cs
@@ -74,135 +74,16 @@ namespace umbraco.cms.businesslogic.workflow
//TODO: Include update with html mail notification and document contents
private static void SendNotification(User performingUser, User mailingUser, Document documentObject, IAction action)
{
- // retrieve previous version of the document
- DocumentVersionList[] versions = documentObject.GetVersions();
- int versionCount = (versions.Length > 1) ? (versions.Length - 2) : (versions.Length - 1);
- var oldDoc = new Document(documentObject.Id, versions[versionCount].Version);
+ var nService = ApplicationContext.Current.Services.NotificationService;
+ var pUser = ApplicationContext.Current.Services.UserService.GetById(performingUser.Id);
- // build summary
- var summary = new StringBuilder();
- var props = documentObject.GenericProperties;
- foreach (Property p in props)
- {
- // check if something was changed and display the changes otherwise display the fields
- Property oldProperty = oldDoc.getProperty(p.PropertyType.Alias);
- string oldText = oldProperty.Value != null ? oldProperty.Value.ToString() : "";
- string newText = p.Value != null ? p.Value.ToString() : "";
-
- // replace html with char equivalent
- ReplaceHtmlSymbols(ref oldText);
- ReplaceHtmlSymbols(ref newText);
-
- // make sure to only highlight changes done using TinyMCE editor... other changes will be displayed using default summary
- //TODO PPH: Had to change this, as a reference to the editorcontrols is not allowed, so a string comparison is the only way, this should be a DIFF or something instead..
- if (p.PropertyType.DataTypeDefinition.DataType.ToString() ==
- "umbraco.editorControls.tinymce.TinyMCEDataType" &&
- string.CompareOrdinal(oldText, newText) != 0)
- {
- summary.Append("
");
- summary.Append("
Note:
");
- summary.Append(
- "
Red for deleted charactersYellow for inserted characters
@@ -26,7 +27,7 @@
-
+
\ No newline at end of file
From 9e9b94b1d5f7dac09251f33ad36efd733660b37e Mon Sep 17 00:00:00 2001
From: Morten Christensen
Date: Tue, 14 Jan 2014 14:50:57 +0100
Subject: [PATCH 036/100] Correcting raiseEvents parameter for dictionary items
---
src/Umbraco.Core/Services/PackagingService.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs
index 3dc7d8b61e..f1ba56b049 100644
--- a/src/Umbraco.Core/Services/PackagingService.cs
+++ b/src/Umbraco.Core/Services/PackagingService.cs
@@ -1001,7 +1001,7 @@ namespace Umbraco.Core.Services
{
var items = new List();
foreach (var dictionaryItemElement in dictionaryItemElementList.Elements("DictionaryItem"))
- items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages));
+ items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, raiseEvents));
if (raiseEvents)
DictionaryItemImported.RaiseEvent(new SaveEventArgs(items, false), this);
@@ -1009,7 +1009,7 @@ namespace Umbraco.Core.Services
return items;
}
- private IEnumerable ImportDictionaryItem(XElement dictionaryItemElement, List languages)
+ private IEnumerable ImportDictionaryItem(XElement dictionaryItemElement, List languages, bool raiseEvents)
{
var items = new List();
@@ -1021,7 +1021,7 @@ namespace Umbraco.Core.Services
dictionaryItem = CreateNewDictionaryItem(key, dictionaryItemElement, languages);
_localizationService.Save(dictionaryItem);
items.Add(dictionaryItem);
- items.AddRange(ImportDictionaryItems(dictionaryItemElement, languages, true));
+ items.AddRange(ImportDictionaryItems(dictionaryItemElement, languages, raiseEvents));
return items;
}
From 7b1fd5378fb4ca1197338aa177bf6e8bb3d532b2 Mon Sep 17 00:00:00 2001
From: Morten Christensen
Date: Tue, 14 Jan 2014 15:03:39 +0100
Subject: [PATCH 037/100] Correcting the naming of events in the
RelationService
---
src/Umbraco.Core/Services/RelationService.cs | 22 ++++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/Umbraco.Core/Services/RelationService.cs b/src/Umbraco.Core/Services/RelationService.cs
index 2f82af9fc9..8ae7d80745 100644
--- a/src/Umbraco.Core/Services/RelationService.cs
+++ b/src/Umbraco.Core/Services/RelationService.cs
@@ -337,7 +337,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationSaved.RaiseEvent(new SaveEventArgs(relation, false), this);
+ SavedRelation.RaiseEvent(new SaveEventArgs(relation, false), this);
return relation;
}
@@ -365,7 +365,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationSaved.RaiseEvent(new SaveEventArgs(relation, false), this);
+ SavedRelation.RaiseEvent(new SaveEventArgs(relation, false), this);
return relation;
}
@@ -428,7 +428,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationSaved.RaiseEvent(new SaveEventArgs(relation, false), this);
+ SavedRelation.RaiseEvent(new SaveEventArgs(relation, false), this);
}
///
@@ -447,7 +447,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationTypeSaved.RaiseEvent(new SaveEventArgs(relationType, false), this);
+ SavedRelationType.RaiseEvent(new SaveEventArgs(relationType, false), this);
}
///
@@ -466,7 +466,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationDeleted.RaiseEvent(new DeleteEventArgs(relation, false), this);
+ DeletedRelation.RaiseEvent(new DeleteEventArgs(relation, false), this);
}
///
@@ -485,7 +485,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationTypeDeleted.RaiseEvent(new DeleteEventArgs(relationType, false), this);
+ DeletedRelationType.RaiseEvent(new DeleteEventArgs(relationType, false), this);
}
///
@@ -508,7 +508,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
- RelationDeleted.RaiseEvent(new DeleteEventArgs(relations, false), this);
+ DeletedRelation.RaiseEvent(new DeleteEventArgs(relations, false), this);
}
#region Private Methods
@@ -537,7 +537,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after a Relation is Deleted
///
- public static event TypedEventHandler> RelationDeleted;
+ public static event TypedEventHandler> DeletedRelation;
///
/// Occurs before Saving a Relation
@@ -547,7 +547,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after a Relation is Saved
///
- public static event TypedEventHandler> RelationSaved;
+ public static event TypedEventHandler> SavedRelation;
///
/// Occurs before Deleting a RelationType
@@ -557,7 +557,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after a RelationType is Deleted
///
- public static event TypedEventHandler> RelationTypeDeleted;
+ public static event TypedEventHandler> DeletedRelationType;
///
/// Occurs before Saving a RelationType
@@ -567,7 +567,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after a RelationType is Saved
///
- public static event TypedEventHandler> RelationTypeSaved;
+ public static event TypedEventHandler> SavedRelationType;
#endregion
}
}
\ No newline at end of file
From d6b3d115b0ce39e65019d7eeb4f4447b2952dc88 Mon Sep 17 00:00:00 2001
From: Morten Christensen
Date: Tue, 14 Jan 2014 15:03:52 +0100
Subject: [PATCH 038/100] Correcting the naming of events in the
PackagingService
---
src/Umbraco.Core/Services/PackagingService.cs | 50 +++++++++----------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs
index f1ba56b049..bb658c23f8 100644
--- a/src/Umbraco.Core/Services/PackagingService.cs
+++ b/src/Umbraco.Core/Services/PackagingService.cs
@@ -93,7 +93,7 @@ namespace Umbraco.Core.Services
}
if(raiseEvents)
- ContentExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedContent.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -181,7 +181,7 @@ namespace Umbraco.Core.Services
_contentService.Save(contents, userId);
if(raiseEvents)
- ContentImported.RaiseEvent(new SaveEventArgs(contents, false), this);
+ ImportedContent.RaiseEvent(new SaveEventArgs(contents, false), this);
return contents;
}
@@ -195,7 +195,7 @@ namespace Umbraco.Core.Services
_contentService.Save(contents, userId);
if(raiseEvents)
- ContentImported.RaiseEvent(new SaveEventArgs(contents, false), this);
+ ImportedContent.RaiseEvent(new SaveEventArgs(contents, false), this);
return contents;
}
@@ -398,7 +398,7 @@ namespace Umbraco.Core.Services
tabs);
if (raiseEvents)
- ContentTypeExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedContentType.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -478,7 +478,7 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
- ContentTypeImported.RaiseEvent(new SaveEventArgs(list, false), this);
+ ImportedContentType.RaiseEvent(new SaveEventArgs(list, false), this);
return list;
}
@@ -804,7 +804,7 @@ namespace Umbraco.Core.Services
xml.Add(new XAttribute("DatabaseType", dataTypeDefinition.DatabaseType.ToString()));
if (raiseEvents)
- DataTypeExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedDataType.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -888,7 +888,7 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
- DataTypeImported.RaiseEvent(new SaveEventArgs(list, false), this);
+ ImportedDataType.RaiseEvent(new SaveEventArgs(list, false), this);
return list;
}
@@ -974,7 +974,7 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
- DictionaryItemExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedDictionaryItem.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -1004,7 +1004,7 @@ namespace Umbraco.Core.Services
items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, raiseEvents));
if (raiseEvents)
- DictionaryItemImported.RaiseEvent(new SaveEventArgs(items, false), this);
+ ImportedDictionaryItem.RaiseEvent(new SaveEventArgs(items, false), this);
return items;
}
@@ -1107,7 +1107,7 @@ namespace Umbraco.Core.Services
new XAttribute("FriendlyName", language.CultureName));
if (raiseEvents)
- LanguageExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedLanguage.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -1143,7 +1143,7 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
- LanguageImported.RaiseEvent(new SaveEventArgs(list, false), this);
+ ImportedLanguage.RaiseEvent(new SaveEventArgs(list, false), this);
return list;
}
@@ -1214,7 +1214,7 @@ namespace Umbraco.Core.Services
}
if(raiseEvents)
- MediaExported.RaiseEvent(new SaveEventArgs(xml, false), this);
+ ExportedMedia.RaiseEvent(new SaveEventArgs(xml, false), this);
return xml;
}
@@ -1395,7 +1395,7 @@ namespace Umbraco.Core.Services
_fileService.SaveTemplate(templates, userId);
if(raiseEvents)
- TemplateImported.RaiseEvent(new SaveEventArgs(templates, false), this);
+ ImportedTemplate.RaiseEvent(new SaveEventArgs(templates, false), this);
return templates;
}
@@ -1430,7 +1430,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Content is Imported and Saved
///
- public static event TypedEventHandler> ContentImported;
+ public static event TypedEventHandler> ImportedContent;
///
/// Occurs before Exporting Content
@@ -1440,7 +1440,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Content is Exported to Xml
///
- public static event TypedEventHandler> ContentExported;
+ public static event TypedEventHandler> ExportedContent;
///
/// Occurs before Exporting Media
@@ -1450,7 +1450,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Media is Exported to Xml
///
- public static event TypedEventHandler> MediaExported;
+ public static event TypedEventHandler> ExportedMedia;
///
/// Occurs before Importing ContentType
@@ -1460,7 +1460,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after ContentType is Imported and Saved
///
- public static event TypedEventHandler> ContentTypeImported;
+ public static event TypedEventHandler> ImportedContentType;
///
/// Occurs before Exporting ContentType
@@ -1470,7 +1470,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after ContentType is Exported to Xml
///
- public static event TypedEventHandler> ContentTypeExported;
+ public static event TypedEventHandler> ExportedContentType;
///
/// Occurs before Importing DataType
@@ -1480,7 +1480,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after DataType is Imported and Saved
///
- public static event TypedEventHandler> DataTypeImported;
+ public static event TypedEventHandler> ImportedDataType;
///
/// Occurs before Exporting DataType
@@ -1490,7 +1490,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after DataType is Exported to Xml
///
- public static event TypedEventHandler> DataTypeExported;
+ public static event TypedEventHandler> ExportedDataType;
///
/// Occurs before Importing DictionaryItem
@@ -1500,7 +1500,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after DictionaryItem is Imported and Saved
///
- public static event TypedEventHandler> DictionaryItemImported;
+ public static event TypedEventHandler> ImportedDictionaryItem;
///
/// Occurs before Exporting DictionaryItem
@@ -1510,7 +1510,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after DictionaryItem is Exported to Xml
///
- public static event TypedEventHandler> DictionaryItemExported;
+ public static event TypedEventHandler> ExportedDictionaryItem;
///
/// Occurs before Importing Language
@@ -1520,7 +1520,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Language is Imported and Saved
///
- public static event TypedEventHandler> LanguageImported;
+ public static event TypedEventHandler> ImportedLanguage;
///
/// Occurs before Exporting Language
@@ -1530,7 +1530,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Language is Exported to Xml
///
- public static event TypedEventHandler> LanguageExported;
+ public static event TypedEventHandler> ExportedLanguage;
///
/// Occurs before Importing Template
@@ -1540,7 +1540,7 @@ namespace Umbraco.Core.Services
///
/// Occurs after Template is Imported and Saved
///
- public static event TypedEventHandler> TemplateImported;
+ public static event TypedEventHandler> ImportedTemplate;
#endregion
}
}
\ No newline at end of file
From 14cfd2a8df3c49bcdada868c218ac0491ced08c9 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Tue, 14 Jan 2014 15:21:20 +0100
Subject: [PATCH 039/100] D'oh .. now properly renamed, in the csproj as well -
U4-4046 Rename "empty template" to "empty"
---
src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index f97ff2ca1e..4bdd618fa2 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -2135,13 +2135,13 @@
-
+
-
+
-
+ Code
@@ -2161,7 +2161,7 @@
-
+
From 0da7ed8d93e4bb53f52f86213eb34f2dd3a57ec6 Mon Sep 17 00:00:00 2001
From: Bob Davidson
Date: Tue, 14 Jan 2014 15:40:22 -0600
Subject: [PATCH 040/100] Fix for U4-3831. Removes form, adds ng-click with
$event.preventDefault() to prevent premature saving.
---
.../propertyeditors/relatedlinks/relatedlinks.controller.js | 3 ++-
.../src/views/propertyeditors/relatedlinks/relatedlinks.html | 4 +---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
index f275cdc25b..3e13e0014b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
@@ -43,7 +43,7 @@
$scope.model.value.splice(idx, 1);
};
- $scope.add = function () {
+ $scope.add = function ($event) {
if ($scope.newCaption == "") {
$scope.hasError = true;
} else {
@@ -79,6 +79,7 @@
$scope.newInternalName = '';
}
+ $event.preventDefault();
};
$scope.switch = function ($event) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.html
index 5513d96a58..afd61a4e88 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.html
@@ -51,7 +51,6 @@
-
From 84da5f43a2df62fd63e9d469d4fcb13d2e6f6544 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 10:41:37 +1100
Subject: [PATCH 041/100] U4-4045 The "Empty" partial view snippet should have
@inherits
---
.../Umbraco/PartialViews/Templates/EmptyTemplate.cshtml | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml
index e69de29bb2..dda3a17f51 100644
--- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml
@@ -0,0 +1 @@
+@inherits Umbraco.Web.Macros.PartialViewMacroPage
\ No newline at end of file
From 75a42fd0d6a0fb57de4121169faa402085591e34 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 10:42:01 +1100
Subject: [PATCH 042/100] fixes the protect page logic
---
.../umbraco/dialogs/protectPage.aspx.cs | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs
index 4bfb0ee7ad..2af1add9fa 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs
@@ -183,7 +183,9 @@ namespace umbraco.presentation.umbraco.dialogs
if (e.CommandName == "simple")
{
- var member = Membership.GetUser(simpleLogin.Text);
+ var memberLogin = simpleLogin.Visible ? simpleLogin.Text : SimpleLoginLabel.Text;
+
+ var member = Membership.GetUser(memberLogin);
if (member == null)
{
var tempEmail = "u" + Guid.NewGuid().ToString("N") + "@example.com";
@@ -191,7 +193,7 @@ namespace umbraco.presentation.umbraco.dialogs
// this needs to work differently depending on umbraco members or external membership provider
if (Membership.Provider.IsUmbracoMembershipProvider() == false)
{
- member = Membership.CreateUser(simpleLogin.Text, simplePassword.Text, tempEmail);
+ member = Membership.CreateUser(memberLogin, simplePassword.Text, tempEmail);
}
else
{
@@ -203,7 +205,7 @@ namespace umbraco.presentation.umbraco.dialogs
var provider = Membership.Provider.AsUmbracoMembershipProvider();
MembershipCreateStatus status;
member = provider.CreateUser(Constants.Conventions.MemberTypes.SystemDefaultProtectType,
- simpleLogin.Text, simplePassword.Text, tempEmail, null, null, true, null, out status);
+ memberLogin, simplePassword.Text, tempEmail, null, null, true, null, out status);
if (status != MembershipCreateStatus.Success)
{
SimpleLoginNameValidator.IsValid = false;
@@ -217,14 +219,14 @@ namespace umbraco.presentation.umbraco.dialogs
{
SimpleLoginNameValidator.IsValid = false;
SimpleLoginLabel.Visible = true;
- SimpleLoginLabel.Text = simpleLogin.Text;
+ SimpleLoginLabel.Text = memberLogin;
simpleLogin.Visible = false;
pp_pass.Visible = false;
return;
}
// Create or find a memberGroup
- string simpleRoleName = "__umbracoRole_" + simpleLogin.Text;
+ var simpleRoleName = "__umbracoRole_" + member.UserName;
if (Roles.RoleExists(simpleRoleName) == false)
{
Roles.CreateRole(simpleRoleName);
From 5a29441640e0a823fce279bacda65438da657dbd Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 10:53:14 +1100
Subject: [PATCH 043/100] Reverts GetByQuery and MNTP Xpath query WIP - is
contained only in 7.1
---
.../src/common/resources/entity.resource.js | 10 ----
.../contentpicker/contentpicker.controller.js | 22 ++------
src/Umbraco.Web/Editors/EntityController.cs | 54 -------------------
3 files changed, 4 insertions(+), 82 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
index 182b487f11..75d2f47a28 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
@@ -99,16 +99,6 @@ function entityResource($q, $http, umbRequestHelper) {
'Failed to retreive entity data for id ' + id);
},
- getByQuery: function (query, rootNodeId, type) {
- return umbRequestHelper.resourcePromise(
- $http.get(
- umbRequestHelper.getApiUrl(
- "entityApiBaseUrl",
- "GetByQuery",
- [{query: query},{ rootNodeId: rootNodeId}, {type: type }])),
- 'Failed to retreive entity data for query ' + query);
- },
-
/**
* @ngdoc method
* @name umbraco.resources.entityResource#getByIds
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
index 70de53bf24..ab1aeb06e2 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
@@ -3,7 +3,7 @@
angular.module('umbraco')
.controller("Umbraco.PropertyEditors.ContentPickerController",
- function($scope, dialogService, entityResource, editorState, $log, iconHelper){
+ function($scope, dialogService, entityResource, $log, iconHelper){
$scope.renderModel = [];
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
@@ -11,8 +11,6 @@ angular.module('umbraco')
$scope.cfg = {
multiPicker: "0",
entityType: "Document",
- filterCssClass: "not-allowed not-published",
-
startNode:{
type: "content",
id: -1
@@ -33,23 +31,11 @@ angular.module('umbraco')
$scope.cfg.entityType = "Media";
}
- //if we have a query for the startnode, we will use that.
- if($scope.cfg.startNode.query){
- var rootId = -1;
- if($scope.cfg.startNode.scope === "current"){
- rootId = editorState.current.id;
- }
-
- entityResource.getByQuery($scope.cfg.startNode.query, rootId, "Document").then(function(ent){
- $scope.cfg.startNodeId = ent.id;
- });
- }else{
- $scope.cfg.startNodeId = $scope.cfg.startNode.id;
- }
-
$scope.cfg.callback = populate;
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
- $scope.cfg.section = $scope.cfg.startNode.type;
+ $scope.cfg.section = $scope.cfg.startNode.type;
+ $scope.cfg.startNodeId = $scope.cfg.startNode.id;
+ $scope.cfg.filterCssClass = "not-allowed not-published";
//load current data
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function(data){
diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs
index 4eef37e3ed..e30d67fe1d 100644
--- a/src/Umbraco.Web/Editors/EntityController.cs
+++ b/src/Umbraco.Web/Editors/EntityController.cs
@@ -25,7 +25,6 @@ using Examine;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Umbraco.Web.Dynamics;
-using umbraco;
namespace Umbraco.Web.Editors
{
@@ -129,59 +128,6 @@ namespace Umbraco.Web.Editors
return GetResultForKey(id, type);
}
- ///
- /// Gets an entity by a xpath or css-like query
- ///
- ///
- ///
- ///
- ///
- public EntityBasic GetByQuery(string query, int rootNodeId, UmbracoEntityTypes type)
- {
-
- //this is css (commented out for now, due to external dependency)
- //if (!query.Contains("::") && !query.Contains('/'))
- // query = css2xpath.Converter.CSSToXPath(query, "");
-
-
- if(rootNodeId < 0)
- {
- var node = Umbraco.TypedContentSingleAtXPath(query);
-
- if(node == null)
- return null;
-
- return GetById(node.Id, UmbracoEntityTypes.Document);
- }
- else
- {
- //SD: This should be done using UmbracoHelper
-
- //var node = Umbraco.TypedContent(rootNodeId);
- //if (node != null)
- //{
- // //TODO: Build an Xpath query based on this node ID and the rest of the query
- // // var subQuery = [@id=rootNodeId]/query
- // // and then get that node with:
- // // var result = Umbraco.TypedContentSingleAtXPath(subQuery);
- //}
-
- var node = global::umbraco.library.GetXmlNodeById(rootNodeId.ToString());
- if (node.MoveNext())
- {
- if (node.Current != null)
- {
- var result = node.Current.Select(query);
- //set it to the first node found (if there is one), otherwise to -1
- if (result.Current != null)
- return GetById(int.Parse(result.Current.GetAttribute("id", string.Empty)), UmbracoEntityTypes.Document);
- }
- }
- }
-
- return null;
- }
-
public EntityBasic GetById(int id, UmbracoEntityTypes type)
{
return GetResultForId(id, type);
From 5caf09140677a263ade2e75340638ae77a91ee0e Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 10:55:22 +1100
Subject: [PATCH 044/100] Revert "WIP: adds cropper directive"
This reverts commit c5a7eab1d5496be7090a5bb686bc0a2f069992a6.
new cropper is only contained in 7.1 branch
---
.../imaging/umbImageCrop.directive.js | 265 ------------------
.../imaging/umbImageGravity.directive.js | 157 -----------
.../src/less/property-editors.less | 54 ----
.../directives/imaging/umb-image-crop.html | 32 ---
.../directives/imaging/umb-image-gravity.html | 17 --
5 files changed, 525 deletions(-)
delete mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageCrop.directive.js
delete mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageGravity.directive.js
delete mode 100644 src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-crop.html
delete mode 100644 src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-gravity.html
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageCrop.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageCrop.directive.js
deleted file mode 100644
index 2f8cf5ca60..0000000000
--- a/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageCrop.directive.js
+++ /dev/null
@@ -1,265 +0,0 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:umbImageCrop
-* @restrict E
-* @function
-**/
-angular.module("umbraco.directives")
- .directive('umbImageCrop', function ($timeout, localizationService, $log) {
- return {
- restrict: 'E',
- replace: true,
- templateUrl: 'views/directives/umb-image-crop.html',
- scope: {
- src: '@',
- width: '@',
- height: '@',
- presets: '@',
- crop: "="
- },
- link: function(scope, element, attrs) {
-
- scope.scale = 100;
-
- //if image is over this, we re-calculate the editors global ratio
- //this will not have an effect on the result, since that is returned in percentage
- scope.maxHeight = 500;
- scope.maxWidth = 600;
-
- scope.width = 400;
- scope.height = 320;
-
- scope.dimensions = {
- image: {},
- cropper:{},
- viewport:{},
- margin: 20,
- ratio: 1
- };
-
- scope.style = function () {
- return {
- 'height': (parseInt(scope.height, 10) + 2 * scope.dimensions.margin) + 'px',
- 'width': (parseInt(scope.width, 10) + 2 * scope.dimensions.margin) + 'px'
- };
- };
-
- //elements
- var $viewport = element.find(".viewport");
- var $image = element.find("img");
- var $overlay = element.find(".overlay");
- var $container = element.find(".crop-container");
-
- //default constraints for drag n drop
- var constraints = {left: {max: 20, min: 20}, top: {max: 20, min: 20}, };
-
- var setDimensions = function(){
- scope.dimensions.image.width = $image.width();
- scope.dimensions.image.height = $image.height();
-
- scope.dimensions.viewport.width = $viewport.width();
- scope.dimensions.viewport.height = $viewport.height();
-
- scope.dimensions.cropper.width = scope.dimensions.viewport.width - 2 * scope.dimensions.margin;
- scope.dimensions.cropper.height = scope.dimensions.viewport.height - 2 * scope.dimensions.margin;
- };
-
- var setImageSize = function(width, height){
- $image.width(width);
- $image.height(height);
- scope.dimensions.image.width = width;
- scope.dimensions.image.height = height;
- };
-
- //when loading an image without any crop info, we center and fit it
- var fitImage = function(){
- fitToViewPort($image);
- centerImage($image);
- syncOverLay();
- setConstraints($image);
- };
-
- //utill for centering scaled image
- var centerImage = function(img) {
- var image_width = img.width(),
- image_height = img.height(),
- mask_width = $viewport.width(),
- mask_height = $viewport.height();
-
- img.css({
- 'position': 'absolute',
- 'left': scope.dimensions.viewport.width / 2 - scope.dimensions.image.width / 2,
- 'top': scope.dimensions.viewport.height / 2 - scope.dimensions.image.height / 2
- });
- };
-
- //utill for scaling image to fit viewport
- var fitToViewPort = function(img) {
- //returns size fitting the cropper
- var size = calculateAspectRatioFit(
- scope.dimensions.image.width,
- scope.dimensions.image.height,
- scope.dimensions.cropper.width,
- scope.dimensions.cropper.height,
- true);
-
- //sets the image size and updates the scope
- setImageSize(size.width, size.height);
-
- scope.minScale = size.ratio;
- scope.maxScale = size.ratio * 3;
- scope.currentScale = scope.minScale;
- scope.scale = scope.currentScale;
- };
-
- var resizeImageToScale = function(img, ratio){
- //do stuff
- var size = calculateSizeToRatio(scope.dimensions.image.originalWidth, scope.dimensions.image.originalHeight, ratio);
-
- setImageSize(size.width, size.height);
- centerImage(img);
- scope.currentScale = scope.scale;
-
- syncOverLay();
- };
-
- //set constaints for cropping drag and drop
- var setConstraints = function(img){
- //do stuff
- var w = img.width(),
- h = img.height(),
- crop_width = $viewport.width() - 2 * 20,
- crop_height = $viewport.height() - 2 * 20;
-
- constraints.left.min = 20 + crop_width - w;
- constraints.top.min = 20 + crop_height - h;
- };
-
- //utill for getting either min/max aspect ratio to scale image after
- var calculateAspectRatioFit = function(srcWidth, srcHeight, maxWidth, maxHeight, maximize) {
- var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
-
- if(maximize){
- ratio = Math.max(ratio[0], ratio[1]);
- }else{
- ratio = Math.min(ratio[0], ratio[1]);
- }
-
- return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
- };
-
- //utill for scaling width / height given a ratio
- var calculateSizeToRatio= function(srcWidth, srcHeight, ratio) {
- return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
- };
-
- var calculateCropBox = function(){
- scope.crop.left = Math.abs($image[0].offsetLeft - scope.dimensions.margin) / scope.dimensions.image.width;
- scope.crop.top = Math.abs($image[0].offsetTop - scope.dimensions.margin) / scope.dimensions.image.height;
-
- scope.crop.right = 1 - Math.abs(scope.dimensions.cropper.width - (scope.dimensions.image.width - scope.crop.left)) / scope.dimensions.image.width;
- scope.crop.bottom = 1 - Math.abs(scope.dimensions.cropper.height - (scope.dimensions.image.height - scope.crop.top)) / scope.dimensions.image.height;
- };
-
- var calculatePosition = function(crop){
-
- var left = (crop.left * scope.dimensions.image.originalWidth);
- var top = (crop.top * scope.dimensions.image.originalHeight);
-
- var cropped_width = scope.dimensions.image.originalWidth - left;
- var ratio = cropped_width / scope.dimensions.image.originalWidth;
-
- scope.scale = ratio;
- resizeImageToScale($image, ratio);
-
- $image.css({
- "top": -top,
- "left": -left
- });
-
- syncOverLay();
- };
-
-
-
- var syncOverLay = function(){
- $overlay.height($image.height());
- $overlay.width($image.width());
-
- $overlay.css({
- "top": $image[0].offsetTop,
- "left": $image[0].offsetLeft
- });
-
- calculateCropBox();
- };
-
- //Drag and drop positioning, using jquery ui draggable
- var onStartDragPosition, top, left;
- $overlay.draggable({
- start: function(event, ui) {
- syncOverLay();
- },
- drag: function(event, ui) {
-
-
- if(ui.position.left <= constraints.left.max && ui.position.left >= constraints.left.min){
- $image.css({
- 'left': ui.position.left
- });
- }
-
- if(ui.position.top <= constraints.top.max && ui.position.top >= constraints.top.min){
- $image.css({
- 'top': ui.position.top
- });
- }
- },
- stop: function() {
- syncOverLay();
- }
- });
-
-
-
-
-
- //// INIT /////
- $image.load(function(){
- $timeout(function(){
- $image.width("auto");
- $image.height("auto");
-
- scope.dimensions.image.originalWidth = $image.width();
- scope.dimensions.image.originalHeight = $image.height();
-
- setDimensions();
-
- if(scope.crop && scope.crop.top){
- calculatePosition(scope.crop);
- }else{
- fitImage();
- }
-
- scope.loaded = true;
- });
- });
-
-
- /// WATCHERS ////
- scope.$watch("scale", function(){
- if(scope.loaded && scope.scale !== scope.currentScale){
- resizeImageToScale($image, scope.scale);
- setConstraints($image);
- }
- });
-
- /// WATCHERS ////
- scope.$watch("crop", function(newVal, oldVal){
- if(scope.loaded && newVal !== oldVal){
- calculatePosition(scope.crop);
- }
- });
- }
- };
- });
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageGravity.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageGravity.directive.js
deleted file mode 100644
index 418e0f0709..0000000000
--- a/src/Umbraco.Web.UI.Client/src/common/directives/imaging/umbImageGravity.directive.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
-* @ngdoc directive
-* @name umbraco.directives.directive:umbCropsy
-* @restrict E
-* @function
-* @description
-* Used by editors that require naming an entity. Shows a textbox/headline with a required validator within it's own form.
-**/
-angular.module("umbraco.directives")
- .directive('umbImageGravity', function ($timeout, localizationService, $log) {
- return {
- restrict: 'E',
- replace: true,
- templateUrl: 'views/directives/umb-image-gravity.html',
- scope: {
- src: '@',
- width: '@',
- height: '@',
- gravity: "="
- },
- link: function(scope, element, attrs) {
-
- scope.scale = 100;
-
- //if image is over this, we re-calculate the editors global ratio
- //this will not have an effect on the result, since that is returned in percentage
- scope.maxHeight = 500;
- scope.maxWidth = 600;
-
- scope.width = 400;
- scope.height = 320;
-
- scope.dimensions = {
- image: {},
- viewport:{},
- ratio: 1
- };
-
- scope.style = function () {
- return {
- 'height': parseInt(scope.height, 10) + 'px',
- 'width': parseInt(scope.width, 10) + 'px'
- };
- };
-
- //elements
- var $viewport = element.find(".viewport");
- var $image = element.find("img");
- var $overlay = element.find(".overlay");
- var $container = element.find(".crop-container");
-
- var setImageSize = function(width, height){
- $image.width(width);
- $image.height(height);
-
- $viewport.width(width);
- $viewport.height(height);
-
- scope.dimensions.image.width = width;
- scope.dimensions.image.height = height;
- };
-
- //when loading an image without any crop info, we center and fit it
- var fitImage = function(){
- fitToViewPort($image);
- centerImage($image);
- };
-
- //utill for centering scaled image
- var centerImage = function(img) {
- img.css({
- 'position': 'absolute',
- 'left': scope.dimensions.viewport.width / 2 - scope.dimensions.image.width / 2,
- 'top': scope.dimensions.viewport.height / 2 - scope.dimensions.image.height / 2
- });
- };
-
- //utill for scaling image to fit viewport
- var fitToViewPort = function(img) {
- //returns size fitting the cropper
- var size = calculateAspectRatioFit(
- scope.dimensions.image.width,
- scope.dimensions.image.height,
- scope.dimensions.viewport.width,
- scope.dimensions.viewport.height,
- true);
-
- //sets the image size and updates the scope
- setImageSize(size.width, size.height);
-
- scope.minScale = size.ratio;
- scope.maxScale = size.ratio * 3;
- scope.currentScale = scope.minScale;
- scope.scale = scope.currentScale;
- };
-
- var resizeImageToScale = function(img, ratio){
- //do stuff
- var size = calculateSizeToRatio(scope.dimensions.image.originalWidth, scope.dimensions.image.originalHeight, ratio);
-
- setImageSize(size.width, size.height);
- centerImage(img);
- scope.currentScale = scope.scale;
- };
-
- //utill for getting either min/max aspect ratio to scale image after
- var calculateAspectRatioFit = function(srcWidth, srcHeight, maxWidth, maxHeight, maximize) {
- var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
-
- if(maximize){
- ratio = Math.max(ratio[0], ratio[1]);
- }else{
- ratio = Math.min(ratio[0], ratio[1]);
- }
-
- return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
- };
-
- //utill for scaling width / height given a ratio
- var calculateSizeToRatio= function(srcWidth, srcHeight, ratio) {
- return { width:srcWidth*ratio, height:srcHeight*ratio, ratio: ratio};
- };
-
- var calculateGravity = function(){
- scope.gravity.left = $overlay[0].offsetLeft + 10;
- scope.gravity.top = $overlay[0].offsetTop + 10;
- };
-
-
- //Drag and drop positioning, using jquery ui draggable
- var onStartDragPosition, top, left;
- $overlay.draggable({
- stop: function() {
- calculateGravity();
- }
- });
-
- //// INIT /////
- $image.load(function(){
- $timeout(function(){
- $image.width("auto");
- $image.height("auto");
-
- scope.dimensions.image.originalWidth = $image.width();
- scope.dimensions.image.originalHeight = $image.height();
-
- setDimensions();
-
- fitImage();
- scope.loaded = true;
- });
- });
-
-
- }
- };
- });
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
index 6291c1066c..6ffde599a6 100644
--- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less
+++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
@@ -184,60 +184,6 @@ ul.color-picker li a {
}
-//
-// Cropper
-// -------------------------------------------------
-
-.umb-cropper .crop-container .viewport img {
- position: absolute;
- top: 0;
- left: 0;
-}
-
-
-.umb-cropper .overlay {
- top: 0;
- left: 0;
- cursor: move;
- z-index: 6001;
-}
-
-.umb-cropper .viewport {
- overflow: hidden;
- position: relative;
- width: 600px;
- height: 400px;
- border:1px solid #ccc;
- background-image: url('images/viewport_background.gif');
-}
-
-.umb-cropper .viewport:after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 5999;
- -moz-opacity: .75;
- opacity: .75;
- filter: alpha(opacity=7);
- -webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
- -moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
- box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
-}
-
-.umb-cropper-gravity .pointer{
- width: 20px;
- height: 20px;
-
- top: 0;
- left: 0;
- cursor: move;
- z-index: 6001;
-}
-
-
//
// folder-browser
// --------------------------------------------------
diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-crop.html b/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-crop.html
deleted file mode 100644
index 82f83d56d6..0000000000
--- a/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-crop.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- {{dimensions | json}}
-
-
-
- {{box | json}}
-
-
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-gravity.html b/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-gravity.html
deleted file mode 100644
index 97acd321d2..0000000000
--- a/src/Umbraco.Web.UI.Client/src/views/directives/imaging/umb-image-gravity.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{gravity | json}}
-
-
-
\ No newline at end of file
From c527833081763e85221337380bbae8d6e548f519 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 10:59:05 +1100
Subject: [PATCH 045/100] Revert "adds editing function to media picker
controller"
This reverts commit 7d051dffbb1b891979cb4e1d698e5f536661d691.
This will only be contained in 7.1
---
.../propertyeditors/mediapicker/mediapicker.controller.js | 8 --------
1 file changed, 8 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
index af5779b9a7..23a0a4aefc 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
@@ -32,14 +32,6 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.sync();
};
- $scope.edit = function(image){
- $scope.currentImage = image;
- $scope.currentImage.crop ={};
- if(!$scope.currentImage.crop){
- //$scope.currentImage.crop = { "left": 0.31731772342645215, "top": 0.17420325244997603, "right": 0.36246473116627076, "bottom": 0.30226197981593617 };
- }
- }
-
$scope.add = function() {
dialogService.mediaPicker({
multiPicker: multiPicker,
From 3ef9635406266a9676f3fa01b82c5bd5a8edf64d Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 13:17:38 +1100
Subject: [PATCH 046/100] Fixes: U4-4010 Member and user session gets mixed -
fixes how we detect a back office request + unit tests and added new
IsBackOffice attribute
---
src/Umbraco.Core/UriExtensions.cs | 91 +++++++++++++++++--
src/Umbraco.Tests/UriExtensionsTests.cs | 41 ++++++---
src/Umbraco.Web/Mvc/PluginController.cs | 10 +-
.../Mvc/PluginControllerMetadata.cs | 6 ++
.../ServerRegistrationEventHandler.cs | 4 +-
src/Umbraco.Web/Umbraco.Web.csproj | 1 +
src/Umbraco.Web/UmbracoModule.cs | 2 +-
.../WebApi/IsBackOfficeAttribute.cs | 13 +++
.../WebApi/UmbracoAuthorizedApiController.cs | 1 +
src/Umbraco.Web/WebBootManager.cs | 8 +-
10 files changed, 148 insertions(+), 29 deletions(-)
create mode 100644 src/Umbraco.Web/WebApi/IsBackOfficeAttribute.cs
diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs
index da9498c96d..058c53892c 100644
--- a/src/Umbraco.Core/UriExtensions.cs
+++ b/src/Umbraco.Core/UriExtensions.cs
@@ -11,24 +11,97 @@ namespace Umbraco.Core
///
public static class UriExtensions
{
-
///
/// Checks if the current uri is a back office request
///
///
+ ///
+ /// The current application path or VirtualPath
+ ///
///
- internal static bool IsBackOfficeRequest(this Uri url)
+ ///
+ /// There are some special routes we need to check to properly determine this:
+ ///
+ /// If any route has an extension in the path like .aspx = back office
+ ///
+ /// These are def back office:
+ /// /Umbraco/RestServices = back office
+ /// /Umbraco/BackOffice = back office
+ /// /Umbraco/UmbracpApi = back office
+ /// /Umbraco/UmbracoTrees = back office
+ /// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end
+ /// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice
+ /// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute.
+ ///
+ /// These are def front-end:
+ /// /Umbraco/Surface = front-end
+ /// /Umbraco/Api = front-end
+ /// But if we've got this far we'll just have to assume it's front-end anyways.
+ ///
+ ///
+ internal static bool IsBackOfficeRequest(this Uri url, string applicationPath)
{
-
- var authority = url.GetLeftPart(UriPartial.Authority);
- var afterAuthority = url.GetLeftPart(UriPartial.Query)
- .TrimStart(authority)
- .TrimStart("/");
+ applicationPath = applicationPath ?? string.Empty;
+ var fullUrlPath = url.AbsolutePath.TrimStart(new[] {'/'});
+ var appPath = applicationPath.TrimStart(new[] {'/'});
+ var urlPath = fullUrlPath.TrimStart(appPath).EnsureStartsWith('/');
-
//check if this is in the umbraco back office
- return afterAuthority.InvariantStartsWith(GlobalSettings.Path.TrimStart("/"));
+ var isUmbracoPath = urlPath.InvariantStartsWith(GlobalSettings.Path.EnsureStartsWith('/'));
+ //if not, then def not back office
+ if (isUmbracoPath == false) return false;
+
+ //if its the normal /umbraco path
+ if (urlPath.InvariantEquals("/" + GlobalSettings.UmbracoMvcArea)
+ || urlPath.InvariantEquals("/" + GlobalSettings.UmbracoMvcArea + "/"))
+ {
+ return true;
+ }
+
+ //check for a file extension
+ var extension = Path.GetExtension(url.LocalPath);
+ //has an extension, def back office
+ if (extension.IsNullOrWhiteSpace() == false) return true;
+ //check for special case asp.net calls like:
+ // /umbraco/webservices/legacyAjaxCalls.asmx/js which will return a null file extension but are still considered extension'd requests
+ if (urlPath.InvariantContains(".asmx/")
+ || urlPath.InvariantContains(".aspx/")
+ || urlPath.InvariantContains(".ashx/")
+ || urlPath.InvariantContains(".axd/")
+ || urlPath.InvariantContains(".svc/"))
+ {
+ return true;
+ }
+
+ //check for special back office paths
+ if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/UmbracoApi/")
+ || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/UmbracoTrees/")
+ || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/BackOffice/")
+ || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/RestServices/"))
+ {
+ return true;
+ }
+
+ //check for special front-end paths
+ if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/Surface/")
+ || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/Api/"))
+ {
+ return false;
+ }
+
+ //if its none of the above, we will have to try to detect if it's a PluginController route, we can detect this by
+ // checking how many parts the route has, for example, all PluginController routes will be routed like
+ // Umbraco/MYPLUGINAREA/MYCONTROLLERNAME/{action}/{id}
+ // so if the path contains at a minimum 3 parts: Umbraco + MYPLUGINAREA + MYCONTROLLERNAME then we will have to assume it is a
+ // plugin controller for the front-end.
+ if (urlPath.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries).Length >= 3)
+ {
+ return false;
+ }
+
+ //if its anything else we can assume it's back office
+ return true;
}
///
diff --git a/src/Umbraco.Tests/UriExtensionsTests.cs b/src/Umbraco.Tests/UriExtensionsTests.cs
index 61ed49d65d..9a6cfcae17 100644
--- a/src/Umbraco.Tests/UriExtensionsTests.cs
+++ b/src/Umbraco.Tests/UriExtensionsTests.cs
@@ -10,20 +10,35 @@ namespace Umbraco.Tests
[TestFixture]
public class UriExtensionsTests
{
- [TestCase("http://www.domain.com/umbraco", true)]
- [TestCase("http://www.domain.com/Umbraco/", true)]
- [TestCase("http://www.domain.com/umbraco/default.aspx", true)]
- [TestCase("http://www.domain.com/umbraco/test/test", true)]
- [TestCase("http://www.domain.com/Umbraco/test/test.aspx", true)]
- [TestCase("http://www.domain.com/umbraco/test/test.js", true)]
- [TestCase("http://www.domain.com/umbrac", false)]
- [TestCase("http://www.domain.com/test", false)]
- [TestCase("http://www.domain.com/test/umbraco", false)]
- [TestCase("http://www.domain.com/test/umbraco.aspx", false)]
- public void Is_Back_Office_Request(string input, bool expected)
+ [TestCase("http://www.domain.com/umbraco", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/", "", true)]
+ [TestCase("http://www.domain.com/umbraco/default.aspx", "", true)]
+ [TestCase("http://www.domain.com/umbraco/test/test", "", false)]
+ [TestCase("http://www.domain.com/umbraco/test/test/test", "", false)]
+ [TestCase("http://www.domain.com/Umbraco/test/test.aspx", "", true)]
+ [TestCase("http://www.domain.com/umbraco/test/test.js", "", true)]
+ [TestCase("http://www.domain.com/umbrac", "", false)]
+ [TestCase("http://www.domain.com/test", "", false)]
+ [TestCase("http://www.domain.com/test/umbraco", "", false)]
+ [TestCase("http://www.domain.com/test/umbraco.aspx", "", false)]
+ [TestCase("http://www.domain.com/Umbraco/restServices/blah", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/umbracoapi/blah", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/umbracotrees/blah", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/anything", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/anything/", "", true)]
+ [TestCase("http://www.domain.com/Umbraco/surface/blah", "", false)]
+ [TestCase("http://www.domain.com/umbraco/api/blah", "", false)]
+ [TestCase("http://www.domain.com/myvdir/umbraco/api/blah", "myvdir", false)]
+ [TestCase("http://www.domain.com/MyVdir/umbraco/api/blah", "/myvdir", false)]
+ [TestCase("http://www.domain.com/MyVdir/Umbraco/", "myvdir", true)]
+ [TestCase("http://www.domain.com/MyVdir/Umbraco/restServices/blah", "/myvdir", true)]
+ [TestCase("http://www.domain.com/umbraco/webservices/legacyAjaxCalls.asmx/js", "", true)]
+ [TestCase("http://www.domain.com/umbraco/test/legacyAjaxCalls.ashx?some=query&blah=js", "", true)]
+ public void Is_Back_Office_Request(string input, string virtualPath, bool expected)
{
- var source = new Uri(input);
- Assert.AreEqual(expected, source.IsBackOfficeRequest());
+ var source = new Uri(input);
+ Assert.AreEqual(expected, source.IsBackOfficeRequest(virtualPath));
}
[TestCase("http://www.domain.com/install", true)]
diff --git a/src/Umbraco.Web/Mvc/PluginController.cs b/src/Umbraco.Web/Mvc/PluginController.cs
index 6c14edf3d9..1814da09b2 100644
--- a/src/Umbraco.Web/Mvc/PluginController.cs
+++ b/src/Umbraco.Web/Mvc/PluginController.cs
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Services;
+using Umbraco.Web.WebApi;
namespace Umbraco.Web.Mvc
{
@@ -86,14 +87,17 @@ namespace Umbraco.Web.Mvc
return MetadataStorage.GetOrAdd(type, type1 =>
{
- var attribute = type.GetCustomAttribute(false);
+ var pluginAttribute = type.GetCustomAttribute(false);
+ //check if any inherited class of this type contains the IsBackOffice attribute
+ var backOfficeAttribute = type.GetCustomAttribute(true);
var meta = new PluginControllerMetadata()
{
- AreaName = attribute == null ? null : attribute.AreaName,
+ AreaName = pluginAttribute == null ? null : pluginAttribute.AreaName,
ControllerName = ControllerExtensions.GetControllerName(type),
ControllerNamespace = type.Namespace,
- ControllerType = type
+ ControllerType = type,
+ IsBackOffice = backOfficeAttribute != null
};
MetadataStorage.TryAdd(type, meta);
diff --git a/src/Umbraco.Web/Mvc/PluginControllerMetadata.cs b/src/Umbraco.Web/Mvc/PluginControllerMetadata.cs
index dfe01ef3a3..6de8525de9 100644
--- a/src/Umbraco.Web/Mvc/PluginControllerMetadata.cs
+++ b/src/Umbraco.Web/Mvc/PluginControllerMetadata.cs
@@ -11,5 +11,11 @@ namespace Umbraco.Web.Mvc
internal string ControllerName { get; set; }
internal string ControllerNamespace { get; set; }
internal string AreaName { get; set; }
+
+ ///
+ /// This is determined by another attribute [IsBackOffice] which slightly modifies the route path
+ /// allowing us to determine if it is indeed a back office request or not
+ ///
+ internal bool IsBackOffice { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
index 79edd8192e..ab478c6c2b 100644
--- a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
+++ b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
@@ -55,7 +55,7 @@ namespace Umbraco.Web.Strategies
}
- static void UmbracoModuleRouteAttempt(object sender, Routing.RoutableAttemptEventArgs e)
+ static void UmbracoModuleRouteAttempt(object sender, RoutableAttemptEventArgs e)
{
if (e.HttpContext.Request == null || e.HttpContext.Request.Url == null) return;
@@ -78,7 +78,7 @@ namespace Umbraco.Web.Strategies
if (e.Outcome == EnsureRoutableOutcome.NotDocumentRequest)
{
//check if this is in the umbraco back office
- if (e.HttpContext.Request.Url.IsBackOfficeRequest())
+ if (e.HttpContext.Request.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath))
{
//yup it's a back office request!
using (var lck = new UpgradeableReadLock(Locker))
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 076e7d6fbe..83d7ba6288 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -457,6 +457,7 @@
+
diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs
index 5ba568c56e..f058b85461 100644
--- a/src/Umbraco.Web/UmbracoModule.cs
+++ b/src/Umbraco.Web/UmbracoModule.cs
@@ -139,7 +139,7 @@ namespace Umbraco.Web
if (http.Request.Url.IsClientSideRequest())
return;
- if (app.Request.Url.IsBackOfficeRequest() || app.Request.Url.IsInstallerRequest())
+ if (app.Request.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath) || app.Request.Url.IsInstallerRequest())
{
var ticket = http.GetUmbracoAuthTicket();
if (ticket != null)
diff --git a/src/Umbraco.Web/WebApi/IsBackOfficeAttribute.cs b/src/Umbraco.Web/WebApi/IsBackOfficeAttribute.cs
new file mode 100644
index 0000000000..219be51d48
--- /dev/null
+++ b/src/Umbraco.Web/WebApi/IsBackOfficeAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Umbraco.Web.WebApi
+{
+ ///
+ /// When applied to an api controller it will be routed to the /Umbraco/BackOffice prefix route so we can determine if it
+ /// is a back office route or not.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+ public sealed class IsBackOfficeAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs
index d0ede6fcda..782b206bbd 100644
--- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs
+++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs
@@ -7,6 +7,7 @@ using umbraco.BusinessLogic;
namespace Umbraco.Web.WebApi
{
+ [IsBackOffice]
[UmbracoAuthorize]
public abstract class UmbracoAuthorizedApiController : UmbracoApiController
{
diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs
index 1fd2371eb7..536eb23b84 100644
--- a/src/Umbraco.Web/WebBootManager.cs
+++ b/src/Umbraco.Web/WebBootManager.cs
@@ -231,9 +231,15 @@ namespace Umbraco.Web
private void RouteLocalApiController(Type controller, string umbracoPath)
{
var meta = PluginController.GetMetadata(controller);
+
+ //url to match
+ var routePath = meta.IsBackOffice == false
+ ? umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}"
+ : umbracoPath + "/BackOffice/Api/" + meta.ControllerName + "/{action}/{id}";
+
var route = RouteTable.Routes.MapHttpRoute(
string.Format("umbraco-{0}-{1}", "api", meta.ControllerName),
- umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}", //url to match
+ routePath,
new {controller = meta.ControllerName, id = UrlParameter.Optional});
//web api routes don't set the data tokens object
if (route.DataTokens == null)
From 5c614a88a2efc6101d66d2e7785f48c96c160ea5 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 13:29:17 +1100
Subject: [PATCH 047/100] ensures webapi plugincontrollers are routed to
/backoffice if [IsBackOffice] is specified
---
src/Umbraco.Core/UriExtensions.cs | 6 +-----
src/Umbraco.Tests/UriExtensionsTests.cs | 2 --
src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs | 15 ++++++++++++---
src/Umbraco.Web/Mvc/PluginControllerArea.cs | 4 +++-
4 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs
index 058c53892c..45cb906eef 100644
--- a/src/Umbraco.Core/UriExtensions.cs
+++ b/src/Umbraco.Core/UriExtensions.cs
@@ -27,8 +27,6 @@ namespace Umbraco.Core
/// These are def back office:
/// /Umbraco/RestServices = back office
/// /Umbraco/BackOffice = back office
- /// /Umbraco/UmbracpApi = back office
- /// /Umbraco/UmbracoTrees = back office
/// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end
/// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice
/// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute.
@@ -75,9 +73,7 @@ namespace Umbraco.Core
}
//check for special back office paths
- if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/UmbracoApi/")
- || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/UmbracoTrees/")
- || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/BackOffice/")
+ if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/BackOffice/")
|| urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/RestServices/"))
{
return true;
diff --git a/src/Umbraco.Tests/UriExtensionsTests.cs b/src/Umbraco.Tests/UriExtensionsTests.cs
index 9a6cfcae17..8e826fc428 100644
--- a/src/Umbraco.Tests/UriExtensionsTests.cs
+++ b/src/Umbraco.Tests/UriExtensionsTests.cs
@@ -23,8 +23,6 @@ namespace Umbraco.Tests
[TestCase("http://www.domain.com/test/umbraco.aspx", "", false)]
[TestCase("http://www.domain.com/Umbraco/restServices/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)]
- [TestCase("http://www.domain.com/Umbraco/umbracoapi/blah", "", true)]
- [TestCase("http://www.domain.com/Umbraco/umbracotrees/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything/", "", true)]
[TestCase("http://www.domain.com/Umbraco/surface/blah", "", false)]
diff --git a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs
index 833fe92906..2836c458fb 100644
--- a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs
+++ b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs
@@ -27,13 +27,20 @@ namespace Umbraco.Web.Mvc
/// The DataToken value to set for the 'umbraco' key, this defaults to 'backoffice'
/// By default this value is just {action}/{id} but can be modified for things like web api routes
/// Default is true for MVC, otherwise false for WebAPI
+ ///
+ /// If specified will add this string to the path between the umbraco path and the area path name, for example:
+ /// /umbraco/CUSTOMPATHPREFIX/areaname
+ /// if not specified, will just route like:
+ /// /umbraco/areaname
+ ///
///
///
internal static Route RouteControllerPlugin(this AreaRegistration area, string controllerName, Type controllerType, RouteCollection routes,
string controllerSuffixName, string defaultAction, object defaultId,
string umbracoTokenValue = "backoffice",
string routeTokens = "{action}/{id}",
- bool isMvc = true)
+ bool isMvc = true,
+ string areaPathPrefix = "")
{
Mandate.ParameterNotNullOrEmpty(controllerName, "controllerName");
Mandate.ParameterNotNull(controllerSuffixName, "controllerSuffixName");
@@ -44,8 +51,10 @@ namespace Umbraco.Web.Mvc
var umbracoArea = GlobalSettings.UmbracoMvcArea;
- //routes are explicitly name with controller names and IDs
- var url = umbracoArea + "/" + area.AreaName + "/" + controllerName + "/" + routeTokens;
+ //routes are explicitly named with controller names and IDs
+ var url = umbracoArea + "/" +
+ (areaPathPrefix.IsNullOrWhiteSpace() ? "" : areaPathPrefix + "/") +
+ area.AreaName + "/" + controllerName + "/" + routeTokens;
Route controllerPluginRoute;
//var meta = PluginController.GetMetadata(controllerType);
diff --git a/src/Umbraco.Web/Mvc/PluginControllerArea.cs b/src/Umbraco.Web/Mvc/PluginControllerArea.cs
index 2d4c1a56ce..e197804031 100644
--- a/src/Umbraco.Web/Mvc/PluginControllerArea.cs
+++ b/src/Umbraco.Web/Mvc/PluginControllerArea.cs
@@ -85,7 +85,9 @@ namespace Umbraco.Web.Mvc
{
foreach (var s in apiControllers)
{
- this.RouteControllerPlugin(s.ControllerName, s.ControllerType, routes, "", "", UrlParameter.Optional, "api", isMvc: false);
+ this.RouteControllerPlugin(s.ControllerName, s.ControllerType, routes, "", "", UrlParameter.Optional, "api",
+ isMvc: false,
+ areaPathPrefix: s.IsBackOffice ? "backoffice" : null);
}
}
}
From 6d57afc71a4dd4c9922f5652174a66c5c2dc8552 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 13:49:37 +1100
Subject: [PATCH 048/100] ensures auth controller has IsBackOffice specified
---
src/Umbraco.Web/Editors/AuthenticationController.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index f37b61eae8..5e1672fa90 100644
--- a/src/Umbraco.Web/Editors/AuthenticationController.cs
+++ b/src/Umbraco.Web/Editors/AuthenticationController.cs
@@ -30,6 +30,7 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
[ValidationFilter]
[AngularJsonOnlyConfiguration]
+ [IsBackOffice]
public class AuthenticationController : UmbracoApiController
{
From bb837232bad2eb5ce196538a2e59ba0e56fb37f1 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 14:45:33 +1100
Subject: [PATCH 049/100] Allows DefaultPropertyValueConverters to shadow other
default converters, this allows us to have a hierarchy of default converters.
This also fixes part of this issue: U4-4030 RelatedLinksEditorValueConvertor
can't be overruled and internal links are wrong
---
.../PublishedContent/PublishedPropertyType.cs | 43 +++++++++++++++----
.../DefaultPropertyValueConverterAttribute.cs | 24 +++++++++++
.../PropertyValueConvertersResolver.cs | 38 ++++++++++++++++
.../RelatedLinksEditorValueConvertor.cs | 1 +
4 files changed, 97 insertions(+), 9 deletions(-)
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs
index 295cbdef66..c8bf96be8f 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs
@@ -80,11 +80,8 @@ namespace Umbraco.Core.Models.PublishedContent
private void InitializeConverters()
{
- var converters = PropertyValueConvertersResolver.Current.Converters.ToArray();
-
- var defaultConverters = converters
- .Where(x => x.GetType().GetCustomAttribute(false) != null)
- .ToArray();
+ var converters = PropertyValueConvertersResolver.Current.Converters.ToArray();
+ var defaultConvertersWithAttributes = PropertyValueConvertersResolver.Current.DefaultConverters;
_converter = null;
@@ -98,8 +95,14 @@ namespace Umbraco.Core.Models.PublishedContent
else if (foundConverters.Length > 1)
{
//more than one was found, we need to first figure out if one of these is an Umbraco default value type converter
- var nonDefault = foundConverters.Except(defaultConverters).ToArray();
- if (nonDefault.Length > 1)
+ //get the non-default and see if we have one
+ var nonDefault = foundConverters.Except(defaultConvertersWithAttributes.Select(x => x.Item1)).ToArray();
+ if (nonDefault.Length == 1)
+ {
+ //there's only 1 custom converter registered that so use it
+ _converter = nonDefault[0];
+ }
+ else if (nonDefault.Length > 1)
{
//this is not allowed, there cannot be more than 1 custom converter
throw new InvalidOperationException(
@@ -109,9 +112,31 @@ namespace Umbraco.Core.Models.PublishedContent
ContentType.Alias, PropertyTypeAlias,
nonDefault[1].GetType().FullName, nonDefault[0].GetType().FullName));
}
+ else
+ {
+ //we need to remove any converters that have been shadowed by another converter
+ var foundDefaultConvertersWithAttributes = defaultConvertersWithAttributes.Where(x => foundConverters.Contains(x.Item1));
+ var shadowedTypes = foundDefaultConvertersWithAttributes.SelectMany(x => x.Item2.DefaultConvertersToShadow);
+ var shadowedDefaultConverters = foundConverters.Where(x => shadowedTypes.Contains(x.GetType()));
+ var nonShadowedDefaultConverters = foundConverters.Except(shadowedDefaultConverters).ToArray();
- //there's only 1 custom converter registered that so use it
- _converter = nonDefault[0];
+ if (nonShadowedDefaultConverters.Length == 1)
+ {
+ //assign to the single default converter
+ _converter = nonShadowedDefaultConverters[0];
+ }
+ else if (nonShadowedDefaultConverters.Length > 1)
+ {
+ //this is not allowed, there cannot be more than 1 custom converter
+ throw new InvalidOperationException(
+ string.Format("Type '{2}' cannot be an IPropertyValueConverter"
+ + " for property '{1}' of content type '{0}' because type '{3}' has already been detected as a converter"
+ + " for that property, and only one converter can exist for a property.",
+ ContentType.Alias, PropertyTypeAlias,
+ nonShadowedDefaultConverters[1].GetType().FullName, nonShadowedDefaultConverters[0].GetType().FullName));
+ }
+ }
+
}
// get the cache levels, quietely fixing the inconsistencies (no need to throw, really)
diff --git a/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs b/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs
index 4857e2bb07..10bdd053a8 100644
--- a/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs
+++ b/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
namespace Umbraco.Core.PropertyEditors
{
@@ -8,5 +10,27 @@ namespace Umbraco.Core.PropertyEditors
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
internal class DefaultPropertyValueConverterAttribute : Attribute
{
+ public DefaultPropertyValueConverterAttribute()
+ {
+ DefaultConvertersToShadow = Enumerable.Empty();
+ }
+
+ public DefaultPropertyValueConverterAttribute(params Type[] convertersToShadow)
+ {
+ DefaultConvertersToShadow = convertersToShadow;
+ }
+
+ ///
+ /// A DefaultPropertyValueConverter can 'shadow' other default property value converters so that
+ /// a DefaultPropertyValueConverter can be more specific than another one.
+ ///
+ ///
+ /// An example where this is useful is that both the RelatedLiksEditorValueConverter and the JsonValueConverter
+ /// will be returned as value converters for the Related Links Property editor, however the JsonValueConverter
+ /// is a very generic converter and the RelatedLiksEditorValueConverter is more specific than it, so the RelatedLiksEditorValueConverter
+ /// can specify that it 'shadows' the JsonValueConverter.
+ ///
+ public IEnumerable DefaultConvertersToShadow { get; private set; }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueConvertersResolver.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueConvertersResolver.cs
index 53fecdac9d..295fdb4b09 100644
--- a/src/Umbraco.Core/PropertyEditors/PropertyValueConvertersResolver.cs
+++ b/src/Umbraco.Core/PropertyEditors/PropertyValueConvertersResolver.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Core.PropertyEditors
@@ -36,5 +38,41 @@ namespace Umbraco.Core.PropertyEditors
{
get { return Values; }
}
+
+ private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
+ private Tuple[] _defaults = null;
+
+ ///
+ /// Caches and gets the default converters with their metadata
+ ///
+ internal Tuple[] DefaultConverters
+ {
+ get
+ {
+ using (var locker = new UpgradeableReadLock(_lock))
+ {
+ if (_defaults == null)
+ {
+ locker.UpgradeToWriteLock();
+
+ var defaultConvertersWithAttributes = Converters
+ .Select(x => new
+ {
+ attribute = x.GetType().GetCustomAttribute(false),
+ converter = x
+ })
+ .Where(x => x.attribute != null)
+ .ToArray();
+
+ _defaults = defaultConvertersWithAttributes
+ .Select(
+ x => new Tuple(x.converter, x.attribute))
+ .ToArray();
+ }
+
+ return _defaults;
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
index 469175f75f..e2431255d0 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
@@ -16,6 +16,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(JToken))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
+ [DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
public class RelatedLinksEditorValueConvertor : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
From 9f078357a791436e55e214dc96bb2f8aa65f5232 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 15:17:03 +1100
Subject: [PATCH 050/100] Fixes: U4-4030 RelatedLinksEditorValueConvertor can't
be overruled and internal links are wrong
---
.../RelatedLinksEditorValueConvertor.cs | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
index e2431255d0..9d3b50f2d9 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs
@@ -14,7 +14,7 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
- [PropertyValueType(typeof(JToken))]
+ [PropertyValueType(typeof(JArray))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
public class RelatedLinksEditorValueConvertor : PropertyValueConverterBase
@@ -33,7 +33,25 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
{
try
{
- var obj = JsonConvert.DeserializeObject(sourceString);
+ var obj = JsonConvert.DeserializeObject(sourceString);
+ //update the internal links if we have a context
+ if (UmbracoContext.Current != null)
+ {
+ var helper = new UmbracoHelper(UmbracoContext.Current);
+ foreach (var a in obj)
+ {
+ var type = a.Value("type");
+ if (type.IsNullOrWhiteSpace() == false)
+ {
+ if (type == "internal")
+ {
+ var linkId = a.Value("link");
+ var link = helper.NiceUrl(linkId);
+ a["link"] = link;
+ }
+ }
+ }
+ }
return obj;
}
catch (Exception ex)
From cf3de52249214babb3df991e5e977c8f3e73d22a Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 15:36:28 +1100
Subject: [PATCH 051/100] removes the old language.ascx webforms files
---
.../umbraco/create/language.ascx | 2 +-
src/Umbraco.Web/Umbraco.Web.csproj | 13 +--
.../umbraco/create/language.ascx | 17 ----
.../umbraco/create/language.ascx.cs | 81 ++++++++++---------
.../umbraco/create/language.ascx.designer.cs | 51 ------------
5 files changed, 46 insertions(+), 118 deletions(-)
delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx
delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.designer.cs
diff --git a/src/Umbraco.Web.UI/umbraco/create/language.ascx b/src/Umbraco.Web.UI/umbraco/create/language.ascx
index feffae0a34..1814d741f6 100644
--- a/src/Umbraco.Web.UI/umbraco/create/language.ascx
+++ b/src/Umbraco.Web.UI/umbraco/create/language.ascx
@@ -1,4 +1,4 @@
-<%@ Control Language="c#" AutoEventWireup="True" Codebehind="language.ascx.cs" Inherits="umbraco.cms.presentation.create.controls.language" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
+<%@ Control Language="c#" AutoEventWireup="True" Inherits="umbraco.cms.presentation.create.controls.language" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index d4d6931953..0a0573a4f5 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -424,6 +424,9 @@
ASPXCodeBehind
+
+ ASPXCodeBehind
+ ASPXCodeBehind
@@ -1205,13 +1208,6 @@
Code
-
- language.ascx
- ASPXCodeBehind
-
-
- language.ascx
- media.ascxASPXCodeBehind
@@ -1926,9 +1922,6 @@
ASPXCodeBehind
-
- ASPXCodeBehind
- ASPXCodeBehind
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx b/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx
deleted file mode 100644
index c0d359b612..0000000000
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx
+++ /dev/null
@@ -1,17 +0,0 @@
-<%@ Control Language="c#" AutoEventWireup="True" Codebehind="language.ascx.cs" Inherits="umbraco.cms.presentation.create.controls.language" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
-<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
-
-
-
-
-
-
- *
-
-
-
-
- <%=umbraco.ui.Text("cancel")%>
-
-
-
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.cs
index 017b7fe9b4..5799f932e1 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.Globalization;
using System.Web;
@@ -16,9 +16,6 @@ namespace umbraco.cms.presentation.create.controls
///
public partial class language : UserControl
{
- private Language[] m_langs = Language.getAll;
-
-
protected void Page_Load(object sender, EventArgs e)
{
// get all existing languages
@@ -31,7 +28,7 @@ namespace umbraco.cms.presentation.create.controls
Cultures.Items.Add(new ListItem(ui.Text("choose") + "...", ""));
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures))
{
- sortedCultures.Add(ci.DisplayName + "|||" + Guid.NewGuid().ToString(), ci.Name);
+ sortedCultures.Add(ci.DisplayName + "|||" + Guid.NewGuid().ToString(), ci.Name);
}
IDictionaryEnumerator ide = sortedCultures.GetEnumerator();
@@ -42,37 +39,6 @@ namespace umbraco.cms.presentation.create.controls
}
}
- private bool languageExists(string culture)
- {
- foreach (Language l in m_langs)
- {
- if (l.CultureAlias == culture)
- return true;
- }
- return false;
- }
-
- #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);
- }
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- }
-
- #endregion
-
protected void sbmt_Click(object sender, EventArgs e)
{
LegacyDialogHandler.Create(
@@ -82,10 +48,47 @@ namespace umbraco.cms.presentation.create.controls
-1,
Cultures.SelectedValue);
- BasePage.Current.ClientTools
- .ChildNodeCreated()
- .CloseModalWindow();
+ BasePage.Current.ClientTools
+ .ChildNodeCreated()
+ .CloseModalWindow();
}
+
+ ///
+ /// pp1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel pp1;
+
+ ///
+ /// Cultures control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.DropDownList Cultures;
+
+ ///
+ /// RequiredFieldValidator1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
+
+ ///
+ /// sbmt control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button sbmt;
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.designer.cs
deleted file mode 100644
index d3945627fd..0000000000
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/language.ascx.designer.cs
+++ /dev/null
@@ -1,51 +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.create.controls {
-
-
- public partial class language {
-
- ///
- /// pp1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel pp1;
-
- ///
- /// Cultures control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.DropDownList Cultures;
-
- ///
- /// RequiredFieldValidator1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
-
- ///
- /// sbmt control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Button sbmt;
- }
-}
From 0bc39afdabe858973132b0a829855881cf0e01b6 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 15:39:35 +1100
Subject: [PATCH 052/100] fixes language drop down styles - was too big to fit
---
src/Umbraco.Web.UI/umbraco/create/language.ascx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI/umbraco/create/language.ascx b/src/Umbraco.Web.UI/umbraco/create/language.ascx
index 1814d741f6..686cbbdb96 100644
--- a/src/Umbraco.Web.UI/umbraco/create/language.ascx
+++ b/src/Umbraco.Web.UI/umbraco/create/language.ascx
@@ -5,7 +5,7 @@
-
+ *
From 0e6c199a7e7d4776ecb82d974c23d44f4dc67439 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 17:18:23 +1100
Subject: [PATCH 053/100] working on U4-4011 Package installation will require
either a full app refresh or we will need to re-lazy load in all of the
assets but unfortunately we cannot lazy load in things like directives as
angular doesn't like that, we have to re-load the browser.
---
.../lib/umbraco/LegacyUmbClientMgr.js | 6 +
.../directives/umbsections.directive.js | 5 +
.../src/common/services/assets.service.js | 19 +-
.../src/common/services/events.service.js | 2 +-
.../src/common/services/util.service.js | 16 +
.../umbraco/developer/Packages/installer.aspx | 8 +
.../Editors/BackOfficeController.cs | 22 +
src/Umbraco.Web/Mvc/JsonNetResult.cs | 56 ++
.../UI/JavaScript/CssInitialization.cs | 9 +-
.../UI/JavaScript/JsInitialization.cs | 13 +-
src/Umbraco.Web/Umbraco.Web.csproj | 12 +-
.../umbraco/developer/Packages/installer.aspx | 261 ---------
.../developer/Packages/installer.aspx.cs | 538 ++++++++++++++++--
.../Packages/installer.aspx.designer.cs | 433 --------------
14 files changed, 632 insertions(+), 768 deletions(-)
create mode 100644 src/Umbraco.Web/Mvc/JsonNetResult.cs
delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx
delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs
diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js
index 912c624ce4..5db8fc074e 100644
--- a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js
+++ b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js
@@ -364,6 +364,12 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
getRootScope().$emit("app.closeDialogs", undefined);
}
},
+ /* This is used for the package installer to call in order to reload all app assets so we don't have to reload the window */
+ _packageInstalled: function() {
+ var injector = getRootInjector();
+ var packageHelper = injector.get("packageHelper");
+ packageHelper.packageInstalled();
+ },
_debug: function(strMsg) {
if (this._isDebug) {
Sys.Debug.trace("UmbClientMgr: " + strMsg);
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbsections.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbsections.directive.js
index 349bf0a496..b6b59991b5 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbsections.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbsections.directive.js
@@ -65,6 +65,11 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
scope.currentSection = args.value;
}
});
+
+ eventsService.on("app.reInitialize", function (e, args) {
+ //re-load the sections if we're re-initializing (i.e. package installed)
+ loadSections();
+ });
//on page resize
window.onresize = calculateHeight;
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
index ef534fd7b1..dbf1d3fc14 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
@@ -41,7 +41,7 @@
*
*/
angular.module('umbraco.services')
-.factory('assetsService', function ($q, $log, angularHelper, umbRequestHelper, $rootScope) {
+.factory('assetsService', function ($q, $log, angularHelper, umbRequestHelper, $rootScope, $http) {
var initAssetsLoaded = false;
@@ -71,6 +71,23 @@ angular.module('umbraco.services')
return deferred.promise;
},
+ /** Internal method. This is used after installing a package to reload the application assets so we don't have to reload the whole window */
+ _reloadApplicationAssets: function() {
+
+ umbRequestHelper.resourcePromise(
+ $http.get(umbRequestHelper.getApiUrl("manifestAssetList", "", "")),
+ 'Failed to get manifest list').then(function(data) {
+
+ //ok so we have the list of assets, now we'll use yepnope to go get them. Anything that is already loaded should remain loaded
+ // and this should just load anything that is newly installed.
+
+ yepnope({
+ load: data
+ });
+
+ });
+ },
+
/**
* @ngdoc method
* @name umbraco.services.assetsService#loadCss
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/events.service.js b/src/Umbraco.Web.UI.Client/src/common/services/events.service.js
index 560b743a29..d050b62961 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/events.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/events.service.js
@@ -65,7 +65,7 @@ function eventsService($q, $rootScope) {
return $rootScope.$on(name, callback);
},
- /** pass in the result of subscribe to this method, or just call the method returned from subscribe to unsubscribe */
+ /** pass in the result of 'on' to this method, or just call the method returned from 'on' to unsubscribe */
unsubscribe: function(handle) {
if (angular.isFunction(handle)) {
handle();
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
index 5abc1116d6..8f47a2270d 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
@@ -1,5 +1,21 @@
/*Contains multiple services for various helper tasks */
+function packageHelper(assetsService, treeService, eventsService) {
+
+ return {
+
+ /** Called when a package is installed, this resets a bunch of data and ensures the new package assets are loaded in */
+ packageInstalled: function () {
+ assetsService._reloadApplicationAssets();
+ treeService.clearCache();
+ //send event
+ eventsService.emit("app.reInitialize");
+ }
+
+ };
+}
+angular.module('umbraco.services').factory('packageHelper', packageHelper);
+
function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, umbRequestHelper) {
return {
/** sets the image's url - will check if it is a folder or a real image */
diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
index 481a030bcc..6a94b46980 100644
--- a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
+++ b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
@@ -260,6 +260,14 @@
+
+ <%--This is a hack to fix this currently until we can replace the installer with a native angular editor
+ http://issues.umbraco.org/issue/U4-4011
+ --%>
+
+
All items in the package has been installed
diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs
index 899229b9cf..8c3d3a6039 100644
--- a/src/Umbraco.Web/Editors/BackOfficeController.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeController.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using System.Web.UI;
+using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
@@ -68,6 +69,26 @@ namespace Umbraco.Web.Editors
return JavaScript(result);
}
+ ///
+ /// Returns a js array of all of the manifest assets
+ ///
+ ///
+ [UmbracoAuthorize(Order = 0)]
+ [HttpGet]
+ public JsonNetResult GetManifestAssetList()
+ {
+ var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
+ var parser = new ManifestParser(plugins);
+ var initJs = new JsInitialization(parser);
+ var initCss = new CssInitialization(parser);
+ var jsResult = initJs.GetJavascriptInitializationArray(HttpContext, new JArray());
+ var cssResult = initCss.GetStylesheetInitializationArray(HttpContext);
+
+ ManifestParser.MergeJArrays(jsResult, cssResult);
+
+ return new JsonNetResult {Data = jsResult, Formatting = Formatting.Indented};
+ }
+
///
/// Returns the JavaScript object representing the static server variables javascript object
///
@@ -86,6 +107,7 @@ namespace Umbraco.Web.Editors
"umbracoUrls", new Dictionary
{
{"legacyTreeJs", Url.Action("LegacyTreeJs", "BackOffice")},
+ {"manifestAssetList", Url.Action("GetManifestAssetList", "BackOffice")},
//API URLs
{
"contentApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl(
diff --git a/src/Umbraco.Web/Mvc/JsonNetResult.cs b/src/Umbraco.Web/Mvc/JsonNetResult.cs
new file mode 100644
index 0000000000..da6780451e
--- /dev/null
+++ b/src/Umbraco.Web/Mvc/JsonNetResult.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using System.Web.Mvc;
+using Newtonsoft.Json;
+
+namespace Umbraco.Web.Mvc
+{
+
+ ///
+ /// Custom json result using newtonsoft json.net
+ ///
+ public class JsonNetResult : ActionResult
+ {
+ public Encoding ContentEncoding { get; set; }
+ public string ContentType { get; set; }
+ public object Data { get; set; }
+
+ public JsonSerializerSettings SerializerSettings { get; set; }
+ public Formatting Formatting { get; set; }
+
+ public JsonNetResult()
+ {
+ SerializerSettings = new JsonSerializerSettings();
+ }
+
+ public override void ExecuteResult(ControllerContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ HttpResponseBase response = context.HttpContext.Response;
+
+ response.ContentType = string.IsNullOrEmpty(ContentType) == false
+ ? ContentType
+ : "application/json";
+
+ if (ContentEncoding != null)
+ response.ContentEncoding = ContentEncoding;
+
+ if (Data != null)
+ {
+ var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
+
+ var serializer = JsonSerializer.Create(SerializerSettings);
+ serializer.Serialize(writer, Data);
+
+ writer.Flush();
+ }
+ }
+ }
+
+}
diff --git a/src/Umbraco.Web/UI/JavaScript/CssInitialization.cs b/src/Umbraco.Web/UI/JavaScript/CssInitialization.cs
index a483d7f776..c2b200604e 100644
--- a/src/Umbraco.Web/UI/JavaScript/CssInitialization.cs
+++ b/src/Umbraco.Web/UI/JavaScript/CssInitialization.cs
@@ -24,6 +24,13 @@ namespace Umbraco.Web.UI.JavaScript
/// Processes all found manifest files and outputs yepnope.injectcss calls for all css files found in all manifests
///
public string GetStylesheetInitialization(HttpContextBase httpContext)
+ {
+ var result = GetStylesheetInitializationArray(httpContext);
+
+ return ParseMain(result);
+ }
+
+ public JArray GetStylesheetInitializationArray(HttpContextBase httpContext)
{
var merged = new JArray();
foreach (var m in _parser.GetManifests())
@@ -37,7 +44,7 @@ namespace Umbraco.Web.UI.JavaScript
//now we need to merge in any found cdf declarations on property editors
ManifestParser.MergeJArrays(merged, ScanPropertyEditors(ClientDependencyType.Css, httpContext));
- return ParseMain(merged);
+ return merged;
}
diff --git a/src/Umbraco.Web/UI/JavaScript/JsInitialization.cs b/src/Umbraco.Web/UI/JavaScript/JsInitialization.cs
index e78a329db0..51c780cfc2 100644
--- a/src/Umbraco.Web/UI/JavaScript/JsInitialization.cs
+++ b/src/Umbraco.Web/UI/JavaScript/JsInitialization.cs
@@ -39,6 +39,15 @@ namespace Umbraco.Web.UI.JavaScript
/// Processes all found manifest files and outputs the main.js file containing all plugin manifests
///
public string GetJavascriptInitialization(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
+ {
+ var result = GetJavascriptInitializationArray(httpContext, umbracoInit, additionalJsFiles);
+
+ return ParseMain(
+ result.ToString(),
+ IOHelper.ResolveUrl(SystemDirectories.Umbraco));
+ }
+
+ public JArray GetJavascriptInitializationArray(HttpContextBase httpContext, JArray umbracoInit, JArray additionalJsFiles = null)
{
foreach (var m in _parser.GetManifests())
{
@@ -57,9 +66,7 @@ namespace Umbraco.Web.UI.JavaScript
//now we need to merge in any found cdf declarations on property editors
ManifestParser.MergeJArrays(umbracoInit, ScanPropertyEditors(ClientDependencyType.Javascript, httpContext));
- return ParseMain(
- umbracoInit.ToString(),
- IOHelper.ResolveUrl(SystemDirectories.Umbraco));
+ return umbracoInit;
}
///
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 0a0573a4f5..ce74fb02a8 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -305,6 +305,7 @@
+
@@ -433,6 +434,9 @@
ASPXCodeBehind
+
+ ASPXCodeBehind
+ ASPXCodeBehind
@@ -1363,13 +1367,6 @@
notifications.aspx
-
- installer.aspx
- ASPXCodeBehind
-
-
- installer.aspx
- RegexWs.aspxASPXCodeBehind
@@ -1867,7 +1864,6 @@
ASPXCodeBehind
- ASPXCodeBehind
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx
deleted file mode 100644
index e271bf7413..0000000000
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx
+++ /dev/null
@@ -1,261 +0,0 @@
-<%@ Page Language="c#" MasterPageFile="../../masterpages/umbracoPage.Master" CodeBehind="installer.aspx.cs"
- AutoEventWireup="True" Inherits="umbraco.presentation.developer.packages.Installer"
- Trace="false" %>
-<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Only install packages from sources you know and trust!
-
- When installing an Umbraco package you should use the same caution as when you install
- an application on your computer.
-
- A malicious package could damage your Umbraco installation just like a malicious
- application can damage your computer.
-
-
- It is recommended to install from the official Umbraco package
- repository or a custom repository whenever it's possible.
-
- This repository requires authentication before you can download any packages from
- it.
- Please enter email and password to login.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Please note: Installing a package containing several items and
- files can take some time. Do not refresh the page or navigate away before, the installer
- notifies you the install is completed.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Binary files in the package!
-
- Read more...
-
-
-
- This package contains .NET code. This is not unusual as .NET code
- is used for any advanced functionality on an Umbraco powered website.
-
- However, if you don't know the author of the package or are unsure why this package
- contains these files, it is adviced not to continue the installation.
-
-
- The Files in question:
-
-
-
-
-
-
-
-
-
-
- Macro Conflicts in the package!
-
- Read more...
-
-
-
- This package contains one or more macros which have the same alias as an existing one on your site, based on the Macro Alias.
-
-
- If you choose to continue your existing macros will be replaced with the ones from this package. If you do not want to overwrite your existing macros you will need to change their alias.
-
-
- The Macros in question:
-
-
-
-
-
-
-
-
-
-
- Template Conflicts in the package!
-
- Read more...
-
-
-
- This package contains one or more templates which have the same alias as an existing one on your site, based on the Template Alias.
-
-
- If you choose to continue your existing template will be replaced with the ones from this package. If you do not want to overwrite your existing templates you will need to change their alias.
-
-
- The Templates in question:
-
-
-
-
-
-
-
-
-
-
- Stylesheet Conflicts in the package!
-
- Read more...
-
-
-
- This package contains one or more stylesheets which have the same alias as an existing one on your site, based on the Stylesheet Name.
-
-
- If you choose to continue your existing stylesheets will be replaced with the ones from this package. If you do not want to overwrite your existing stylesheets you will need to change their name.
-
-
- The Stylesheets in question:
-
-
-
-
-
-
-
-
-
-
-
-
- Installing package, please wait...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- All items in the package has been installed
-
- Overview of what was installed can found under "installed package" in the developer
- section.
-
- Uninstall is available at the same location.
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
index e18d46c625..a192176fda 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
@@ -53,9 +53,9 @@ namespace umbraco.presentation.developer.packages
}
//if we are actually in the middle of installing something... meaning we keep redirecting back to this page with
- // custom query strings
- // TODO: SD: This process needs to be fixed/changed/etc... to use the InstallPackageController
- // http://issues.umbraco.org/issue/U4-1047
+ // custom query strings
+ // TODO: SD: This process needs to be fixed/changed/etc... to use the InstallPackageController
+ // http://issues.umbraco.org/issue/U4-1047
if (!string.IsNullOrEmpty(Request.GetItemAsString("installing")))
{
HideAllPanes();
@@ -63,22 +63,22 @@ namespace umbraco.presentation.developer.packages
ProcessInstall(Request.GetItemAsString("installing")); //process the current step
}
- else if (tempFile.Value.IsNullOrWhiteSpace() //if we haven't downloaded the .umb temp file yet
- && (!Request.GetItemAsString("guid").IsNullOrWhiteSpace() && !Request.GetItemAsString("repoGuid").IsNullOrWhiteSpace()))
+ else if (tempFile.Value.IsNullOrWhiteSpace() //if we haven't downloaded the .umb temp file yet
+ && (!Request.GetItemAsString("guid").IsNullOrWhiteSpace() && !Request.GetItemAsString("repoGuid").IsNullOrWhiteSpace()))
{
//we'll fetch the local information we have about our repo, to find out what webservice to query.
- _repo = cms.businesslogic.packager.repositories.Repository.getByGuid(Request.GetItemAsString("repoGuid"));
-
+ _repo = cms.businesslogic.packager.repositories.Repository.getByGuid(Request.GetItemAsString("repoGuid"));
+
if (_repo != null && _repo.HasConnection())
{
//from the webservice we'll fetch some info about the package.
- cms.businesslogic.packager.repositories.Package pack = _repo.Webservice.PackageByGuid(Request.GetItemAsString("guid"));
+ cms.businesslogic.packager.repositories.Package pack = _repo.Webservice.PackageByGuid(Request.GetItemAsString("guid"));
//if the package is protected we will ask for the users credentials. (this happens every time they try to fetch anything)
if (!pack.Protected)
{
//if it isn't then go straigt to the accept licens screen
- tempFile.Value = _installer.Import(_repo.fetch(Request.GetItemAsString("guid")));
+ tempFile.Value = _installer.Import(_repo.fetch(Request.GetItemAsString("guid")));
UpdateSettings();
}
@@ -212,25 +212,25 @@ namespace umbraco.presentation.developer.packages
private void ProcessInstall(string currentStep)
{
- var dir = Request.GetItemAsString("dir");
+ var dir = Request.GetItemAsString("dir");
var packageId = 0;
- int.TryParse(Request.GetItemAsString("pId"), out packageId);
+ int.TryParse(Request.GetItemAsString("pId"), out packageId);
switch (currentStep)
{
case "businesslogic":
- //first load in the config from the temporary directory
- //this will ensure that the installer have access to all the new files and the package manifest
- _installer.LoadConfig(dir);
+ //first load in the config from the temporary directory
+ //this will ensure that the installer have access to all the new files and the package manifest
+ _installer.LoadConfig(dir);
_installer.InstallBusinessLogic(packageId, dir);
//making sure that publishing actions performed from the cms layer gets pushed to the presentation
library.RefreshContent();
-
+
if (!string.IsNullOrEmpty(_installer.Control))
{
- Response.Redirect("installer.aspx?installing=customInstaller&dir=" + dir + "&pId=" + packageId.ToString() + "&customControl=" + Server.UrlEncode(_installer.Control) + "&customUrl=" + Server.UrlEncode(_installer.Url));
+ Response.Redirect("installer.aspx?installing=customInstaller&dir=" + dir + "&pId=" + packageId.ToString() + "&customControl=" + Server.UrlEncode(_installer.Control) + "&customUrl=" + Server.UrlEncode(_installer.Url));
}
else
{
@@ -238,50 +238,50 @@ namespace umbraco.presentation.developer.packages
}
break;
case "customInstaller":
- var customControl = Request.GetItemAsString("customControl");
+ var customControl = Request.GetItemAsString("customControl");
- if (!customControl.IsNullOrWhiteSpace())
+ if (!customControl.IsNullOrWhiteSpace())
{
HideAllPanes();
- _configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + customControl);
+ _configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + customControl);
_configControl.ID = "packagerConfigControl";
pane_optional.Controls.Add(_configControl);
pane_optional.Visible = true;
- if (!IsPostBack)
- {
- //We still need to clean everything up which is normally done in the Finished Action
- PerformPostInstallCleanup(packageId, dir);
- }
-
+ if (!IsPostBack)
+ {
+ //We still need to clean everything up which is normally done in the Finished Action
+ PerformPostInstallCleanup(packageId, dir);
+ }
+
}
else
{
//if the custom installer control is empty here (though it should never be because we've already checked for it previously)
- //then we should run the normal FinishedAction
- PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ //then we should run the normal FinishedAction
+ PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
}
break;
case "finished":
- PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
break;
default:
break;
}
}
- ///
- /// Perform the 'Finished' action of the installer
- ///
- ///
- ///
- ///
- private void PerformFinishedAction(int packageId, string dir, string url)
- {
- HideAllPanes();
- //string url = _installer.Url;
+ ///
+ /// Perform the 'Finished' action of the installer
+ ///
+ ///
+ ///
+ ///
+ private void PerformFinishedAction(int packageId, string dir, string url)
+ {
+ HideAllPanes();
+ //string url = _installer.Url;
string packageViewUrl = "installedPackage.aspx?id=" + packageId.ToString();
bt_viewInstalledPackage.OnClientClick = "document.location = '" + packageViewUrl + "'; return false;";
@@ -292,23 +292,23 @@ namespace umbraco.presentation.developer.packages
pane_success.Visible = true;
- PerformPostInstallCleanup(packageId, dir);
- }
+ PerformPostInstallCleanup(packageId, dir);
+ }
- ///
- /// Runs Post install actions such as clearning any necessary cache, reloading the correct tree nodes, etc...
- ///
- ///
- ///
- private void PerformPostInstallCleanup(int packageId, string dir)
- {
- BasePage.Current.ClientTools.ReloadActionNode(true, true);
- _installer.InstallCleanUp(packageId, dir);
- //clear the tree cache
- ClientTools.ClearClientTreeCache().RefreshTree("packager");
- TreeDefinitionCollection.Instance.ReRegisterTrees();
- BizLogicAction.ReRegisterActionsAndHandlers();
- }
+ ///
+ /// Runs Post install actions such as clearning any necessary cache, reloading the correct tree nodes, etc...
+ ///
+ ///
+ ///
+ private void PerformPostInstallCleanup(int packageId, string dir)
+ {
+ BasePage.Current.ClientTools.ReloadActionNode(true, true);
+ _installer.InstallCleanUp(packageId, dir);
+ //clear the tree cache
+ ClientTools.ClearClientTreeCache().RefreshTree("packager");
+ TreeDefinitionCollection.Instance.ReRegisterTrees();
+ BizLogicAction.ReRegisterActionsAndHandlers();
+ }
//this accepts the package, creates the manifest and then installs the files.
protected void startInstall(object sender, System.EventArgs e)
@@ -323,11 +323,11 @@ namespace umbraco.presentation.developer.packages
//and then copy over the files. This will take some time if it contains .dlls that will reboot the system..
_installer.InstallFiles(pId, tempFile.Value);
- //TODO: This is a total hack, we need to refactor the installer to be just like the package installer during the
- // install process and use AJAX to ensure that app pool restarts and restarts PROPERLY before installing the business
- // logic. Until then, we are going to put a thread sleep here for 2 seconds in hopes that we always fluke out and the app
- // pool will be restarted after redirect.
- Thread.Sleep(2000);
+ //TODO: This is a total hack, we need to refactor the installer to be just like the package installer during the
+ // install process and use AJAX to ensure that app pool restarts and restarts PROPERLY before installing the business
+ // logic. Until then, we are going to put a thread sleep here for 2 seconds in hopes that we always fluke out and the app
+ // pool will be restarted after redirect.
+ Thread.Sleep(2000);
Response.Redirect("installer.aspx?installing=businesslogic&dir=" + tempFile.Value + "&pId=" + pId.ToString());
}
@@ -341,5 +341,423 @@ namespace umbraco.presentation.developer.packages
pane_success.Visible = false;
pane_upload.Visible = false;
}
+
+ ///
+ /// Panel1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.UmbracoPanel Panel1;
+
+ ///
+ /// fb control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Feedback fb;
+
+ ///
+ /// pane_upload control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_upload;
+
+ ///
+ /// PropertyPanel9 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel9;
+
+ ///
+ /// file1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.HtmlControls.HtmlInputFile file1;
+
+ ///
+ /// ButtonLoadPackage control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button ButtonLoadPackage;
+
+ ///
+ /// progbar1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.ProgressBar progbar1;
+
+ ///
+ /// pane_authenticate control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_authenticate;
+
+ ///
+ /// tb_email control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.TextBox tb_email;
+
+ ///
+ /// PropertyPanel1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel1;
+
+ ///
+ /// tb_password control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.TextBox tb_password;
+
+ ///
+ /// PropertyPanel2 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel2;
+
+ ///
+ /// Button1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button Button1;
+
+ ///
+ /// pane_acceptLicense control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Panel pane_acceptLicense;
+
+ ///
+ /// pane_acceptLicenseInner control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_acceptLicenseInner;
+
+ ///
+ /// PropertyPanel3 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel3;
+
+ ///
+ /// LabelName control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Label LabelName;
+
+ ///
+ /// PropertyPanel5 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel5;
+
+ ///
+ /// LabelAuthor control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Label LabelAuthor;
+
+ ///
+ /// PropertyPanel4 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel4;
+
+ ///
+ /// LabelMore control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Label LabelMore;
+
+ ///
+ /// PropertyPanel6 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel6;
+
+ ///
+ /// LabelLicense control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Label LabelLicense;
+
+ ///
+ /// PropertyPanel7 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel7;
+
+ ///
+ /// acceptCheckbox control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.CheckBox acceptCheckbox;
+
+ ///
+ /// PropertyPanel8 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel PropertyPanel8;
+
+ ///
+ /// readme control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal readme;
+
+ ///
+ /// pp_unsecureFiles control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel pp_unsecureFiles;
+
+ ///
+ /// lt_files control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal lt_files;
+
+ ///
+ /// pp_macroConflicts control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel pp_macroConflicts;
+
+ ///
+ /// ltrMacroAlias control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal ltrMacroAlias;
+
+ ///
+ /// pp_templateConflicts control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel pp_templateConflicts;
+
+ protected global::umbraco.uicontrols.PropertyPanel BinaryFileErrorsPanel;
+ protected global::umbraco.uicontrols.PropertyPanel LegacyPropertyEditorPanel;
+ protected global::System.Web.UI.WebControls.Literal BinaryFileErrorReport;
+
+ ///
+ /// ltrTemplateAlias control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal ltrTemplateAlias;
+
+ ///
+ /// pp_stylesheetConflicts control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.PropertyPanel pp_stylesheetConflicts;
+
+ ///
+ /// ltrStylesheetNames control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal ltrStylesheetNames;
+
+ ///
+ /// _progbar1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.ProgressBar _progbar1;
+
+ ///
+ /// ButtonInstall control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button ButtonInstall;
+
+ ///
+ /// pane_installing control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_installing;
+
+ ///
+ /// progBar2 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.ProgressBar progBar2;
+
+ ///
+ /// lit_installStatus control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal lit_installStatus;
+
+ ///
+ /// pane_optional control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_optional;
+
+ ///
+ /// pane_success control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::umbraco.uicontrols.Pane pane_success;
+
+ ///
+ /// bt_viewInstalledPackage control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button bt_viewInstalledPackage;
+
+ ///
+ /// lit_authorUrl control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Literal lit_authorUrl;
+
+ ///
+ /// tempFile control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.HtmlControls.HtmlInputHidden tempFile;
+
+ ///
+ /// processState control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.HtmlControls.HtmlInputHidden processState;
}
}
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs
deleted file mode 100644
index abe1f67506..0000000000
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs
+++ /dev/null
@@ -1,433 +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.presentation.developer.packages {
-
-
- public partial class Installer {
-
- ///
- /// Panel1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.UmbracoPanel Panel1;
-
- ///
- /// fb control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Feedback fb;
-
- ///
- /// pane_upload control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_upload;
-
- ///
- /// PropertyPanel9 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel9;
-
- ///
- /// file1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.HtmlControls.HtmlInputFile file1;
-
- ///
- /// ButtonLoadPackage control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Button ButtonLoadPackage;
-
- ///
- /// progbar1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.ProgressBar progbar1;
-
- ///
- /// pane_authenticate control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_authenticate;
-
- ///
- /// tb_email control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.TextBox tb_email;
-
- ///
- /// PropertyPanel1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel1;
-
- ///
- /// tb_password control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.TextBox tb_password;
-
- ///
- /// PropertyPanel2 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel2;
-
- ///
- /// Button1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Button Button1;
-
- ///
- /// pane_acceptLicense control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Panel pane_acceptLicense;
-
- ///
- /// pane_acceptLicenseInner control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_acceptLicenseInner;
-
- ///
- /// PropertyPanel3 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel3;
-
- ///
- /// LabelName control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Label LabelName;
-
- ///
- /// PropertyPanel5 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel5;
-
- ///
- /// LabelAuthor control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Label LabelAuthor;
-
- ///
- /// PropertyPanel4 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel4;
-
- ///
- /// LabelMore control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Label LabelMore;
-
- ///
- /// PropertyPanel6 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel6;
-
- ///
- /// LabelLicense control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Label LabelLicense;
-
- ///
- /// PropertyPanel7 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel7;
-
- ///
- /// acceptCheckbox control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.CheckBox acceptCheckbox;
-
- ///
- /// PropertyPanel8 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel PropertyPanel8;
-
- ///
- /// readme control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal readme;
-
- ///
- /// pp_unsecureFiles control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel pp_unsecureFiles;
-
- ///
- /// lt_files control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal lt_files;
-
- ///
- /// pp_macroConflicts control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel pp_macroConflicts;
-
- ///
- /// ltrMacroAlias control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal ltrMacroAlias;
-
- ///
- /// pp_templateConflicts control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel pp_templateConflicts;
-
- protected global::umbraco.uicontrols.PropertyPanel BinaryFileErrorsPanel;
- protected global::umbraco.uicontrols.PropertyPanel LegacyPropertyEditorPanel;
- protected global::System.Web.UI.WebControls.Literal BinaryFileErrorReport;
-
- ///
- /// ltrTemplateAlias control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal ltrTemplateAlias;
-
- ///
- /// pp_stylesheetConflicts control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.PropertyPanel pp_stylesheetConflicts;
-
- ///
- /// ltrStylesheetNames control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal ltrStylesheetNames;
-
- ///
- /// _progbar1 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.ProgressBar _progbar1;
-
- ///
- /// ButtonInstall control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Button ButtonInstall;
-
- ///
- /// pane_installing control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_installing;
-
- ///
- /// progBar2 control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.ProgressBar progBar2;
-
- ///
- /// lit_installStatus control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal lit_installStatus;
-
- ///
- /// pane_optional control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_optional;
-
- ///
- /// pane_success control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::umbraco.uicontrols.Pane pane_success;
-
- ///
- /// bt_viewInstalledPackage control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Button bt_viewInstalledPackage;
-
- ///
- /// lit_authorUrl control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.WebControls.Literal lit_authorUrl;
-
- ///
- /// tempFile control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.HtmlControls.HtmlInputHidden tempFile;
-
- ///
- /// processState control.
- ///
- ///
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- ///
- protected global::System.Web.UI.HtmlControls.HtmlInputHidden processState;
- }
-}
From f334c3d74a5473ae5bdb7aa35b678a9f2d54e173 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Wed, 15 Jan 2014 17:47:46 +1100
Subject: [PATCH 054/100] playing a bit more with re-initializing the app, but
think we're def gonna have to do a full browser refresh. To do that we'll
have to figure out how to gen a deep link url to the installer complete
screen which could include a custom screen from a package.
---
.../src/common/services/assets.service.js | 10 +++++++++-
.../src/common/services/util.service.js | 13 +++++++++----
.../umbraco/developer/Packages/installer.aspx | 2 +-
src/Umbraco.Web/Editors/BackOfficeController.cs | 1 +
4 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
index dbf1d3fc14..715f795b71 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
@@ -74,6 +74,8 @@ angular.module('umbraco.services')
/** Internal method. This is used after installing a package to reload the application assets so we don't have to reload the whole window */
_reloadApplicationAssets: function() {
+ var deferred = $q.defer();
+
umbRequestHelper.resourcePromise(
$http.get(umbRequestHelper.getApiUrl("manifestAssetList", "", "")),
'Failed to get manifest list').then(function(data) {
@@ -82,10 +84,16 @@ angular.module('umbraco.services')
// and this should just load anything that is newly installed.
yepnope({
- load: data
+ load: data,
+ complete: function () {
+ //resolve the promise
+ deferred.resolve(data);
+ }
});
});
+
+ return deferred.promise;
},
/**
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
index 8f47a2270d..0b416a2753 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
@@ -6,10 +6,15 @@ function packageHelper(assetsService, treeService, eventsService) {
/** Called when a package is installed, this resets a bunch of data and ensures the new package assets are loaded in */
packageInstalled: function () {
- assetsService._reloadApplicationAssets();
- treeService.clearCache();
- //send event
- eventsService.emit("app.reInitialize");
+ //assetsService._reloadApplicationAssets().then(function() {
+ // treeService.clearCache();
+ // //send event
+ // //eventsService.emit("app.reInitialize");
+
+ // //TODO: This doesn't work and will end in an infinite browser load loop, we can't really
+ // // re-bootstrap anyways since that would be the same as loading the whole browser window.
+ // //angular.bootstrap(document, ['umbraco']);
+ //});
}
};
diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
index 6a94b46980..6c7cbe7038 100644
--- a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
+++ b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
@@ -265,7 +265,7 @@
http://issues.umbraco.org/issue/U4-4011
--%>
-
+
-
+
-
+ Code
@@ -2193,7 +2193,7 @@
-
+
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EmptyTemplate (ForUseWithCustomViews).cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Empty (ForUseWithCustomViews).cshtml
similarity index 100%
rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EmptyTemplate (ForUseWithCustomViews).cshtml
rename to src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Empty (ForUseWithCustomViews).cshtml
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EmptyTemplate.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Empty.cshtml
similarity index 100%
rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EmptyTemplate.cshtml
rename to src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Empty.cshtml
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate (ForUseWithCustomViews).cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty (ForUseWithCustomViews).cshtml
similarity index 100%
rename from src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate (ForUseWithCustomViews).cshtml
rename to src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty (ForUseWithCustomViews).cshtml
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
similarity index 100%
rename from src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml
rename to src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
diff --git a/src/umbraco.sln b/src/umbraco.sln
index ba7a350194..d1022a5a71 100644
--- a/src/umbraco.sln
+++ b/src/umbraco.sln
@@ -1,5 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4-3B4E-40A3-A309-F3CB4F0E125F}"
ProjectSection(SolutionItems) = preProject
..\build\Build.bat = ..\build\Build.bat
From 99e91a1053d9bc249efd27d980a0ea35f4eecd77 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Wed, 15 Jan 2014 20:55:17 +0100
Subject: [PATCH 056/100] U4-2737 Snippets that are available when creating new
MacroScripts should also be available for Partial Views
---
src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml | 2 +-
src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
index dda3a17f51..2363dcc14c 100644
--- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
@@ -1 +1 @@
-@inherits Umbraco.Web.Macros.PartialViewMacroPage
\ No newline at end of file
+@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
index b779f6854f..222c2b879a 100644
--- a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
+++ b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
@@ -12,7 +12,7 @@ Filename (without .cshtml):
- Choose a template:
+ Choose a snippet:
From 168abddacfd7cfcb243490650b54f32a6bf25129 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Wed, 15 Jan 2014 20:57:27 +0100
Subject: [PATCH 057/100] U4-2737 Snippets that are available when creating new
MacroScripts should also be available for Partial Views
---
src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml | 2 +-
src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx | 2 +-
src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
index dda3a17f51..2363dcc14c 100644
--- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Empty.cshtml
@@ -1 +1 @@
-@inherits Umbraco.Web.Macros.PartialViewMacroPage
\ No newline at end of file
+@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx
index b0cc4e634d..b34560a19e 100644
--- a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx
+++ b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx
@@ -8,7 +8,7 @@
*
-
+ Clean
diff --git a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
index 7a4372d7c9..9dc16377eb 100644
--- a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
+++ b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx
@@ -9,7 +9,7 @@
*
-
+
From ae83b0fbafb1bf94e654f1db8eb672e5b20f8953 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Wed, 15 Jan 2014 21:07:24 +0100
Subject: [PATCH 058/100] Hardcoded empty snippets need to be updated as well..
---
.../Umbraco/create/PartialView.ascx.cs | 12 ++++++------
.../umbraco/create/PartialViewMacro.ascx.cs | 10 +++++-----
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
index 367daad3f4..777adfec01 100644
--- a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
+++ b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
@@ -24,16 +24,16 @@ namespace Umbraco.Web.UI.Umbraco.Create
var path = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViews/Templates/");
list.Items.Clear();
- // always add the options of empty templates
- list.Items.Add(new ListItem("Empty Template", "EmptyTemplate.cshtml"));
- list.Items.Add(new ListItem("Empty Template (For Use With Custom Views)", "EmptyTemplate (ForUseWithCustomViews).cshtml"));
+ // always add the options of empty snippets
+ list.Items.Add(new ListItem("Empty", "Empty.cshtml"));
+ list.Items.Add(new ListItem("Empty (For Use With Custom Views)", "Empty (ForUseWithCustomViews).cshtml"));
if (System.IO.Directory.Exists(path))
{
const string extension = ".cshtml";
- //Already adding Empty Template as the first item, so don't add it again
- foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("EmptyTemplate") == false))
+ //Already adding Empty as the first item, so don't add it again
+ foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("Empty") == false))
{
var filename = System.IO.Path.GetFileName(fileInfo.FullName);
diff --git a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
index 8ed79da349..4e06c08cd4 100644
--- a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
+++ b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
@@ -24,16 +24,16 @@ namespace Umbraco.Web.UI.Umbraco.Create
var path = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViewMacros/Templates/");
list.Items.Clear();
- // always add the options of empty templates
- list.Items.Add(new ListItem("Empty Template", "EmptyTemplate.cshtml"));
- list.Items.Add(new ListItem("Empty Template (For Use With Custom Views)", "EmptyTemplate (ForUseWithCustomViews).cshtml"));
+ // always add the options of empty snippets
+ list.Items.Add(new ListItem("Empty", "Empty.cshtml"));
+ list.Items.Add(new ListItem("Empty (For Use With Custom Views)", "Empty (ForUseWithCustomViews).cshtml"));
if (System.IO.Directory.Exists(path))
{
const string extension = ".cshtml";
- //Already adding Empty Template as the first item, so don't add it again
- foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("EmptyTemplate") == false))
+ //Already adding Empt as the first item, so don't add it again
+ foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("Empty") == false))
{
var filename = System.IO.Path.GetFileName(fileInfo.FullName);
From f56cb2c3ace04601aaa126cdf6f9c72c294d02d6 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Wed, 15 Jan 2014 21:11:35 +0100
Subject: [PATCH 059/100] Hardcoded empty snippets need to be updated as well..
---
src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs | 10 +++++-----
.../umbraco/create/PartialViewMacro.ascx.cs | 10 +++++-----
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
index 5fcd310656..05c9944177 100644
--- a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
+++ b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx.cs
@@ -24,16 +24,16 @@ namespace Umbraco.Web.UI.Umbraco.Create
var path = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViews/Templates/");
list.Items.Clear();
- // always add the options of empty templates
- list.Items.Add(new ListItem("Empty Template", "EmptyTemplate.cshtml"));
- list.Items.Add(new ListItem("Empty Template (For Use With Custom Views)", "EmptyTemplate (ForUseWithCustomViews).cshtml"));
+ // always add the options of empty snippets
+ list.Items.Add(new ListItem("Empty", "Empty.cshtml"));
+ list.Items.Add(new ListItem("Empty (For Use With Custom Views)", "Empty (ForUseWithCustomViews).cshtml"));
if (System.IO.Directory.Exists(path))
{
const string extension = ".cshtml";
- //Already adding Empty Template as the first item, so don't add it again
- foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("EmptyTemplate") == false))
+ //Already adding Empty as the first item, so don't add it again
+ foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("Empty") == false))
{
var filename = System.IO.Path.GetFileName(fileInfo.FullName);
diff --git a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
index 8ed79da349..6e07894b9f 100644
--- a/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
+++ b/src/Umbraco.Web.UI/umbraco/create/PartialViewMacro.ascx.cs
@@ -24,16 +24,16 @@ namespace Umbraco.Web.UI.Umbraco.Create
var path = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViewMacros/Templates/");
list.Items.Clear();
- // always add the options of empty templates
- list.Items.Add(new ListItem("Empty Template", "EmptyTemplate.cshtml"));
- list.Items.Add(new ListItem("Empty Template (For Use With Custom Views)", "EmptyTemplate (ForUseWithCustomViews).cshtml"));
+ // always add the options of empty snippets
+ list.Items.Add(new ListItem("Empty", "Empty.cshtml"));
+ list.Items.Add(new ListItem("Empty (For Use With Custom Views)", "Empty (ForUseWithCustomViews).cshtml"));
if (System.IO.Directory.Exists(path))
{
const string extension = ".cshtml";
- //Already adding Empty Template as the first item, so don't add it again
- foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("EmptyTemplate") == false))
+ //Already adding Empty as the first item, so don't add it again
+ foreach (var fileInfo in new System.IO.DirectoryInfo(path).GetFiles("*" + extension).Where(f => f.Name.StartsWith("Empty") == false))
{
var filename = System.IO.Path.GetFileName(fileInfo.FullName);
From 1e2e26d898b06d0dc9dd83ee67819d96a3b0cc0a Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 12:31:29 +1100
Subject: [PATCH 060/100] publicizes server vars parser and event
---
src/Umbraco.Web/UI/JavaScript/ServerVariablesParser.cs | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web/UI/JavaScript/ServerVariablesParser.cs b/src/Umbraco.Web/UI/JavaScript/ServerVariablesParser.cs
index 6b32c68b2c..bab84de3ad 100644
--- a/src/Umbraco.Web/UI/JavaScript/ServerVariablesParser.cs
+++ b/src/Umbraco.Web/UI/JavaScript/ServerVariablesParser.cs
@@ -4,14 +4,13 @@ using Newtonsoft.Json.Linq;
namespace Umbraco.Web.UI.JavaScript
{
-
- internal class ServerVariablesParser
+ public sealed class ServerVariablesParser
{
///
- /// Could allow developers to add custom variables on startup - not sure if we want to allow that ? maybe.
+ /// Could allow developers to add custom variables on startup
///
- internal static EventHandler> Parsing;
+ public static EventHandler> Parsing;
internal const string Token = "##Variables##";
From 2b1a43b40a618562a8816a28435bfe4e9a3d70cc Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 18:33:31 +1100
Subject: [PATCH 061/100] Finally got somewhere with U4-4011 Package
installation will require either a full app refresh or we will need to
re-lazy load in all of the assets - took ages to get this going, now to get
it working when packages have custom screens.
---
.../src/common/services/assets.service.js | 25 ----------
src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 +
.../umbraco/ClientRedirect.aspx | 23 +++++++++
.../umbraco/developer/Packages/installer.aspx | 37 ++++++++++++--
.../developer/Packages/installer.aspx.cs | 48 +++++++++++++++++--
5 files changed, 100 insertions(+), 34 deletions(-)
create mode 100644 src/Umbraco.Web.UI/umbraco/ClientRedirect.aspx
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
index 715f795b71..e3f86a4b14 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
@@ -71,31 +71,6 @@ angular.module('umbraco.services')
return deferred.promise;
},
- /** Internal method. This is used after installing a package to reload the application assets so we don't have to reload the whole window */
- _reloadApplicationAssets: function() {
-
- var deferred = $q.defer();
-
- umbRequestHelper.resourcePromise(
- $http.get(umbRequestHelper.getApiUrl("manifestAssetList", "", "")),
- 'Failed to get manifest list').then(function(data) {
-
- //ok so we have the list of assets, now we'll use yepnope to go get them. Anything that is already loaded should remain loaded
- // and this should just load anything that is newly installed.
-
- yepnope({
- load: data,
- complete: function () {
- //resolve the promise
- deferred.resolve(data);
- }
- });
-
- });
-
- return deferred.promise;
- },
-
/**
* @ngdoc method
* @name umbraco.services.assetsService#loadCss
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 4bdd618fa2..e68642c61f 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -616,6 +616,7 @@
treeInit.aspx
+
diff --git a/src/Umbraco.Web.UI/umbraco/ClientRedirect.aspx b/src/Umbraco.Web.UI/umbraco/ClientRedirect.aspx
new file mode 100644
index 0000000000..fd9c5182f2
--- /dev/null
+++ b/src/Umbraco.Web.UI/umbraco/ClientRedirect.aspx
@@ -0,0 +1,23 @@
+<%@ Page Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.Page" %>
+<%--
+ This page is required because we cannot reload the angular app with a changed Hash since it just detects the hash and doesn't reload.
+ So this is used purely for a full reload of an angular app with a changed hash.
+--%>
+
+
+
+ Redirecting...
+
+
+
+ Redirecting...
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
index 6c7cbe7038..88750a011d 100644
--- a/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
+++ b/src/Umbraco.Web.UI/umbraco/developer/Packages/installer.aspx
@@ -1,6 +1,7 @@
-<%@ Page Language="c#" MasterPageFile="../../masterpages/umbracoPage.Master" CodeBehind="installer.aspx.cs"
+<%@ Page Language="c#" MasterPageFile="../../masterpages/umbracoPage.Master"
AutoEventWireup="True" Inherits="umbraco.presentation.developer.packages.Installer"
Trace="false" ValidateRequest="false" %>
+<%@ Import Namespace="umbraco" %>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
@@ -261,11 +262,8 @@
- <%--This is a hack to fix this currently until we can replace the installer with a native angular editor
- http://issues.umbraco.org/issue/U4-4011
- --%>
@@ -282,6 +280,35 @@
+
+
+
+
+ Please wait while the browser is reloaded...
+
+
+
+
+
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
index a192176fda..c91cb1c030 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
@@ -36,6 +36,8 @@ namespace umbraco.presentation.developer.packages
private readonly cms.businesslogic.packager.Installer _installer = new cms.businesslogic.packager.Installer();
private string _tempFileName = "";
+ protected string RefreshQueryString { get; set; }
+
protected void Page_Load(object sender, EventArgs e)
{
var ex = new Exception();
@@ -234,7 +236,7 @@ namespace umbraco.presentation.developer.packages
}
else
{
- Response.Redirect("installer.aspx?installing=finished&dir=" + dir + "&pId=" + packageId.ToString() + "&customUrl=" + Server.UrlEncode(_installer.Url));
+ Response.Redirect("installer.aspx?installing=refresh&dir=" + dir + "&pId=" + packageId.ToString() + "&customUrl=" + Server.UrlEncode(_installer.Url));
}
break;
case "customInstaller":
@@ -261,9 +263,12 @@ namespace umbraco.presentation.developer.packages
{
//if the custom installer control is empty here (though it should never be because we've already checked for it previously)
//then we should run the normal FinishedAction
- PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ PerformRefreshAction(packageId, dir, Request.GetItemAsString("customUrl"));
}
break;
+ case "refresh":
+ PerformRefreshAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ break;
case "finished":
PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
break;
@@ -295,6 +300,39 @@ namespace umbraco.presentation.developer.packages
PerformPostInstallCleanup(packageId, dir);
}
+ ///
+ /// Perform the 'Refresh' action of the installer
+ ///
+ ///
+ ///
+ ///
+ private void PerformRefreshAction(int packageId, string dir, string url)
+ {
+ HideAllPanes();
+
+ //create the URL to refresh to
+ // /umbraco/developer/packages/installer.aspx?installing=finished
+ // &dir=X:\Projects\Umbraco\Umbraco_7.0\src\Umbraco.Web.UI\App_Data\aef8c41f-63a0-494b-a1e2-10d761647033
+ // &pId=3
+ // &customUrl=http:%2f%2four.umbraco.org%2fprojects%2fwebsite-utilities%2fmerchello
+
+ RefreshQueryString = Server.UrlEncode(string.Format(
+ "installing=finished&dir={0}&pId={1}&customUrl={2}",
+ dir, packageId, url));
+
+ pane_refresh.Visible = true;
+
+ PerformPostInstallCleanup(packageId, dir);
+ }
+
+ ///
+ /// Runs Post refresh actions such reloading the correct tree nodes, etc...
+ ///
+ private void PerformPostRefreshAction()
+ {
+ BasePage.Current.ClientTools.ReloadActionNode(true, true);
+ }
+
///
/// Runs Post install actions such as clearning any necessary cache, reloading the correct tree nodes, etc...
///
@@ -302,9 +340,8 @@ namespace umbraco.presentation.developer.packages
///
private void PerformPostInstallCleanup(int packageId, string dir)
{
- BasePage.Current.ClientTools.ReloadActionNode(true, true);
_installer.InstallCleanUp(packageId, dir);
- //clear the tree cache
+ //clear the tree cache - we'll do this here even though the browser will reload, but just in case it doesn't can't hurt.
ClientTools.ClearClientTreeCache().RefreshTree("packager");
TreeDefinitionCollection.Instance.ReRegisterTrees();
BizLogicAction.ReRegisterActionsAndHandlers();
@@ -339,6 +376,7 @@ namespace umbraco.presentation.developer.packages
pane_installing.Visible = false;
pane_optional.Visible = false;
pane_success.Visible = false;
+ pane_refresh.Visible = false;
pane_upload.Visible = false;
}
@@ -724,6 +762,8 @@ namespace umbraco.presentation.developer.packages
///
protected global::umbraco.uicontrols.Pane pane_success;
+ protected global::umbraco.uicontrols.Pane pane_refresh;
+
///
/// bt_viewInstalledPackage control.
///
From 4b22ff3a759bcb9c87ac99fcd58e054f356b993b Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 19:11:03 +1100
Subject: [PATCH 062/100] Completes: U4-4011 Package installation will require
either a full app refresh or we will need to re-lazy load in all of the
assets
---
.../developer/Packages/installer.aspx.cs | 37 ++++++++++++-------
1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
index c91cb1c030..a429f3018f 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
+using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.SessionState;
@@ -96,7 +97,7 @@ namespace umbraco.presentation.developer.packages
else
{
fb.Style.Add("margin-top", "7px");
- fb.type = global::umbraco.uicontrols.Feedback.feedbacktype.error;
+ fb.type = uicontrols.Feedback.feedbacktype.error;
fb.Text = "No connection to repository. Runway could not be installed as there was no connection to: '" + _repo.RepositoryUrl + "'";
pane_upload.Visible = false;
}
@@ -109,7 +110,7 @@ namespace umbraco.presentation.developer.packages
acceptCheckbox.Attributes.Add("onmouseup", "document.getElementById('" + ButtonInstall.ClientID + "').disabled = false;");
}
- protected void uploadFile(object sender, System.EventArgs e)
+ protected void uploadFile(object sender, EventArgs e)
{
try
{
@@ -133,7 +134,7 @@ namespace umbraco.presentation.developer.packages
string memberGuid = _repo.Webservice.authenticate(tb_email.Text, library.md5(tb_password.Text));
//if we auth correctly and get a valid key back, we will fetch the file from the repo webservice.
- if (!string.IsNullOrEmpty(memberGuid))
+ if (string.IsNullOrEmpty(memberGuid) == false)
{
tempFile.Value = _installer.Import(_repo.fetch(helper.Request("guid"), memberGuid));
UpdateSettings();
@@ -230,9 +231,9 @@ namespace umbraco.presentation.developer.packages
//making sure that publishing actions performed from the cms layer gets pushed to the presentation
library.RefreshContent();
- if (!string.IsNullOrEmpty(_installer.Control))
+ if (string.IsNullOrEmpty(_installer.Control) == false)
{
- Response.Redirect("installer.aspx?installing=customInstaller&dir=" + dir + "&pId=" + packageId.ToString() + "&customControl=" + Server.UrlEncode(_installer.Control) + "&customUrl=" + Server.UrlEncode(_installer.Url));
+ Response.Redirect("installer.aspx?installing=refresh&dir=" + dir + "&pId=" + packageId.ToString() + "&customControl=" + Server.UrlEncode(_installer.Control) + "&customUrl=" + Server.UrlEncode(_installer.Url));
}
else
{
@@ -242,11 +243,11 @@ namespace umbraco.presentation.developer.packages
case "customInstaller":
var customControl = Request.GetItemAsString("customControl");
- if (!customControl.IsNullOrWhiteSpace())
+ if (customControl.IsNullOrWhiteSpace() == false)
{
HideAllPanes();
- _configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + customControl);
+ _configControl = LoadControl(SystemDirectories.Root + customControl);
_configControl.ID = "packagerConfigControl";
pane_optional.Controls.Add(_configControl);
@@ -263,11 +264,11 @@ namespace umbraco.presentation.developer.packages
{
//if the custom installer control is empty here (though it should never be because we've already checked for it previously)
//then we should run the normal FinishedAction
- PerformRefreshAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
}
break;
case "refresh":
- PerformRefreshAction(packageId, dir, Request.GetItemAsString("customUrl"));
+ PerformRefreshAction(packageId, dir, Request.GetItemAsString("customUrl"), Request.GetItemAsString("customControl"));
break;
case "finished":
PerformFinishedAction(packageId, dir, Request.GetItemAsString("customUrl"));
@@ -287,7 +288,7 @@ namespace umbraco.presentation.developer.packages
{
HideAllPanes();
//string url = _installer.Url;
- string packageViewUrl = "installedPackage.aspx?id=" + packageId.ToString();
+ string packageViewUrl = "installedPackage.aspx?id=" + packageId.ToString(CultureInfo.InvariantCulture);
bt_viewInstalledPackage.OnClientClick = "document.location = '" + packageViewUrl + "'; return false;";
@@ -306,19 +307,29 @@ namespace umbraco.presentation.developer.packages
///
///
///
- private void PerformRefreshAction(int packageId, string dir, string url)
+ ///
+ private void PerformRefreshAction(int packageId, string dir, string url, string customControl)
{
HideAllPanes();
-
+
//create the URL to refresh to
// /umbraco/developer/packages/installer.aspx?installing=finished
// &dir=X:\Projects\Umbraco\Umbraco_7.0\src\Umbraco.Web.UI\App_Data\aef8c41f-63a0-494b-a1e2-10d761647033
// &pId=3
// &customUrl=http:%2f%2four.umbraco.org%2fprojects%2fwebsite-utilities%2fmerchello
- RefreshQueryString = Server.UrlEncode(string.Format(
+ if (customControl.IsNullOrWhiteSpace())
+ {
+ RefreshQueryString = Server.UrlEncode(string.Format(
"installing=finished&dir={0}&pId={1}&customUrl={2}",
dir, packageId, url));
+ }
+ else
+ {
+ RefreshQueryString = Server.UrlEncode(string.Format(
+ "installing=customInstaller&dir={0}&pId={1}&customUrl={2}&customControl={3}",
+ dir, packageId, url, customControl));
+ }
pane_refresh.Visible = true;
From c288734877d77c19450f320010540f0d07c5924e Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 19:47:27 +1100
Subject: [PATCH 063/100] Fixes: U4-4054 Multinode Treepicker datatype -
selecting a start node sends to content section
---
.../views/prevalueeditors/treesource.controller.js | 9 +++++++++
.../src/views/prevalueeditors/treesource.html | 13 -------------
2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js
index 87fa2c8724..5850225e68 100644
--- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js
@@ -5,6 +5,15 @@ angular.module('umbraco')
function($scope, dialogService, entityResource, $log, iconHelper){
+ if (!$scope.model) {
+ $scope.model = {};
+ }
+ if (!$scope.model.value) {
+ $scope.model.value = {
+ type: "content"
+ };
+ }
+
if($scope.model.value.id && $scope.model.value.type !== "member"){
var ent = "Document";
if($scope.model.value.type === "media"){
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.html
index 0e375cc106..c9fdd8674d 100644
--- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.html
+++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.html
@@ -24,20 +24,7 @@
Choose...
-
-
\ No newline at end of file
From 122069752ac65353a75073f0c5aa4b8bd8bf3d0d Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 20:03:29 +1100
Subject: [PATCH 064/100] fixes legacy validate member logic
---
.../members/UmbracoMembershipProvider.cs | 41 ++++++++++---------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/src/umbraco.providers/members/UmbracoMembershipProvider.cs b/src/umbraco.providers/members/UmbracoMembershipProvider.cs
index fed4a5cd5d..c4c130b2c3 100644
--- a/src/umbraco.providers/members/UmbracoMembershipProvider.cs
+++ b/src/umbraco.providers/members/UmbracoMembershipProvider.cs
@@ -692,59 +692,62 @@ namespace umbraco.providers.members
if (isLocked)
{
LogHelper.Info("Cannot validate member " + username + " because they are currently locked out");
- m = null;
+ return false;
}
}
}
}
//check for approve status. If not approved, then set the member property to null
- if (m != null && CheckApproveStatus(m) == false)
+ if (CheckApproveStatus(m) == false)
{
LogHelper.Info("Cannot validate member " + username + " because they are not approved");
- m = null;
+ return false;
}
// maybe update login date
- if (m != null && string.IsNullOrEmpty(LastLoginPropertyTypeAlias) == false)
+ if (string.IsNullOrEmpty(LastLoginPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
// maybe reset password attempts
- if (m != null && string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
+ if (string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, 0);
}
// persist data
- if (m != null)
- m.Save();
+ m.Save();
+
+ return true;
}
- else if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false
+
+
+ // update fail rate if it's approved
+ if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false
&& string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
- {
- var updateMemberDataObject = Member.GetMemberFromLoginName(username);
- // update fail rate if it's approved
- if (updateMemberDataObject != null && CheckApproveStatus(updateMemberDataObject))
+ {
+ if (CheckApproveStatus(m))
{
- int failedAttempts = 0;
- int.TryParse(GetMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, false), out failedAttempts);
+ var failedAttempts = 0;
+ int.TryParse(GetMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, false), out failedAttempts);
failedAttempts = failedAttempts + 1;
- UpdateMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, failedAttempts);
+ UpdateMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, failedAttempts);
// lock user?
if (failedAttempts >= MaxInvalidPasswordAttempts)
{
- UpdateMemberProperty(updateMemberDataObject, LockPropertyTypeAlias, 1);
- UpdateMemberProperty(updateMemberDataObject, LastLockedOutPropertyTypeAlias, DateTime.Now);
+ UpdateMemberProperty(m, LockPropertyTypeAlias, 1);
+ UpdateMemberProperty(m, LastLockedOutPropertyTypeAlias, DateTime.Now);
LogHelper.Info("Member " + username + " is now locked out, max invalid password attempts exceeded");
}
- updateMemberDataObject.Save();
+ m.Save();
}
}
- return (m != null);
+
+ return false;
}
private static void UpdateMemberProperty(Member m, string propertyTypeAlias, object propertyValue)
From c38030def28094889c46266c9d5d56579a18b552 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 20:47:13 +1100
Subject: [PATCH 065/100] Fixes: U4-3855 Preview cookie should be a session
cookie not persisted
---
.../Configuration/UmbracoSettings.cs | 2 +-
src/Umbraco.Core/Constants-Web.cs | 22 ++++++++++++
.../Security/AuthenticationExtensions.cs | 34 +++++++++++--------
src/Umbraco.Core/Umbraco.Core.csproj | 3 ++
.../TestHelpers/FakeHttpContextFactory.cs | 3 +-
src/umbraco.businesslogic/StateHelper.cs | 20 +++++++----
6 files changed, 61 insertions(+), 23 deletions(-)
create mode 100644 src/Umbraco.Core/Constants-Web.cs
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
index 6b53540238..a6f81b593c 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
@@ -309,7 +309,7 @@ namespace Umbraco.Core.Configuration
{
return value;
}
- return "UMB_UCONTEXT";
+ return Constants.Web.AuthCookieName;
}
}
diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
new file mode 100644
index 0000000000..83cb995eeb
--- /dev/null
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -0,0 +1,22 @@
+namespace Umbraco.Core
+{
+ public static partial class Constants
+ {
+ ///
+ /// Defines the identifiers for Umbraco system nodes.
+ ///
+ public static class Web
+ {
+ ///
+ /// The preview cookie name
+ ///
+ public const string PreviewCookieName = "UMB_PREVIEW";
+
+ ///
+ /// The auth cookie name
+ ///
+ public const string AuthCookieName = "UMB_UCONTEXT";
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
index 87d09aecf5..306a385f61 100644
--- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs
+++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
@@ -99,21 +99,27 @@ namespace Umbraco.Core.Security
///
private static void Logout(this HttpContextBase http, string cookieName)
{
- //remove from the request
- http.Request.Cookies.Remove(cookieName);
+ //clear the preview cookie too
+ var cookies = new[] { cookieName, Constants.Web.PreviewCookieName };
+ foreach (var c in cookies)
+ {
+ //remove from the request
+ http.Request.Cookies.Remove(c);
+
+ //expire from the response
+ var formsCookie = http.Response.Cookies[c];
+ if (formsCookie != null)
+ {
+ //this will expire immediately and be removed from the browser
+ formsCookie.Expires = DateTime.Now.AddYears(-1);
+ }
+ else
+ {
+ //ensure there's def an expired cookie
+ http.Response.Cookies.Add(new HttpCookie(c) { Expires = DateTime.Now.AddYears(-1) });
+ }
+ }
- //expire from the response
- var formsCookie = http.Response.Cookies[cookieName];
- if (formsCookie != null)
- {
- //this will expire immediately and be removed from the browser
- formsCookie.Expires = DateTime.Now.AddYears(-1);
- }
- else
- {
- //ensure there's def an expired cookie
- http.Response.Cookies.Add(new HttpCookie(cookieName) { Expires = DateTime.Now.AddYears(-1) });
- }
}
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 90bf089d0f..09ab59e054 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -837,6 +837,9 @@
Constants.cs
+
+ Constants.cs
+
diff --git a/src/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs b/src/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs
index abb477d3c6..c7e7764512 100644
--- a/src/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs
+++ b/src/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs
@@ -7,6 +7,7 @@ using System.Text;
using System.Web;
using System.Web.Routing;
using Moq;
+using Umbraco.Core;
namespace Umbraco.Tests.TestHelpers
{
@@ -59,7 +60,7 @@ namespace Umbraco.Tests.TestHelpers
//Cookie collection
var cookieCollection = new HttpCookieCollection();
- cookieCollection.Add(new HttpCookie("UMB_UCONTEXT", "FBA996E7-D6BE-489B-B199-2B0F3D2DD826"));
+ cookieCollection.Add(new HttpCookie(Constants.Web.AuthCookieName, "FBA996E7-D6BE-489B-B199-2B0F3D2DD826"));
//Request
var requestMock = new Mock();
diff --git a/src/umbraco.businesslogic/StateHelper.cs b/src/umbraco.businesslogic/StateHelper.cs
index 387efd2ca3..d14031d7c1 100644
--- a/src/umbraco.businesslogic/StateHelper.cs
+++ b/src/umbraco.businesslogic/StateHelper.cs
@@ -2,6 +2,7 @@ using System;
using System.Reflection;
using System.Web;
using System.Web.UI;
+using Umbraco.Core;
namespace umbraco.BusinessLogic
{
@@ -347,8 +348,8 @@ namespace umbraco.BusinessLogic
* we currently reproduce this by configuring each cookie with a 30d expires, but does
* that actually make sense? shouldn't some cookie have _no_ expires?
*/
- static readonly Cookie _preview = new Cookie("UMB_PREVIEW", 30d); // was "PreviewSet"
- static readonly Cookie _userContext = new Cookie("UMB_UCONTEXT", 30d); // was "UserContext"
+ static readonly Cookie _preview = new Cookie(Constants.Web.PreviewCookieName, TimeSpan.Zero); // was "PreviewSet"
+ static readonly Cookie _userContext = new Cookie(Constants.Web.AuthCookieName, 30d); // was "UserContext"
static readonly Cookie _member = new Cookie("UMB_MEMBER", 30d); // was "umbracoMember"
public static Cookie Preview { get { return _preview; } }
@@ -429,7 +430,7 @@ namespace umbraco.BusinessLogic
}
public void SetValue(string value)
{
- SetValueWithDate(value, DateTime.Now + _expires);
+ SetValueWithDate(value, _expires == TimeSpan.Zero ? DateTime.MinValue : DateTime.Now + _expires);
}
public void SetValue(string value, double days)
@@ -439,7 +440,7 @@ namespace umbraco.BusinessLogic
public void SetValue(string value, TimeSpan expires)
{
- SetValue(value, DateTime.Now + expires);
+ SetValue(value, expires == TimeSpan.Zero ? DateTime.MinValue : DateTime.Now + expires);
}
public void SetValue(string value, DateTime expires)
@@ -449,7 +450,7 @@ namespace umbraco.BusinessLogic
private void SetValueWithDate(string value, DateTime expires)
{
- HttpCookie cookie = new HttpCookie(_key, value);
+ var cookie = new HttpCookie(_key, value);
if (GlobalSettings.UseSSL)
cookie.Secure = true;
@@ -457,7 +458,12 @@ namespace umbraco.BusinessLogic
//ensure http only, this should only be able to be accessed via the server
cookie.HttpOnly = true;
- cookie.Expires = expires;
+ //set an expiry date if not min value, otherwise leave it as a session cookie.
+ if (expires != DateTime.MinValue)
+ {
+ cookie.Expires = expires;
+ }
+
ResponseCookie = cookie;
// original Umbraco code also does this
@@ -471,7 +477,7 @@ namespace umbraco.BusinessLogic
{
if (RequestCookie != null || ResponseCookie != null)
{
- HttpCookie cookie = new HttpCookie(_key);
+ var cookie = new HttpCookie(_key);
cookie.Expires = DateTime.Now.AddDays(-1);
ResponseCookie = cookie;
}
From ee7ee81098e4aa2c392ce14af131b0898f2b7590 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 20:51:23 +1100
Subject: [PATCH 066/100] fixes merge issue
---
src/Umbraco.Core/Constants-System.cs | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs
index f22c41d922..c4ce5b58f6 100644
--- a/src/Umbraco.Core/Constants-System.cs
+++ b/src/Umbraco.Core/Constants-System.cs
@@ -23,22 +23,5 @@
public const int RecycleBinMedia = -21;
}
-
- ///
- /// Defines the identifiers for Umbraco system nodes.
- ///
- public static class Web
- {
- ///
- /// The preview cookie name
- ///
- public const string PreviewCookieName = "UMB_PREVIEW";
-
- ///
- /// The auth cookie name
- ///
- public const string AuthCookieName = "UMB_UCONTEXT";
-
- }
}
}
\ No newline at end of file
From 8926e8c7d950a7640b6e4c26bd8c4c5a486d6ef0 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Thu, 16 Jan 2014 20:56:34 +1100
Subject: [PATCH 067/100] ensures preview cookie is gone on logout.
---
src/Umbraco.Core/Security/AuthenticationExtensions.cs | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
index 6ba1df8b6c..45c290daba 100644
--- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs
+++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs
@@ -137,12 +137,19 @@ namespace Umbraco.Core.Security
{
if (response == null) throw new ArgumentNullException("response");
//remove the cookie
- var cookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "")
+ var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "")
{
Expires = DateTime.Now.AddYears(-1),
Path = "/"
};
- response.Headers.AddCookies(new[] { cookie });
+ //remove the preview cookie too
+ var prevCookie = new CookieHeaderValue(Constants.Web.PreviewCookieName, "")
+ {
+ Expires = DateTime.Now.AddYears(-1),
+ Path = "/"
+ };
+
+ response.Headers.AddCookies(new[] { authCookie, prevCookie });
}
///
From 326309e61ee022755b428afa0409b8938c9d607b Mon Sep 17 00:00:00 2001
From: Stephan
Date: Thu, 16 Jan 2014 17:03:51 +0100
Subject: [PATCH 068/100] U4-4056 - better unicode/ascii support for urls
---
.../Configuration/UmbracoSettings.cs | 2 +
.../Strings/DefaultShortStringHelper.cs | 13 +-
.../Strings/Utf8ToAsciiConverter.cs | 237 ++++++++++++++++++
.../DefaultShortStringHelperTests.cs | 20 ++
4 files changed, 271 insertions(+), 1 deletion(-)
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
index a6f81b593c..0bdb0cd5c9 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
@@ -855,6 +855,8 @@ namespace Umbraco.Core.Configuration
///
/// Whether to replace double dashes from url (ie my--story----from--dash.aspx caused by multiple url replacement chars
///
+ // was used by the legacy short string helper, is not used anymore by the new default short string helper
+ // should update documentation
internal static bool RemoveDoubleDashesFromUrlReplacing
{
get
diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
index 38e9edc4d8..fbbc25ea20 100644
--- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
+++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
@@ -71,6 +71,17 @@ namespace Umbraco.Core.Strings
}
}
+ private static bool UrlReplacingToAscii
+ {
+ get
+ {
+ var replaceChars = UmbracoSettings.UrlReplaceCharacters;
+ if (replaceChars == null || replaceChars.Attributes == null) return false;
+ var attr = replaceChars.Attributes.GetNamedItem("toAscii");
+ return attr != null && attr.Value == "true";
+ }
+ }
+
///
/// Returns a new string in which characters have been replaced according to the Umbraco settings UrlReplaceCharacters.
///
@@ -147,7 +158,7 @@ namespace Umbraco.Core.Strings
{
PreFilter = ApplyUrlReplaceCharacters,
IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore
- StringType = CleanStringType.Utf8 | CleanStringType.LowerCase,
+ StringType = (UrlReplacingToAscii ? CleanStringType.Ascii : CleanStringType.Utf8) | CleanStringType.LowerCase,
BreakTermsOnUpper = false,
Separator = '-'
}).WithConfig(CleanStringType.FileName, new Config
diff --git a/src/Umbraco.Core/Strings/Utf8ToAsciiConverter.cs b/src/Umbraco.Core/Strings/Utf8ToAsciiConverter.cs
index 23ac4e3931..e08defdedd 100644
--- a/src/Umbraco.Core/Strings/Utf8ToAsciiConverter.cs
+++ b/src/Umbraco.Core/Strings/Utf8ToAsciiConverter.cs
@@ -3316,6 +3316,243 @@ namespace Umbraco.Core.Strings
output[opos++] = '~';
break;
+ // BEGIN CUSTOM TRANSLITERATION OF CYRILIC CHARS
+
+ #region Cyrilic chars
+
+ // russian uppercase "А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я"
+ // russian lowercase "а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я"
+
+ // notes
+ // read http://www.vesic.org/english/blog/c-sharp/transliteration-easy-way-microsoft-transliteration-utility/
+ // should we look into MS Transliteration Utility (http://msdn.microsoft.com/en-US/goglobal/bb688104.aspx)
+ // also UnicodeSharpFork https://bitbucket.org/DimaStefantsov/unidecodesharpfork
+ // also Transliterator http://transliterator.codeplex.com/
+ //
+ // in any case it would be good to generate all those "case" statements instead of writing them by hand
+ // time for a T4 template?
+ // also we should support extensibility so ppl can register more cases in external code
+
+ // fixme
+ // transliterates Анастасия as Anastasiya, and not Anastasia
+ // Ольга --> Ol'ga, Татьяна --> Tat'yana -- that's bad (?)
+ // Note: should ä (german umlaut) become a or ae ?
+
+ case '\u0410': // А
+ output[opos++] = 'A';
+ break;
+ case '\u0430': // а
+ output[opos++] = 'a';
+ break;
+ case '\u0411': // Б
+ output[opos++] = 'B';
+ break;
+ case '\u0431': // б
+ output[opos++] = 'b';
+ break;
+ case '\u0412': // В
+ output[opos++] = 'V';
+ break;
+ case '\u0432': // в
+ output[opos++] = 'v';
+ break;
+ case '\u0413': // Г
+ output[opos++] = 'G';
+ break;
+ case '\u0433': // г
+ output[opos++] = 'g';
+ break;
+ case '\u0414': // Д
+ output[opos++] = 'D';
+ break;
+ case '\u0434': // д
+ output[opos++] = 'd';
+ break;
+ case '\u0415': // Е
+ output[opos++] = 'E';
+ break;
+ case '\u0435': // е
+ output[opos++] = 'e';
+ break;
+ case '\u0401': // Ё
+ output[opos++] = 'E'; // alt. Yo
+ break;
+ case '\u0451': // ё
+ output[opos++] = 'e'; // alt. yo
+ break;
+ case '\u0416': // Ж
+ output[opos++] = 'Z';
+ output[opos++] = 'h';
+ break;
+ case '\u0436': // ж
+ output[opos++] = 'z';
+ output[opos++] = 'h';
+ break;
+ case '\u0417': // З
+ output[opos++] = 'Z';
+ break;
+ case '\u0437': // з
+ output[opos++] = 'z';
+ break;
+ case '\u0418': // И
+ output[opos++] = 'I';
+ break;
+ case '\u0438': // и
+ output[opos++] = 'i';
+ break;
+ case '\u0419': // Й
+ output[opos++] = 'I'; // alt. Y, J
+ break;
+ case '\u0439': // й
+ output[opos++] = 'i'; // alt. y, j
+ break;
+ case '\u041A': // К
+ output[opos++] = 'K';
+ break;
+ case '\u043A': // к
+ output[opos++] = 'k';
+ break;
+ case '\u041B': // Л
+ output[opos++] = 'L';
+ break;
+ case '\u043B': // л
+ output[opos++] = 'l';
+ break;
+ case '\u041C': // М
+ output[opos++] = 'M';
+ break;
+ case '\u043C': // м
+ output[opos++] = 'm';
+ break;
+ case '\u041D': // Н
+ output[opos++] = 'N';
+ break;
+ case '\u043D': // н
+ output[opos++] = 'n';
+ break;
+ case '\u041E': // О
+ output[opos++] = 'O';
+ break;
+ case '\u043E': // о
+ output[opos++] = 'o';
+ break;
+ case '\u041F': // П
+ output[opos++] = 'P';
+ break;
+ case '\u043F': // п
+ output[opos++] = 'p';
+ break;
+ case '\u0420': // Р
+ output[opos++] = 'R';
+ break;
+ case '\u0440': // р
+ output[opos++] = 'r';
+ break;
+ case '\u0421': // С
+ output[opos++] = 'S';
+ break;
+ case '\u0441': // с
+ output[opos++] = 's';
+ break;
+ case '\u0422': // Т
+ output[opos++] = 'T';
+ break;
+ case '\u0442': // т
+ output[opos++] = 't';
+ break;
+ case '\u0423': // У
+ output[opos++] = 'U';
+ break;
+ case '\u0443': // у
+ output[opos++] = 'u';
+ break;
+ case '\u0424': // Ф
+ output[opos++] = 'F';
+ break;
+ case '\u0444': // ф
+ output[opos++] = 'f';
+ break;
+ case '\u0425': // Х
+ output[opos++] = 'K'; // alt. X
+ output[opos++] = 'h';
+ break;
+ case '\u0445': // х
+ output[opos++] = 'k'; // alt. x
+ output[opos++] = 'h';
+ break;
+ case '\u0426': // Ц
+ output[opos++] = 'F';
+ break;
+ case '\u0446': // ц
+ output[opos++] = 'f';
+ break;
+ case '\u0427': // Ч
+ output[opos++] = 'C'; // alt. Ts, C
+ output[opos++] = 'h';
+ break;
+ case '\u0447': // ч
+ output[opos++] = 'c'; // alt. ts, c
+ output[opos++] = 'h';
+ break;
+ case '\u0428': // Ш
+ output[opos++] = 'S'; // alt. Ch, S
+ output[opos++] = 'h';
+ break;
+ case '\u0448': // ш
+ output[opos++] = 's'; // alt. ch, s
+ output[opos++] = 'h';
+ break;
+ case '\u0429': // Щ
+ output[opos++] = 'S'; // alt. Shch, Sc
+ output[opos++] = 'h';
+ break;
+ case '\u0449': // щ
+ output[opos++] = 's'; // alt. shch, sc
+ output[opos++] = 'h';
+ break;
+ case '\u042A': // Ъ
+ output[opos++] = '"'; // "
+ break;
+ case '\u044A': // ъ
+ output[opos++] = '"'; // "
+ break;
+ case '\u042B': // Ы
+ output[opos++] = 'Y';
+ break;
+ case '\u044B': // ы
+ output[opos++] = 'y';
+ break;
+ case '\u042C': // Ь
+ output[opos++] = '\''; // '
+ break;
+ case '\u044C': // ь
+ output[opos++] = '\''; // '
+ break;
+ case '\u042D': // Э
+ output[opos++] = 'E';
+ break;
+ case '\u044D': // э
+ output[opos++] = 'e';
+ break;
+ case '\u042E': // Ю
+ output[opos++] = 'Y'; // alt. Ju
+ output[opos++] = 'u';
+ break;
+ case '\u044E': // ю
+ output[opos++] = 'y'; // alt. ju
+ output[opos++] = 'u';
+ break;
+ case '\u042F': // Я
+ output[opos++] = 'Y'; // alt. Ja
+ output[opos++] = 'a';
+ break;
+ case '\u044F': // я
+ output[opos++] = 'y'; // alt. ja
+ output[opos++] = 'a';
+ break;
+
+ #endregion
+
// BEGIN EXTRA
/*
case '£':
diff --git a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
index 6828e4ea88..83328c5135 100644
--- a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
+++ b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
@@ -94,6 +94,26 @@ namespace Umbraco.Tests.CoreStrings
return s;
}
+ [Test]
+ public void U4_4056()
+ {
+ const string input = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page";
+
+ var helper = new DefaultShortStringHelper().WithDefaultConfig(); // unicode
+ var output = helper.CleanStringForUrlSegment(input);
+ Assert.AreEqual("æøå-and-æøå-and-中文测试-and-אודות-האתר-and-größer-ббдджж-page", output);
+
+ helper = new DefaultShortStringHelper()
+ .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelper.Config
+ {
+ IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_',
+ StringType = CleanStringType.LowerCase | CleanStringType.Ascii, // ascii
+ Separator = '-'
+ });
+ output = helper.CleanStringForUrlSegment(input);
+ Assert.AreEqual("aeoa-and-aeoa-and-and-and-grosser-bbddzhzh-page", output);
+ }
+
[Test]
public void CleanStringUnderscoreInTerm()
{
From c2ee3303a552a579d7acc74fe8bc1cb0e5c1eca3 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Thu, 16 Jan 2014 19:49:57 +0100
Subject: [PATCH 069/100] U4-4059 Update MNTP snippets for string of id's
rather than old xml fragment
---
.../PartialViewMacros/Templates/MultinodeTree-picker.cshtml | 4 ++--
.../PartialViews/Templates/MultinodeTree-picker.cshtml | 4 ++--
.../scripting/templates/cshtml/MultinodeTree-picker.cshtml | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/MultinodeTree-picker.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/MultinodeTree-picker.cshtml
index f9e913d9c4..062e5c7171 100644
--- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/MultinodeTree-picker.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/MultinodeTree-picker.cshtml
@@ -10,10 +10,10 @@
@* Lists each selected value from the picker as a link *@
- @foreach(var id in CurrentPage.PropertyWithPicker){
+ @foreach(var id in CurrentPage.PropertyWithPicker.Split(',')){
@*For each link, get the node, and display its name and url*@
- var content = Umbraco.Content(id.InnerText);
+ var content = Umbraco.Content(id);
}
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/MultinodeTree-picker.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/MultinodeTree-picker.cshtml
index 39efceb361..b3e292230d 100644
--- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/MultinodeTree-picker.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/MultinodeTree-picker.cshtml
@@ -10,10 +10,10 @@
@* Lists each selected value from the picker as a link *@
- @foreach(var id in CurrentPage.PropertyWithPicker){
+ @foreach(var id in CurrentPage.PropertyWithPicker.Split(',')){
@*For each link, get the node, and display its name and url*@
- var content = Umbraco.Content(id.InnerText);
+ var content = Umbraco.Content(id);
}
diff --git a/src/Umbraco.Web.UI/umbraco/scripting/templates/cshtml/MultinodeTree-picker.cshtml b/src/Umbraco.Web.UI/umbraco/scripting/templates/cshtml/MultinodeTree-picker.cshtml
index 7e2d252473..a0a17155e4 100644
--- a/src/Umbraco.Web.UI/umbraco/scripting/templates/cshtml/MultinodeTree-picker.cshtml
+++ b/src/Umbraco.Web.UI/umbraco/scripting/templates/cshtml/MultinodeTree-picker.cshtml
@@ -15,10 +15,10 @@
@* Lists each selected value from the picker as a link *@
- @foreach(var id in selection){
+ @foreach(var id in selection.Split(',')){
@*For each link, get the node, and display its name and url*@
- var node = Library.NodeById(id.InnerText);
+ var node = Library.NodeById(id);
}
From 334a56ce5c740816fa9668461497250f15161489 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Fri, 17 Jan 2014 12:25:34 +1100
Subject: [PATCH 070/100] Fixes: U4-3765 v7 MultiNode Treepicker Sort not
working
---
.../contentpicker/contentpicker.controller.js | 35 ++++++++--------
.../contentpicker/contentpicker.html | 19 +++++----
.../mediapicker/mediapicker.controller.js | 5 ++-
.../memberpicker/memberpicker.controller.js | 41 ++++++++-----------
.../memberpicker/memberpicker.html | 2 +-
5 files changed, 48 insertions(+), 54 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
index ab1aeb06e2..70a98843b6 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
@@ -54,39 +54,36 @@ angular.module('umbraco')
$scope.remove =function(index){
$scope.renderModel.splice(index, 1);
- $scope.ids.splice(index, 1);
- $scope.model.value = trim($scope.ids.join(), ",");
};
$scope.add =function(item){
if($scope.ids.indexOf(item.id) < 0){
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
-
- $scope.ids.push(item.id);
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
- $scope.model.value = trim($scope.ids.join(), ",");
}
};
$scope.clear = function() {
- $scope.model.value = "";
$scope.renderModel = [];
- $scope.ids = [];
- };
-
- $scope.sortableOptions = {
- update: function(e, ui) {
- var r = [];
- angular.forEach($scope.renderModel, function(value, key){
- r.push(value.id);
- });
-
- $scope.ids = r;
- $scope.model.value = trim($scope.ids.join(), ",");
- }
};
+ //We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
+ // because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
+ // occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
+ // In their source code there is no event so we need to just subscribe to our model changes here.
+ //This also makes it easier to manage models, we update one and the rest will just work.
+ $scope.$watch(function() {
+ //return the joined Ids as a string to watch
+ return _.map($scope.renderModel, function(i) {
+ return i.id;
+ }).join();
+ }, function (newVal) {
+ $scope.ids = _.map($scope.renderModel, function (i) {
+ return i.id;
+ });
+ $scope.model.value = trim($scope.ids.join(), ",");
+ });
$scope.$on("formSubmitting", function (ev, args) {
$scope.model.value = trim($scope.ids.join(), ",");
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
index e22d4cf22b..ecdd82e15a 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
@@ -1,7 +1,7 @@
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
index 23a0a4aefc..39edcc9590 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
@@ -57,7 +57,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.sortableOptions = {
update: function(e, ui) {
- var r = [];
+ var r = [];
+ //TODO: Instead of doing this with a half second delay would be better to use a watch like we do in the
+ // content picker. THen we don't have to worry about setting ids, render models, models, we just set one and let the
+ // watch do all the rest.
$timeout(function(){
angular.forEach($scope.images, function(value, key){
r.push(value.id);
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js
index afbb248e5d..21afc87c2b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js
@@ -33,52 +33,45 @@ angular.module('umbraco')
$scope.remove =function(index){
$scope.renderModel.splice(index, 1);
- $scope.ids.splice(index, 1);
- $scope.model.value = trim($scope.ids.join(), ",");
};
$scope.add =function(item){
if($scope.ids.indexOf(item.id) < 0){
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
-
- $scope.ids.push(item.id);
- $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
- $scope.model.value = trim($scope.ids.join(), ",");
+ $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
}
};
$scope.clear = function() {
- $scope.model.value = "";
$scope.renderModel = [];
- $scope.ids = [];
};
-
- $scope.sortableOptions = {
- update: function(e, ui) {
- var r = [];
- angular.forEach($scope.renderModel, function(value, key){
- r.push(value.id);
- });
-
- $scope.ids = r;
- $scope.model.value = trim($scope.ids.join(), ",");
- }
- };
-
+ //We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
+ // because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
+ // occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
+ // In their source code there is no event so we need to just subscribe to our model changes here.
+ //This also makes it easier to manage models, we update one and the rest will just work.
+ $scope.$watch(function () {
+ //return the joined Ids as a string to watch
+ return _.map($scope.renderModel, function (i) {
+ return i.id;
+ }).join();
+ }, function (newVal) {
+ $scope.ids = _.map($scope.renderModel, function (i) {
+ return i.id;
+ });
+ $scope.model.value = trim($scope.ids.join(), ",");
+ });
$scope.$on("formSubmitting", function (ev, args) {
$scope.model.value = trim($scope.ids.join(), ",");
});
-
-
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
return str.replace(rgxtrim, '');
}
-
function populate(data){
if(angular.isArray(data)){
_.each(data, function (item, i) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.html
index 473c5694e8..168b6cdd6d 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.html
@@ -2,7 +2,7 @@
From ae05bfd350b632e503ace3bcb5162ddd2c87af3a Mon Sep 17 00:00:00 2001
From: Shannon
Date: Fri, 17 Jan 2014 13:00:11 +1100
Subject: [PATCH 071/100] Fixes: U4-4055 List View document types still display
children in content tree
---
src/Umbraco.Core/DictionaryExtensions.cs | 12 +++----
.../Models/UmbracoEntityExtensions.cs | 32 +++++++++++++++++++
src/Umbraco.Core/Umbraco.Core.csproj | 1 +
.../Models/Mapping/MemberModelMapper.cs | 4 +--
.../Trees/ContentTreeController.cs | 4 +--
.../Trees/ContentTreeControllerBase.cs | 14 ++++----
src/Umbraco.Web/Trees/MediaTreeController.cs | 4 +--
7 files changed, 50 insertions(+), 21 deletions(-)
create mode 100644 src/Umbraco.Core/Models/UmbracoEntityExtensions.cs
diff --git a/src/Umbraco.Core/DictionaryExtensions.cs b/src/Umbraco.Core/DictionaryExtensions.cs
index 194b461fd5..fd6476fe21 100644
--- a/src/Umbraco.Core/DictionaryExtensions.cs
+++ b/src/Umbraco.Core/DictionaryExtensions.cs
@@ -231,7 +231,7 @@ namespace Umbraco.Core
/// The contains key ignore case.
public static bool ContainsKeyIgnoreCase(this IDictionary dictionary, string key)
{
- return dictionary.Keys.Any(i => i.Equals(key, StringComparison.CurrentCultureIgnoreCase));
+ return dictionary.Keys.InvariantContains(key);
}
///
@@ -257,9 +257,9 @@ namespace Umbraco.Core
/// The key.
/// The type
/// The entry
- public static TValue GetEntryIgnoreCase(this IDictionary dictionary, string key)
+ public static TValue GetValueIgnoreCase(this IDictionary dictionary, string key)
{
- return dictionary.GetEntryIgnoreCase(key, default(TValue));
+ return dictionary.GetValueIgnoreCase(key, default(TValue));
}
/// The get entry ignore case.
@@ -268,11 +268,11 @@ namespace Umbraco.Core
/// The default value.
/// The type
/// The entry
- public static TValue GetEntryIgnoreCase(this IDictionary dictionary, string key, TValue defaultValue)
+ public static TValue GetValueIgnoreCase(this IDictionary dictionary, string key, TValue defaultValue)
{
- key = dictionary.Keys.Where(i => i.Equals(key, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
+ key = dictionary.Keys.FirstOrDefault(i => i.InvariantEquals(key));
- return !key.IsNullOrWhiteSpace()
+ return key.IsNullOrWhiteSpace() == false
? dictionary[key]
: defaultValue;
}
diff --git a/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs
new file mode 100644
index 0000000000..edcc25ade8
--- /dev/null
+++ b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web.UI.WebControls;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Models
+{
+ internal static class UmbracoEntityExtensions
+ {
+
+ public static object GetAdditionalDataValueIgnoreCase(this IUmbracoEntity entity, string key, object defaultVal)
+ {
+ if (entity.AdditionalData.ContainsKeyIgnoreCase(key) == false) return defaultVal;
+ return entity.AdditionalData.GetValueIgnoreCase(key, defaultVal);
+ }
+
+ public static bool IsContainer(this IUmbracoEntity entity)
+ {
+ if (entity.AdditionalData.ContainsKeyIgnoreCase("IsContainer") == false) return false;
+ var val = entity.AdditionalData.GetValueIgnoreCase("IsContainer", null);
+ if (val is bool && (bool) val)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 471eb1e28a..bf6fcda1e3 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -339,6 +339,7 @@
+
diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
index 220063c6a0..1d3b5ba33c 100644
--- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
@@ -119,8 +119,8 @@ namespace Umbraco.Web.Models.Mapping
// only when creating a new member and we want to have a generated password pre-filled.
Value = new Dictionary
{
- {"generatedPassword", member.AdditionalData.ContainsKey("GeneratedPassword") ? member.AdditionalData["GeneratedPassword"] : null},
- {"newPassword", member.AdditionalData.ContainsKey("NewPassword") ? member.AdditionalData["NewPassword"] : null},
+ {"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null) },
+ {"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null) },
},
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
View = "changepassword",
diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs
index 5fe20fa45b..246cae6ac4 100644
--- a/src/Umbraco.Web/Trees/ContentTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeController.cs
@@ -98,9 +98,7 @@ namespace Umbraco.Web.Trees
{
//Special check to see if it ia a container, if so then we'll hide children.
- var isContainer = e.AdditionalData.ContainsKey("IsContainer")
- && e.AdditionalData["IsContainer"] is bool
- && (bool)e.AdditionalData["IsContainer"];
+ var isContainer = e.IsContainer();
var node = CreateTreeNode(
e.Id.ToInvariantString(),
diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
index d5edd335fd..83bf72d974 100644
--- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
@@ -69,7 +69,7 @@ namespace Umbraco.Web.Trees
protected abstract int UserStartNode { get; }
protected abstract TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings);
-
+
protected abstract MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings);
protected abstract UmbracoObjectTypes UmbracoObjectType { get; }
@@ -88,7 +88,7 @@ namespace Umbraco.Web.Trees
{
//just return their single start node, it will show up under the 'Content' label
var startNode = Services.EntityService.Get(UserStartNode, UmbracoObjectType);
- return new[] {startNode};
+ return new[] { startNode };
}
return Services.EntityService.GetChildren(iid, UmbracoObjectType).ToArray();
@@ -116,8 +116,8 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
var altStartId = string.Empty;
-
- if(queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
+
+ if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
altStartId = queryStrings.GetValue(TreeQueryStringParameters.StartNodeId);
@@ -154,7 +154,7 @@ namespace Umbraco.Web.Trees
// for the time being we'll just load the dashboard of the section.
//queryStrings.GetValue("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));
queryStrings.GetValue("application")));
-
+
}
return nodes;
@@ -176,12 +176,12 @@ namespace Umbraco.Web.Trees
{
//before we get the children we need to see if this is a container node
var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectType);
- if (current != null && current.AdditionalData.ContainsKey("IsContainer") && current.AdditionalData["IsContainer"] is bool && (bool)current.AdditionalData["IsContainer"])
+
+ if (current != null && current.IsContainer())
{
//no children!
return new TreeNodeCollection();
}
-
return PerformGetTreeNodes(id, queryStrings);
}
diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs
index 0f6849c2ad..ea9a5f230e 100644
--- a/src/Umbraco.Web/Trees/MediaTreeController.cs
+++ b/src/Umbraco.Web/Trees/MediaTreeController.cs
@@ -78,9 +78,7 @@ namespace Umbraco.Web.Trees
var entity = (UmbracoEntity)e;
//Special check to see if it ia a container, if so then we'll hide children.
- var isContainer = entity.AdditionalData.ContainsKey("IsContainer")
- && entity.AdditionalData["IsContainer"] is bool
- && (bool)entity.AdditionalData["IsContainer"];
+ var isContainer = entity.IsContainer();
var node = CreateTreeNode(
e.Id.ToInvariantString(),
From 1621d01992686bb232feb9bf8763c797f705e136 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Fri, 17 Jan 2014 13:18:49 +1100
Subject: [PATCH 072/100] fixes some unit tests
---
.../test/unit/app/media/edit-media-controller.spec.js | 2 +-
.../propertyeditors/content-picker-controller.spec.js | 10 ++++++----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/test/unit/app/media/edit-media-controller.spec.js b/src/Umbraco.Web.UI.Client/test/unit/app/media/edit-media-controller.spec.js
index 3b453a7930..64a21b670e 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/app/media/edit-media-controller.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/app/media/edit-media-controller.spec.js
@@ -47,7 +47,7 @@ describe('edit media controller tests', function () {
});
it('it should have a tabs collection', function () {
- expect(scope.content.tabs.length).toBe(5);
+ expect(scope.content.tabs.length).toBe(1);
});
it('it should have a properties collection on each tab', function () {
diff --git a/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/content-picker-controller.spec.js b/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/content-picker-controller.spec.js
index 2ffd204d24..b42a861e8a 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/content-picker-controller.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/content-picker-controller.spec.js
@@ -60,7 +60,7 @@ describe('Content picker controller tests', function () {
it("Removing an item should update renderModel, ids and model.value", function(){
scope.remove(1);
-
+ scope.$apply();
expect(scope.renderModel.length).toBe(2);
expect(scope.ids.length).toBe(2);
expect(scope.model.value).toBe("1233,23121");
@@ -69,7 +69,7 @@ describe('Content picker controller tests', function () {
it("Adding an item should update renderModel, ids and model.value", function(){
scope.add({name: "meh", id: 666, icon: "woop"});
-
+ scope.$apply();
expect(scope.renderModel.length).toBe(4);
expect(scope.ids.length).toBe(4);
expect(scope.model.value).toBe("1233,1231,23121,666");
@@ -77,12 +77,14 @@ describe('Content picker controller tests', function () {
it("Adding a dublicate item should note update renderModel, ids and model.value", function(){
- scope.add({name: "meh", id: 666, icon: "woop"});
+ scope.add({ name: "meh", id: 666, icon: "woop" });
+ scope.$apply();
expect(scope.renderModel.length).toBe(4);
expect(scope.ids.length).toBe(4);
expect(scope.model.value).toBe("1233,1231,23121,666");
- scope.add({name: "meh 2", id: 666, icon: "woop 2"});
+ scope.add({ name: "meh 2", id: 666, icon: "woop 2" });
+ scope.$apply();
expect(scope.renderModel.length).toBe(4);
expect(scope.ids.length).toBe(4);
expect(scope.model.value).toBe("1233,1231,23121,666");
From 12314f16a23d0b9726cb5f2594bac553544e98a0 Mon Sep 17 00:00:00 2001
From: Stephan
Date: Fri, 17 Jan 2014 10:26:35 +0100
Subject: [PATCH 073/100] U4-4056 - fixing
---
src/Umbraco.Core/StringExtensions.cs | 2 +-
src/Umbraco.Core/Strings/CleanStringType.cs | 41 ++++++++---------
.../Strings/DefaultShortStringHelper.cs | 44 +++++++++++++------
.../DefaultShortStringHelperTests.cs | 38 ++++++++++++++++
4 files changed, 91 insertions(+), 34 deletions(-)
diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs
index 4847df3fc4..0b0c76f620 100644
--- a/src/Umbraco.Core/StringExtensions.cs
+++ b/src/Umbraco.Core/StringExtensions.cs
@@ -1084,7 +1084,7 @@ namespace Umbraco.Core
var cases2 = cases.ToCleanStringType() & CleanStringType.CaseMask;
return legacy != null
? legacy.LegacyConvertStringCase(phrase, cases2)
- : helper.CleanString(phrase, CleanStringType.Ascii | CleanStringType.Alias | cases2);
+ : helper.CleanString(phrase, CleanStringType.Ascii | CleanStringType.ConvertCase | cases2);
}
// the new methods to clean a string (to alias, url segment...)
diff --git a/src/Umbraco.Core/Strings/CleanStringType.cs b/src/Umbraco.Core/Strings/CleanStringType.cs
index f681c42d4a..4c53be4cb8 100644
--- a/src/Umbraco.Core/Strings/CleanStringType.cs
+++ b/src/Umbraco.Core/Strings/CleanStringType.cs
@@ -14,25 +14,6 @@ namespace Umbraco.Core.Strings
// note: you have 32 bits at your disposal
// 0xffffffff
-
- // masks
-
- ///
- /// Flag mask for casing.
- ///
- CaseMask = 0x3f, // 0xff - 8 possible values
-
- ///
- /// Flag mask for encoding.
- ///
- CodeMask = 0x700, // 0xff00 - 8 possible values
-
- ///
- /// Flag mask for role.
- ///
- RoleMask = 0x070000, // 0xff0000 - 8 possible values
-
-
// no value
///
@@ -43,6 +24,11 @@ namespace Umbraco.Core.Strings
// casing values
+ ///
+ /// Flag mask for casing.
+ ///
+ CaseMask = PascalCase | CamelCase | Unchanged | LowerCase | UpperCase | UmbracoCase,
+
///
/// Pascal casing eg "PascalCase".
///
@@ -78,6 +64,11 @@ namespace Umbraco.Core.Strings
// encoding values
+ ///
+ /// Flag mask for encoding.
+ ///
+ CodeMask = Unicode | Utf8 | Ascii,
+
///
/// Unicode encoding.
///
@@ -97,6 +88,11 @@ namespace Umbraco.Core.Strings
// role values
+ ///
+ /// Flag mask for role.
+ ///
+ RoleMask = UrlSegment | Alias | FileName | ConvertCase,
+
///
/// Url role.
///
@@ -110,6 +106,11 @@ namespace Umbraco.Core.Strings
///
/// FileName role.
///
- FileName = 0x040000
+ FileName = 0x040000,
+
+ ///
+ /// ConvertCase role.
+ ///
+ ConvertCase = 0x080000
}
}
diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
index 25abba7232..92d82c9a6b 100644
--- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
+++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
@@ -1,4 +1,8 @@
-using System;
+
+// debugging - define to write cleaning details & steps to console
+#define WRTCONS
+
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -160,6 +164,12 @@ namespace Umbraco.Core.Strings
: (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore
StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase,
BreakTermsOnUpper = false
+ }).WithConfig(CleanStringType.ConvertCase, new Config
+ {
+ PreFilter = null,
+ IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore
+ StringType = CleanStringType.Ascii,
+ BreakTermsOnUpper = true
});
}
@@ -487,6 +497,10 @@ function validateSafeAlias(id, value, immediate, callback) {{
if (culture == null)
throw new ArgumentNullException("culture");
+#if WRTCONS
+ Console.WriteLine("STRING TYPE {0}", stringType);
+#endif
+
// get config
var config = GetConfig(stringType, culture);
stringType = config.StringTypeExtend(stringType);
@@ -554,6 +568,9 @@ function validateSafeAlias(id, value, immediate, callback) {{
var state = StateBreak;
caseType &= CleanStringType.CaseMask;
+#if WRTCONS
+ Console.WriteLine("CASE {0}", caseType);
+#endif
// if we apply global ToUpper or ToLower to text here
// then we cannot break words on uppercase chars
@@ -579,13 +596,13 @@ function validateSafeAlias(id, value, immediate, callback) {{
var isPair = char.IsSurrogate(c);
if (isPair)
throw new NotSupportedException("Surrogate pairs are not supported.");
-
- //Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}",
- // c,
- // isTerm ? "term" : "!term", isUpper ? "upper" : "!upper",
- // state,
- // i, ipos, leading ? "leading" : "!leading");
-
+#if WRTCONS
+ Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}",
+ c,
+ isTerm ? "term" : "!term", isUpper ? "upper" : "!upper",
+ state,
+ i, ipos, leading ? "leading" : "!leading");
+#endif
switch (state)
{
// within a break
@@ -692,11 +709,12 @@ function validateSafeAlias(id, value, immediate, callback) {{
CleanStringType caseType, CultureInfo culture, bool isAcronym)
{
var term = input.Substring(ipos, len);
- //Console.WriteLine("TERM \"{0}\" {1} {2}",
- // term,
- // isAcronym ? "acronym" : "word",
- // caseType);
-
+#if WRTCONS
+ Console.WriteLine("TERM \"{0}\" {1} {2}",
+ term,
+ isAcronym ? "acronym" : "word",
+ caseType);
+#endif
if (isAcronym)
{
if ((caseType == CleanStringType.CamelCase && len <= 2 && opos > 0) ||
diff --git a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
index f8b5808681..64a432e815 100644
--- a/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
+++ b/src/Umbraco.Tests/CoreStrings/DefaultShortStringHelperTests.cs
@@ -6,8 +6,12 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
+using Moq;
using NUnit.Framework;
+using umbraco;
using Umbraco.Core;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Strings;
using Umbraco.Core.ObjectResolution;
using Umbraco.Tests.TestHelpers;
@@ -65,6 +69,13 @@ namespace Umbraco.Tests.CoreStrings
PreFilter = WhiteQuotes,
IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c),
StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii
+ })
+ .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelper.Config
+ {
+ PreFilter = null,
+ IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore
+ StringType = CleanStringType.Ascii,
+ BreakTermsOnUpper = true
});
ShortStringHelperResolver.Reset();
@@ -98,9 +109,30 @@ namespace Umbraco.Tests.CoreStrings
return s;
}
+ [Test]
+ public void U4_4055_4056()
+ {
+ var settings = SettingsForTests.GenerateMockSettings();
+ var contentMock = Mock.Get(settings.RequestHandler);
+ contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty());
+ contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false);
+ SettingsForTests.ConfigureSettings(settings);
+
+ const string input = "publishedVersion";
+
+ Assert.AreEqual("PublishedVersion", input.ConvertCase(StringAliasCaseType.PascalCase)); // obsolete, use the one below
+ Assert.AreEqual("PublishedVersion", input.ToCleanString(CleanStringType.ConvertCase | CleanStringType.PascalCase | CleanStringType.Ascii)); // role, case and code
+ }
+
[Test]
public void U4_4056()
{
+ var settings = SettingsForTests.GenerateMockSettings();
+ var contentMock = Mock.Get(settings.RequestHandler);
+ contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty());
+ contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false);
+ SettingsForTests.ConfigureSettings(settings);
+
const string input = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page";
var helper = new DefaultShortStringHelper().WithDefaultConfig(); // unicode
@@ -381,6 +413,12 @@ namespace Umbraco.Tests.CoreStrings
[Test]
public void CleanStringDefaultConfig()
{
+ var settings = SettingsForTests.GenerateMockSettings();
+ var contentMock = Mock.Get(settings.RequestHandler);
+ contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty());
+ contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false);
+ SettingsForTests.ConfigureSettings(settings);
+
var helper = new DefaultShortStringHelper().WithDefaultConfig();
const string input = "0123 中文测试 中文测试 léger ZÔRG (2) a?? *x";
From 9164567abe1e22adea05d9eecac06ab8a3b68020 Mon Sep 17 00:00:00 2001
From: Morten Christensen
Date: Fri, 17 Jan 2014 13:55:34 +0100
Subject: [PATCH 074/100] Adding export of templates to PackagingService
---
.../Services/IPackagingService.cs | 16 +++++
src/Umbraco.Core/Services/PackagingService.cs | 63 +++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs
index 2f711eb8af..65a4334e9b 100644
--- a/src/Umbraco.Core/Services/IPackagingService.cs
+++ b/src/Umbraco.Core/Services/IPackagingService.cs
@@ -144,5 +144,21 @@ namespace Umbraco.Core.Services
/// Optional parameter indicating whether or not to raise events
/// containing the xml representation of the IDataTypeDefinition object
XElement Export(IDataTypeDefinition dataTypeDefinition, bool raiseEvents = true);
+
+ ///
+ /// Exports a list of items to xml as an
+ ///
+ /// List of Templates to export
+ /// Optional parameter indicating whether or not to raise events
+ /// containing the xml representation of the ITemplate objects
+ XElement Export(IEnumerable templates, bool raiseEvents = true);
+
+ ///
+ /// Exports a single item to xml as an
+ ///
+ /// Template to export
+ /// Optional parameter indicating whether or not to raise events
+ /// containing the xml representation of the ITemplate object
+ XElement Export(ITemplate template, bool raiseEvents = true);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs
index bb658c23f8..920c4eba1e 100644
--- a/src/Umbraco.Core/Services/PackagingService.cs
+++ b/src/Umbraco.Core/Services/PackagingService.cs
@@ -1151,6 +1151,7 @@ namespace Umbraco.Core.Services
#endregion
#region Macros
+
#endregion
#region Members
@@ -1416,6 +1417,58 @@ namespace Umbraco.Core.Services
return IOHelper.MapPath(SystemDirectories.Masterpages + "/" + alias.Replace(" ", "") + ".master");
}
+ ///
+ /// Exports a list of items to xml as an
+ ///
+ /// List of Templates to export
+ /// Optional parameter indicating whether or not to raise events
+ /// containing the xml representation of the ITemplate objects
+ public XElement Export(IEnumerable templates, bool raiseEvents = true)
+ {
+ var xml = new XElement("Templates");
+ foreach (var item in templates)
+ {
+ xml.Add(Export(item, raiseEvents));
+ }
+ return xml;
+ }
+
+ ///
+ /// Exports a single item to xml as an
+ ///
+ /// Template to export
+ /// Optional parameter indicating whether or not to raise events
+ /// containing the xml representation of the ITemplate object
+ public XElement Export(ITemplate template, bool raiseEvents = true)
+ {
+ if (raiseEvents)
+ {
+ if (ExportingTemplate.IsRaisedEventCancelled(new SaveEventArgs(template), this))
+ return default(XElement);
+ }
+
+ var xml = new XElement("Template");
+ xml.Add(new XElement("Name", template.Name));
+ xml.Add(new XElement("Alias", template.Alias));
+ xml.Add(new XElement("Design", new XCData(template.Content)));
+
+ var concreteTemplate = template as Template;
+ if (concreteTemplate != null)
+ {
+ if (concreteTemplate.MasterTemplateId.IsValueCreated &&
+ concreteTemplate.MasterTemplateId.Value != default(int))
+ {
+ xml.Add(new XElement("Master", concreteTemplate.MasterTemplateId.ToString()));
+ xml.Add(new XElement("MasterAlias", concreteTemplate.MasterTemplateAlias));
+ }
+ }
+
+ if (raiseEvents)
+ ExportedTemplate.RaiseEvent(new SaveEventArgs(xml, false), this);
+
+ return xml;
+ }
+
#endregion
#region Stylesheets
@@ -1541,6 +1594,16 @@ namespace Umbraco.Core.Services
/// Occurs after Template is Imported and Saved
///
public static event TypedEventHandler> ImportedTemplate;
+
+ ///
+ /// Occurs before Exporting Template
+ ///
+ public static event TypedEventHandler> ExportingTemplate;
+
+ ///
+ /// Occurs after Template is Exported to Xml
+ ///
+ public static event TypedEventHandler> ExportedTemplate;
#endregion
}
}
\ No newline at end of file
From 65b522a0a0aabce89139148332fcbcdc25d461f3 Mon Sep 17 00:00:00 2001
From: Sebastiaan Janssen
Date: Fri, 17 Jan 2014 14:04:32 +0100
Subject: [PATCH 075/100] Automatically build Belle from build.bat without
having to install Node.js on local machine
---
build/Build.bat | 37 +++++++++++++++++++++++++++++++++++++
src/.nuget/NuGet.exe | Bin 777728 -> 1611264 bytes
src/.nuget/NuGet.targets | 39 ++++++++++++---------------------------
src/umbraco.sln | 14 +++++++-------
4 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/build/Build.bat b/build/Build.bat
index ead7df0abc..867186ee3a 100644
--- a/build/Build.bat
+++ b/build/Build.bat
@@ -4,11 +4,46 @@ SET comment=
SET version=%release%
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
+ECHO Building Umbraco %version%
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
+SET nuGetFolder=%CD%\..\src\packages\
+
+ECHO Installing Npm NuGet Package
+..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder%
+
+for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
+for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
+
+ECHO Temporarily adding Npm and Node to path
+SET oldPath=%PATH%
+
+path=%npmPath%;%nodePath%;%PATH%
+
+SET buildFolder="%CD%"
+
+ECHO Go to Umbraco.Web.UI.Client folder
+CD ..\src\Umbraco.Web.UI.Client\
+
+ECHO Do npm install and the grunt build of Belle
+call npm install
+call npm install -g grunt-cli
+call grunt
+
+ECHO Reset path to what it was before
+path=%oldPath%
+
+ECHO Move back to the build folder
+CD %buildFolder%
+
+ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
+..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder%
+
+ECHO Performing MSBuild and producing Umbraco binaries zip files
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
+ECHO Adding dummy files to include in the NuGet package so that empty folders actually get created
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Code\dummy.txt
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Data\dummy.txt
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Plugins\dummy.txt
@@ -20,9 +55,11 @@ echo This file is only here so that the containing folder will be included in th
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
+ECHO Adding Web.config transform files to the NuGet package
ren .\_BuildOutput\WebApp\MacroScripts\Web.config Web.config.transform
ren .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
+ECHO Packing the NuGet release files
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
diff --git a/src/.nuget/NuGet.exe b/src/.nuget/NuGet.exe
index c296edf177fc5c0373b2c705a006b8c686098e37..8f613402956f9802681f150b1cb51f8400eb628e 100644
GIT binary patch
literal 1611264
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