DO NOT DOWNLOAD. DOWNLOAT LATEST STABLE FROM RELEASE TAB

Created 4.1.0 branch

[TFS Changeset #55082]
This commit is contained in:
Shandem
2009-06-19 07:39:16 +00:00
commit f6d0d043b5
2917 changed files with 267089 additions and 0 deletions

View File

@@ -0,0 +1,498 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Text.RegularExpressions;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.macro;
using umbraco.cms.businesslogic.media;
using umbraco.cms.businesslogic.property;
using Content = umbraco.cms.businesslogic.Content;
namespace umbraco.editorControls.tinyMCE3.webcontrol
{
public class TinyMCEWebControl : System.Web.UI.WebControls.TextBox
{
public NameValueCollection config = new NameValueCollection();
private string temp;
private int _nodeId = 0;
private Guid _versionId;
public bool IsInLiveEditingMode { get; set; }
public int NodeId
{
set { _nodeId = value; }
get { return _nodeId; }
}
public Guid VersionId
{
set { _versionId = value; }
get { return _versionId; }
}
public string InstallPath
{
get
{
if (installPath == null)
installPath = this.config["InstallPath"];
return installPath;
}
set { installPath = value; }
}
#region private
private static readonly object TextChangedEvent = new object();
private int rows = 10;
private int cols = 70;
private bool gzipEnabled, merged;
private string installPath, mode;
private System.Text.StringBuilder m_scriptInitBlock = new StringBuilder();
#endregion
public TinyMCEWebControl()
: base()
{
base.TextMode = TextBoxMode.MultiLine;
base.Attributes.Add("style", "visibility: hidden");
config.Add("mode", "exact");
config.Add("theme", "umbraco");
config.Add("umbraco_path", GlobalSettings.Path);
CssClass = "tinymceContainer";
plugin.ConfigSection configSection = (plugin.ConfigSection)System.Web.HttpContext.Current.GetSection("TinyMCE");
if (configSection != null)
{
this.installPath = configSection.InstallPath;
this.mode = configSection.Mode;
this.gzipEnabled = configSection.GzipEnabled;
// Copy items into local config collection
foreach (string key in configSection.GlobalSettings.Keys)
this.config[key] = configSection.GlobalSettings[key];
}
else
{
configSection = new plugin.ConfigSection();
configSection.GzipExpiresOffset = TimeSpan.FromDays(10).Ticks;
this.gzipEnabled = false;
this.InstallPath = umbraco.editorControls.tinymce.tinyMCEConfiguration.JavascriptPath;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
// update macro's and images in text
if (_nodeId != 0)
{
base.Text = parseMacrosToHtml(formatMedia(base.Text));
}
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
if (!IsInLiveEditingMode)
writer.Write(m_scriptInitBlock.ToString());
else
// add a marker to tell Live Editing when a tinyMCE control is on the page
writer.Write("<input type='hidden' id='__umbraco_tinyMCE' />");
}
protected override void OnLoad(EventArgs args)
{
if (!IsInLiveEditingMode)
this.config["elements"] = this.ClientID;
bool first = true;
// Render HTML for TinyMCE instance
// in the liveediting mode we're always preloading tinymce script
if (!IsInLiveEditingMode)
{
ScriptManager.RegisterClientScriptInclude(this, this.GetType(), _versionId.ToString(), this.ScriptURI);
}
// Write script tag start
m_scriptInitBlock.Append(HtmlTextWriter.TagLeftChar.ToString());
m_scriptInitBlock.Append("script");
m_scriptInitBlock.Append(" type=\"text/javascript\"");
m_scriptInitBlock.Append(HtmlTextWriter.TagRightChar.ToString());
m_scriptInitBlock.Append("\n");
m_scriptInitBlock.Append("tinyMCE.init({\n");
// Write options
foreach (string key in this.config.Keys)
{
//TODO: This is a hack to test if we can prevent tinymce from automatically download languages
if (!IsInLiveEditingMode || (key != "language"))
{
string val = this.config[key];
if (!first)
m_scriptInitBlock.Append(",\n");
else
first = false;
// Is boolean state or string
if (val == "true" || val == "false")
m_scriptInitBlock.Append(key + ":" + this.config[key]);
else
m_scriptInitBlock.Append(key + ":'" + this.config[key] + "'");
}
}
m_scriptInitBlock.Append("\n});\n");
// we're wrapping the tinymce init call in a load function when in live editing,
// so we'll need to close that function declaration
if (IsInLiveEditingMode)
{
m_scriptInitBlock.Append(@"(function() { var f =
function() {
if(document.getElementById('__umbraco_tinyMCE'))
tinyMCE.execCommand('mceAddControl',false,'").Append(ClientID).Append(@"');
ItemEditing.remove_startEdit(f);
}
ItemEditing.add_startEdit(f);})();");
m_scriptInitBlock.Append(@"(function() { var f =
function() {
tinyMCE.execCommand('mceRemoveControl',false,'").Append(ClientID).Append(@"');
ItemEditing.remove_stopEdit(f);
}
ItemEditing.add_stopEdit(f);})();");
}
// Write script tag end
m_scriptInitBlock.Append(HtmlTextWriter.EndTagLeftChars);
m_scriptInitBlock.Append("script");
m_scriptInitBlock.Append(HtmlTextWriter.TagRightChar.ToString());
// add to script manager
if (IsInLiveEditingMode)
{
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), new Guid().ToString(),
m_scriptInitBlock.ToString(), false);
}
}
string ScriptURI
{
get
{
string suffix = "", outURI;
if (this.InstallPath == null)
throw new Exception("Required installPath setting is missing, add it to your web.config. You can also add it directly to your tinymce:TextArea element using InstallPath but the web.config method is recommended since it allows you to switch over to gzip compression.");
if (this.mode != null)
suffix = "_" + this.mode;
outURI = this.InstallPath + "/tiny_mce_src" + suffix + ".js";
if (!File.Exists(this.Context.Server.MapPath(outURI)))
throw new Exception("Could not locate TinyMCE by URI:" + outURI + ", Physical path:" + this.Context.Server.MapPath(outURI) + ". Make sure that you configured the installPath to a valid location in your web.config. This path should be an relative or site absolute URI to where TinyMCE is located.");
// Collect themes, languages and plugins and build gzip URI
// TODO: Make sure gzip is re-enabled
this.gzipEnabled = true;
if (this.gzipEnabled)
{
ArrayList themes = new ArrayList(), plugins = new ArrayList(), languages = new ArrayList();
// Add themes
if (config["theme"] == null)
config["theme"] = "simple";
foreach (string theme in config["theme"].Split(','))
{
string themeVal = theme.Trim();
if (themes.IndexOf(themeVal) == -1)
themes.Add(themeVal);
}
// Add plugins
if (config["plugins"] != null)
{
foreach (string plugin in config["plugins"].Split(','))
{
string pluginVal = plugin.Trim();
if (plugins.IndexOf(pluginVal) == -1)
plugins.Add(pluginVal);
}
}
// Add language
if (config["language"] == null)
config["language"] = "en";
if (languages.IndexOf(config["language"]) == -1)
languages.Add(config["language"]);
// NH: No clue why these extra dashes are added, but the affect other parts of the implementation
// Skip loading of themes and plugins
// area.config["theme"] = "-" + area.config["theme"];
// if (area.config["plugins"] != null)
// area.config["plugins"] = "-" + String.Join(",-", area.config["plugins"].Split(','));
// Build output URI
// NH: Use versionId for randomize to ensure we don't download a new tinymce on every single call
outURI = umbraco.editorControls.tinymce.tinyMCEConfiguration.PluginPath + "/tinymce3tinymceCompress.aspx?rnd=" + this._versionId.ToString() + "&module=gzipmodule";
if (themes.Count > 0)
outURI += "&themes=" + String.Join(",", ((string[])themes.ToArray(typeof(string))));
if (plugins.Count > 0)
outURI += "&plugins=" + String.Join(",", ((string[])plugins.ToArray(typeof(string))));
if (languages.Count > 0)
outURI += "&languages=" + String.Join(",", ((string[])languages.ToArray(typeof(string))));
}
return outURI;
}
}
private string formatMedia(string html)
{
// Local media path
string localMediaPath = getLocalMediaPath();
// Find all media images
string pattern = "<img [^>]*src=\"(?<mediaString>/media[^\"]*)\" [^>]*>";
MatchCollection tags =
Regex.Matches(html, pattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
foreach (Match tag in tags)
if (tag.Groups.Count > 0)
{
// Replace /> to ensure we're in old-school html mode
string tempTag = "<img";
string orgSrc = tag.Groups["mediaString"].Value;
// gather all attributes
// TODO: This should be replaced with a general helper method - but for now we'll wanna leave umbraco.dll alone for this patch
Hashtable ht = new Hashtable();
MatchCollection m =
Regex.Matches(tag.Value.Replace(">", " >"),
"(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"|(?<attributeName>\\S*)=(?<attributeValue>[^\"|\\s]*)\\s",
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
foreach (Match attributeSet in m)
{
if (attributeSet.Groups["attributeName"].Value.ToString().ToLower() != "src")
ht.Add(attributeSet.Groups["attributeName"].Value.ToString(),
attributeSet.Groups["attributeValue"].Value.ToString());
}
// build the element
// Build image tag
IDictionaryEnumerator ide = ht.GetEnumerator();
while (ide.MoveNext())
tempTag += " " + ide.Key.ToString() + "=\"" + ide.Value.ToString() + "\"";
// Find the original filename, by removing the might added width and height
orgSrc =
orgSrc.Replace(
"_" + helper.FindAttribute(ht, "width") + "x" + helper.FindAttribute(ht, "height"), "").
Replace("%20", " ");
// Check for either id or guid from media
string mediaId = getIdFromSource(orgSrc, localMediaPath);
Media imageMedia = null;
try
{
int mId = int.Parse(mediaId);
Property p = new Property(mId);
imageMedia = new Media(Content.GetContentFromVersion(p.VersionId).Id);
}
catch
{
try
{
imageMedia = new Media(Content.GetContentFromVersion(new Guid(mediaId)).Id);
}
catch
{
}
}
// Check with the database if any media matches this url
if (imageMedia != null)
{
try
{
// Check extention
if (imageMedia.getProperty("umbracoExtension").Value.ToString() != orgSrc.Substring(orgSrc.LastIndexOf(".") + 1, orgSrc.Length - orgSrc.LastIndexOf(".") - 1))
orgSrc = orgSrc.Substring(0, orgSrc.LastIndexOf(".") + 1) +
imageMedia.getProperty("umbracoExtension").Value.ToString();
// Format the tag
tempTag = tempTag + " rel=\"" +
imageMedia.getProperty("umbracoWidth").Value.ToString() + "," +
imageMedia.getProperty("umbracoHeight").Value.ToString() + "\" src=\"" + orgSrc +
"\"";
tempTag += "/>";
// Replace the tag
html = html.Replace(tag.Value, tempTag);
}
catch (Exception ee)
{
Log.Add(LogTypes.Error, User.GetUser(0), -1,
"Error reading size data from media: " + imageMedia.Id.ToString() + ", " +
ee.ToString());
}
}
else
Log.Add(LogTypes.Error, User.GetUser(0), -1,
"Error reading size data from media (not found): " + orgSrc);
}
return html;
}
private string getIdFromSource(string src, string localMediaPath)
{
// important - remove out the umbraco path + media!
src = src.Replace(localMediaPath, "");
string _id = "";
// Check for directory id naming
if (src.Length - src.Replace("/", "").Length > 0)
{
string[] dirSplit = src.Split("/".ToCharArray());
string tempId = dirSplit[0];
try
{
// id
_id = int.Parse(tempId).ToString();
}
catch
{
// guid
_id = tempId;
}
}
else
{
string[] fileSplit = src.Replace("/media/", "").Split("-".ToCharArray());
// guid or id
if (fileSplit.Length > 3)
{
for (int i = 0; i < 5; i++)
_id += fileSplit[i] + "-";
_id = _id.Substring(0, _id.Length - 1);
}
else
_id = fileSplit[0];
}
return _id;
}
private string getLocalMediaPath()
{
string[] umbracoPathSplit = GlobalSettings.Path.Split("/".ToCharArray());
string umbracoPath = "";
for (int i = 0; i < umbracoPathSplit.Length - 1; i++)
umbracoPath += umbracoPathSplit[i] + "/";
return umbracoPath + "media/";
}
private string parseMacrosToHtml(string input)
{
int nodeId = _nodeId;
Guid versionId = _versionId;
string content = input;
string pattern = @"(<\?UMBRACO_MACRO\W*[^>]*/>)";
MatchCollection tags =
Regex.Matches(content, pattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
// Page for macro rendering
page p = new page(nodeId, versionId);
System.Web.HttpContext.Current.Items["macrosAdded"] = 0;
System.Web.HttpContext.Current.Items["pageID"] = nodeId.ToString();
foreach (Match tag in tags)
{
try
{
// Create div
Hashtable attributes = helper.ReturnAttributes(tag.Groups[1].Value);
string div = macro.renderMacroStartTag(attributes, nodeId, versionId); //.Replace("&quot;", "&amp;quot;");
// Insert macro contents here...
macro m;
if (helper.FindAttribute(attributes, "macroID") != "")
m = new macro(int.Parse(helper.FindAttribute(attributes, "macroID")));
else
{
// legacy: Check if the macroAlias is typed in lowercasing
string macroAlias = helper.FindAttribute(attributes, "macroAlias");
if (macroAlias == "")
{
macroAlias = helper.FindAttribute(attributes, "macroalias");
attributes.Remove("macroalias");
attributes.Add("macroAlias", macroAlias);
}
if (macroAlias != "")
m = new macro(Macro.GetByAlias(macroAlias).Id);
else
throw new ArgumentException("umbraco is unable to identify the macro. No id or macroalias was provided for the macro in the macro tag.", tag.Groups[1].Value);
}
if (helper.FindAttribute(attributes, "macroAlias") == "")
attributes.Add("macroAlias", m.Alias);
try
{
div += macro.MacroContentByHttp(nodeId, versionId, attributes);
}
catch
{
div += "<span style=\"color: green\">No macro content available for WYSIWYG editing</span>";
}
div += macro.renderMacroEndTag();
content = content.Replace(tag.Groups[1].Value, div);
}
catch (Exception ee)
{
Log.Add(LogTypes.Error, this._nodeId, "Macro Parsing Error: " + ee.ToString());
string div = "<div class=\"umbMacroHolder mceNonEditable\"><p style=\"color: red\"><strong>umbraco was unable to parse a macro tag, which means that parts of this content might be corrupt.</strong> <br /><br />Best solution is to rollback to a previous version by right clicking the node in the tree and then try to insert the macro again. <br/><br/>Please report this to your system administrator as well - this error has been logged.</p></div>";
content = content.Replace(tag.Groups[1].Value, div);
}
}
return content;
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* $Id: ConfigSection.cs 439 2007-11-26 13:26:10Z spocke $
*
* @author Moxiecode
* @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.Collections.Specialized;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
/// Description of ConfigSection.
/// </summary>
public class ConfigSection {
#region private
private NameValueCollection globalSettings;
private bool gzipEnabled, gzipDiskCache, gzipNoCompression;
private string installPath, mode, gzipCachePath;
private long gzipExpiresOffset;
#endregion
/// <summary>
///
/// </summary>
public ConfigSection() {
this.globalSettings = new NameValueCollection();
}
/// <summary>
///
/// </summary>
public string InstallPath {
get { return installPath; }
set { installPath = value; }
}
/// <summary>
///
/// </summary>
public string Mode {
get { return mode; }
set { mode = value; }
}
/// <summary>
///
/// </summary>
public NameValueCollection GlobalSettings {
get { return globalSettings; }
set { globalSettings = value; }
}
/// <summary>
///
/// </summary>
public bool GzipEnabled {
get { return gzipEnabled; }
set { gzipEnabled = value; }
}
/// <summary>
///
/// </summary>
public long GzipExpiresOffset {
get { return gzipExpiresOffset; }
set { gzipExpiresOffset = value; }
}
/// <summary>
///
/// </summary>
public bool GzipDiskCache {
get { return gzipDiskCache; }
set { gzipDiskCache = value; }
}
/// <summary>
///
/// </summary>
public string GzipCachePath {
get { return gzipCachePath; }
set { gzipCachePath = value; }
}
/// <summary>
///
/// </summary>
public bool GzipNoCompression {
get { return gzipNoCompression; }
set { gzipNoCompression = value; }
}
}
}

View File

@@ -0,0 +1,264 @@
/*
* $Id: GzipCompressor.cs 439 2007-11-26 13:26:10Z spocke $
*
* @author Moxiecode
* @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.Web;
using System.Collections;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
/// Description of GzipCompressor.
/// </summary>
public class GzipCompressor {
#region private
private bool diskCache, noCompression;
private string cachePath;
private ArrayList items;
#endregion
/// <summary>
///
/// </summary>
public GzipCompressor() {
this.items = new ArrayList();
}
/// <summary>
///
/// </summary>
public bool NoCompression {
get { return noCompression; }
set { noCompression = value; }
}
/// <summary>
///
/// </summary>
public bool DiskCache {
get { return diskCache; }
set { diskCache = value; }
}
/// <summary>
///
/// </summary>
public string CachePath {
get { return cachePath; }
set { cachePath = value; }
}
/// <summary>
///
/// </summary>
/// <param name="path"></param>
public void AddFile(string path) {
//System.Web.HttpContext.Current.Response.Write(path + "\n");
if (File.Exists(path))
this.items.Add(new CompressItem(CompressItemType.File, path));
else
throw new Exception("File could not be found \"" + path + "\", unable to add it for Gzip compression.");
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
public void AddData(string data) {
this.items.Add(new CompressItem(CompressItemType.Chunk, data));
}
/// <summary>
///
/// </summary>
/// <param name="to_stream"></param>
public void Compress(Stream to_stream) {
GZipStream gzipStream = null;
string key = "";
byte[] bytes;
// Build cache key
foreach (CompressItem item in this.items) {
if (item.Type == CompressItemType.File)
key += item.Data;
}
key = MD5(key);
if (this.NoCompression) {
this.SendPlainText(key, to_stream);
return;
}
// Check for cached file on disk, stream that one if it was found
if (this.DiskCache && File.Exists(Path.Combine(this.CachePath, key + ".gz"))) {
this.StreamFromTo(File.OpenRead(Path.Combine(this.CachePath, key + ".gz")), to_stream, 4096, CloseMode.InStream);
return;
}
try {
// Build new gzipped stream
if (this.DiskCache) {
gzipStream = new GZipStream(File.OpenWrite(Path.Combine(this.CachePath, key + ".gz")), CompressionMode.Compress);
// Compress all files into memory
foreach (CompressItem item in this.items) {
// Add file
if (item.Type == CompressItemType.File)
StreamFromTo(File.OpenRead(item.Data), gzipStream, 4096, CloseMode.InStream);
// Add chunk
if (item.Type == CompressItemType.Chunk) {
bytes = Encoding.ASCII.GetBytes(item.Data.ToCharArray());
gzipStream.Write(bytes, 0, bytes.Length);
}
}
// Close gzip stream
gzipStream.Close();
gzipStream = null;
// Send cached file to user
this.StreamFromTo(File.OpenRead(Path.Combine(this.CachePath, key + ".gz")), to_stream, 4096, CloseMode.InStream);
} else {
gzipStream = new GZipStream(to_stream, CompressionMode.Compress);
// Compress all files into output stream
foreach (CompressItem item in this.items) {
// Add file
if (item.Type == CompressItemType.File)
StreamFromTo(File.OpenRead(item.Data), gzipStream, 4096, CloseMode.InStream);
// Add chunk
if (item.Type == CompressItemType.Chunk) {
bytes = Encoding.ASCII.GetBytes(item.Data.ToCharArray());
gzipStream.Write(bytes, 0, bytes.Length);
}
}
}
} finally {
if (gzipStream != null)
gzipStream.Close();
}
}
#region private
private void SendPlainText(string key, Stream to_stream) {
Stream fileStream = null;
byte[] bytes;
// Check for cached file on disk, stream that one if it was found
if (this.DiskCache && File.Exists(Path.Combine(this.CachePath, key + ".js"))) {
this.StreamFromTo(File.OpenRead(Path.Combine(this.CachePath, key + ".js")), to_stream, 4096, CloseMode.InStream);
return;
}
// Build new plain text stream
if (this.DiskCache) {
try {
fileStream = File.OpenWrite(Path.Combine(this.CachePath, key + ".js"));
// Compress all files into memory
foreach (CompressItem item in this.items) {
// Add file
if (item.Type == CompressItemType.File)
StreamFromTo(File.OpenRead(item.Data), fileStream, 4096, CloseMode.InStream);
// Add chunk
if (item.Type == CompressItemType.Chunk) {
bytes = Encoding.ASCII.GetBytes(item.Data.ToCharArray());
fileStream.Write(bytes, 0, bytes.Length);
}
}
// Close file stream
fileStream.Close();
fileStream = null;
} finally {
// Close file stream
if (fileStream != null)
fileStream.Close();
}
// Send cached file to user
this.StreamFromTo(File.OpenRead(Path.Combine(this.CachePath, key + ".js")), to_stream, 4096, CloseMode.InStream);
} else {
// Concat all files into output stream
foreach (CompressItem item in this.items) {
// Add file
if (item.Type == CompressItemType.File)
StreamFromTo(File.OpenRead(item.Data), to_stream, 4096, CloseMode.InStream);
// Add chunk
if (item.Type == CompressItemType.Chunk) {
bytes = Encoding.ASCII.GetBytes(item.Data.ToCharArray());
to_stream.Write(bytes, 0, bytes.Length);
}
}
}
}
private void StreamFromTo(Stream in_stream, Stream out_stream, int buff_size, CloseMode mode) {
byte[] buff = new byte[buff_size];
int len;
try {
while ((len = in_stream.Read(buff, 0, buff_size)) > 0) {
out_stream.Write(buff, 0, len);
out_stream.Flush();
}
} finally {
if (in_stream != null && (mode == CloseMode.Both || mode == CloseMode.InStream))
in_stream.Close();
if (out_stream != null && (mode == CloseMode.Both || mode == CloseMode.OutStream))
out_stream.Close();
}
}
private string MD5(string str) {
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(Encoding.ASCII.GetBytes(str));
str = BitConverter.ToString(result);
return str.Replace("-", "");
}
#endregion
}
enum CloseMode {
None, InStream, OutStream, Both
}
enum CompressItemType {
File, Chunk
}
class CompressItem {
private string data;
private CompressItemType type;
public CompressItem(CompressItemType type, string data) {
this.type = type;
this.data = data;
}
public string Data {
get { return data; }
set { data = value; }
}
public CompressItemType Type {
get { return type; }
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* $Id: GzipModule.cs 439 2007-11-26 13:26:10Z spocke $
*
* @author Moxiecode
* @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.Web;
using System.Text.RegularExpressions;
using System.IO;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
/// Description of HttpHandler.
/// </summary>
public class GzipModule : IModule {
/// <summary></summary>
/// <param name="context">Request context.</param>
public void ProcessRequest(HttpContext context) {
HttpRequest request = context.Request;
HttpResponse response = context.Response;
HttpServerUtility server = context.Server;
GzipCompressor gzipCompressor = new GzipCompressor();
ConfigSection configSection = (ConfigSection) System.Web.HttpContext.Current.GetSection("TinyMCE");
string suffix = "", enc;
string[] languages = request.QueryString["languages"].Split(',');
bool supportsGzip;
// Set response headers
response.ContentType = "text/javascript";
response.Charset = "UTF-8";
response.Buffer = false;
// UMBRACO: Populate the configsection if it's empty
if (configSection == null)
{
configSection = new ConfigSection();
configSection.GzipEnabled = true;
configSection.InstallPath = umbraco.editorControls.tinymce.tinyMCEConfiguration.JavascriptPath;
configSection.GzipExpiresOffset = TimeSpan.FromDays(10).Ticks;
}
// Setup cache
response.Cache.SetExpires(DateTime.Now.AddTicks(configSection.GzipExpiresOffset));
response.Cache.SetCacheability(HttpCacheability.Public);
response.Cache.SetValidUntilExpires(false);
// Check if it supports gzip
enc = Regex.Replace("" + request.Headers["Accept-Encoding"], @"\s+", "").ToLower();
supportsGzip = enc.IndexOf("gzip") != -1 || request.Headers["---------------"] != null;
enc = enc.IndexOf("x-gzip") != -1 ? "x-gzip" : "gzip";
// Handle mode/suffix
if (configSection.Mode != null)
suffix = "_" + configSection.Mode;
gzipCompressor.AddData("var tinyMCEPreInit = {base : '" + new Uri(request.Url, configSection.InstallPath).ToString() + "', suffix : '" + suffix + "'};");
// Add core
gzipCompressor.AddFile(server.MapPath(configSection.InstallPath + "/tiny_mce" + suffix + ".js"));
// Add core languages
foreach (string lang in languages)
gzipCompressor.AddFile(server.MapPath(configSection.InstallPath + "/langs/" + lang + ".js"));
// Add themes
if (request.QueryString["themes"] != null) {
foreach (string theme in request.QueryString["themes"].Split(',')) {
gzipCompressor.AddFile(server.MapPath(configSection.InstallPath + "/themes/" + theme + "/editor_template" + suffix + ".js"));
// Add theme languages
foreach (string lang in languages) {
string path = server.MapPath(configSection.InstallPath + "/themes/" + theme + "/langs/" + lang + ".js");
if (File.Exists(path))
gzipCompressor.AddFile(path);
}
gzipCompressor.AddData("tinymce.ThemeManager.urls['" + theme + "'] = tinymce.baseURL+'/themes/" + theme + "';");
}
}
// Add plugins
if (request.QueryString["plugins"] != null) {
foreach (string plugin in request.QueryString["plugins"].Split(',')) {
gzipCompressor.AddFile(server.MapPath(configSection.InstallPath + "/plugins/" + plugin + "/editor_plugin" + suffix + ".js"));
// Add plugin languages
foreach (string lang in languages) {
string path = server.MapPath(configSection.InstallPath + "/plugins/" + plugin + "/langs/" + lang + ".js");
if (File.Exists(path))
gzipCompressor.AddFile(path);
}
gzipCompressor.AddData("tinymce.ThemeManager.urls['" + plugin + "'] = tinymce.baseURL+'/plugins/" + plugin + "';");
}
}
// Output compressed file
gzipCompressor.NoCompression = !supportsGzip || configSection.GzipNoCompression;
if (!gzipCompressor.NoCompression)
response.AppendHeader("Content-Encoding", enc);
gzipCompressor.DiskCache = configSection.GzipDiskCache;
gzipCompressor.CachePath = configSection.GzipCachePath;
gzipCompressor.Compress(response.OutputStream);
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* Created by SharpDevelop.
* User: spocke
* Date: 2007-11-22
* Time: 14:32
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Web;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin {
/// <summary>
/// Description of IAction.
/// </summary>
public interface IModule {
/// <summary>
///
/// </summary>
/// <param name="context"></param>
void ProcessRequest(HttpContext context);
}
}

View File

@@ -0,0 +1,352 @@
/*
* $Id: JSON.cs 439 2007-11-26 13:26:10Z spocke $
*
* Copyright © 2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
/// Description of JSON.
/// </summary>
public class JSON {
/// <summary>
///
/// </summary>
public static void SerializeRPC(string id, object error, object obj, Stream stream) {
JSONWriter writer = new JSONWriter(new StreamWriter(stream));
// Start JSON output
writer.WriteStartObject();
writer.WritePropertyName("result");
WriteValue(writer, obj);
// Write id
writer.WritePropertyName("id");
writer.WriteValue(id);
// Write error
writer.WritePropertyName("error");
writer.WriteValue(null);
// Close
writer.WriteEndObject();
writer.Close();
}
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
/// <param name="obj"></param>
public static void WriteObject(TextWriter writer, object obj) {
WriteValue(new JSONWriter(writer), obj);
writer.Flush();
}
private static void WriteValue(JSONWriter writer, object obj) {
if (obj == null)
writer.WriteNull();
if (obj is System.String)
writer.WriteValue((string) obj);
if (obj is System.Boolean)
writer.WriteValue((bool) obj);
if (obj is System.Double)
writer.WriteValue(Convert.ToDouble(obj));
if (obj is System.Int32)
writer.WriteValue(Convert.ToInt32(obj));
if (obj is System.Int64)
writer.WriteValue(Convert.ToInt64(obj));
if (obj is ArrayList) {
writer.WriteStartArray();
foreach (object val in ((ArrayList) obj))
WriteValue(writer, val);
writer.WriteEndArray();
}
if (obj is string[]) {
writer.WriteStartArray();
foreach (string val in ((string[]) obj))
WriteValue(writer, val);
writer.WriteEndArray();
}
if (obj is NameValueCollection) {
writer.WriteStartObject();
string[] keys = GetReversedKeys(obj);
foreach (string key in keys) {
writer.WritePropertyName(key);
WriteValue(writer, ((NameValueCollection) obj)[key]);
}
writer.WriteEndObject();
}
if (obj is Hashtable) {
writer.WriteStartObject();
string[] keys = GetReversedKeys(obj);
foreach (string key in keys) {
writer.WritePropertyName((string) key);
WriteValue(writer, ((Hashtable) obj)[key]);
}
writer.WriteEndObject();
}
}
private static string[] GetReversedKeys(object obj) {
ICollection keyCollection;
string[] keys;
int count;
if (obj is Hashtable)
keyCollection = ((Hashtable) obj).Keys;
else
keyCollection = ((NameValueCollection) obj).AllKeys;
count = keyCollection.Count;
keys = new string[count];
foreach (string key in keyCollection)
keys[--count] = key;
Array.Sort(keys);
return keys;
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
public static object ParseJSON(TextReader reader) {
return ReadValue(new JSONReader(reader));
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
public static JSONRpcCall ParseRPC(TextReader reader) {
JSONRpcCall call = new JSONRpcCall();
object obj = ParseJSON(reader);
Hashtable jsonRpc = (Hashtable) obj;
call.Method = (string) jsonRpc["method"];
call.Id = (string) jsonRpc["id"];
call.Args = (ArrayList) jsonRpc["params"];
return call;
}
#region private methods
/* private static void Debug(string str) {
System.Web.HttpContext.Current.Trace.Write(str);
}*/
private static object ReadValue(JSONReader reader) {
Stack parents = new Stack();
object cur = null;
string key = null;
object obj;
while (reader.Read()) {
//Debug(reader.ToString());
switch (reader.TokenType) {
case JSONToken.Boolean:
case JSONToken.Integer:
case JSONToken.String:
case JSONToken.Float:
case JSONToken.Null:
if (cur is Hashtable) {
//Debug(key + "=" + reader.ToString());
((Hashtable) cur)[key] = reader.Value;
} else if (cur is ArrayList)
((ArrayList) cur).Add(reader.Value);
else
return reader.Value;
break;
case JSONToken.PropertyName:
key = (string) reader.Value;
break;
case JSONToken.StartArray:
case JSONToken.StartObject:
if (reader.TokenType == JSONToken.StartObject)
obj = new Hashtable();
else
obj = new ArrayList();
if (cur is Hashtable) {
//Debug(key + "=" + reader.ToString());
((Hashtable) cur)[key] = obj;
} else if (cur is ArrayList)
((ArrayList) cur).Add(obj);
parents.Push(cur);
cur = obj;
break;
case JSONToken.EndArray:
case JSONToken.EndObject:
obj = parents.Pop();
if (obj != null)
cur = obj;
break;
}
}
return cur;
}
private static object ReadValue2(JSONReader jsonReader) {
jsonReader.Read();
switch (jsonReader.TokenType) {
case JSONToken.Boolean:
return (bool) jsonReader.Value;
case JSONToken.Integer:
return Convert.ToInt32(jsonReader.Value);
case JSONToken.String:
return (string) jsonReader.Value;
case JSONToken.Float:
return (double) jsonReader.Value;
case JSONToken.Null:
return null;
case JSONToken.StartObject:
Hashtable hash = new Hashtable();
while (jsonReader.TokenType != JSONToken.EndObject) {
if (jsonReader.TokenType == JSONToken.PropertyName)
hash[jsonReader.Value] = ReadValue(jsonReader);
else
jsonReader.Read();
}
return hash;
case JSONToken.StartArray:
ArrayList list = new ArrayList();
while (jsonReader.TokenType != JSONToken.EndArray) {
if (jsonReader.TokenType == JSONToken.EndArray && jsonReader.Value == null)
break;
list.Add(ReadValue(jsonReader));
}
return list;
}
return null;
}
private static bool FindNext(JSONReader reader, JSONToken token) {
if (reader.TokenType == token)
return true;
while (reader.Read() && reader.TokenType != JSONToken.EndObject && reader.TokenType != JSONToken.EndArray) {
if (reader.TokenType == token)
return true;
}
return false;
}
private static bool FindNextValue(JSONReader reader) {
switch (reader.TokenType) {
case JSONToken.Boolean:
case JSONToken.Float:
case JSONToken.Integer:
case JSONToken.Null:
case JSONToken.String:
return true;
}
while (reader.Read() && reader.TokenType != JSONToken.EndObject) {
switch (reader.TokenType) {
case JSONToken.Boolean:
case JSONToken.Float:
case JSONToken.Integer:
case JSONToken.Null:
case JSONToken.String:
return true;
}
}
return false;
}
#endregion
}
/// <summary>
///
/// </summary>
public class JSONRpcCall {
private string id, method;
private ArrayList args;
/// <summary>
///
/// </summary>
public JSONRpcCall() {
this.args = new ArrayList();
}
/// <summary>
///
/// </summary>
public string Method {
get { return method; }
set { method = value; }
}
/// <summary>
///
/// </summary>
public string Id {
get { return id; }
set { id = value; }
}
/// <summary>
///
/// </summary>
public ArrayList Args {
get { return args; }
set { args = value; }
}
}
}

View File

@@ -0,0 +1,387 @@
/*
* $Id: JSONReader.cs 439 2007-11-26 13:26:10Z spocke $
*
* Copyright © 2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.IO;
using System.Text;
using System.Collections;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
///
/// </summary>
public enum JSONToken {
/// <summary> </summary>
Boolean,
/// <summary> </summary>
Integer,
/// <summary> </summary>
String,
/// <summary> </summary>
Null,
/// <summary> </summary>
Float,
/// <summary> </summary>
StartArray,
/// <summary> </summary>
EndArray,
/// <summary> </summary>
PropertyName,
/// <summary> </summary>
StartObject,
/// <summary> </summary>
EndObject
}
/// <summary>
/// Description of JSONReader.
/// </summary>
public class JSONReader {
private TextReader reader;
private JSONToken token;
private object val;
private JSONLocation location;
private Stack lastLocations;
private bool needProp;
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
public JSONReader(TextReader reader) {
this.reader = reader;
this.val = null;
this.token = JSONToken.Null;
this.location = JSONLocation.Normal;
this.lastLocations = new Stack();
this.needProp = false;
}
/// <summary>
///
/// </summary>
public JSONLocation Location {
get { return location; }
}
/// <summary>
///
/// </summary>
public JSONToken TokenType {
get {
return this.token;
}
}
/// <summary>
///
/// </summary>
public object Value {
get {
return this.val;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool Read() {
int chr = this.reader.Read();
if (chr != -1) {
switch ((char) chr) {
case '[':
this.lastLocations.Push(this.location);
this.location = JSONLocation.InArray;
this.token = JSONToken.StartArray;
this.val = null;
this.ReadAway();
return true;
case ']':
this.location = (JSONLocation) this.lastLocations.Pop();
this.token = JSONToken.EndArray;
this.val = null;
this.ReadAway();
if (this.location == JSONLocation.InObject)
this.needProp = true;
return true;
case '{':
this.lastLocations.Push(this.location);
this.location = JSONLocation.InObject;
this.needProp = true;
this.token = JSONToken.StartObject;
this.val = null;
this.ReadAway();
return true;
case '}':
this.location = (JSONLocation) this.lastLocations.Pop();
this.token = JSONToken.EndObject;
this.val = null;
this.ReadAway();
if (this.location == JSONLocation.InObject)
this.needProp = true;
return true;
// String
case '"':
case '\'':
return this.ReadString((char) chr);
// Null
case 'n':
return this.ReadNull();
// Bool
case 't':
case 'f':
return this.ReadBool((char) chr);
default:
// Is number
if (Char.IsNumber((char) chr) || (char) chr == '-' || (char) chr == '.')
return this.ReadNumber((char) chr);
return true;
}
}
return false;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString() {
switch (this.token) {
case JSONToken.Boolean:
return "[Boolean] = " + ((bool) this.Value ? "true" : "false");
case JSONToken.EndArray:
return "[EndArray]";
case JSONToken.EndObject:
return "[EndObject]";
case JSONToken.Float:
return "[Float] = " + Convert.ToDouble(this.Value);
case JSONToken.Integer:
return "[Integer] = " + ((int) this.Value);
case JSONToken.Null:
return "[Null]";
case JSONToken.StartArray:
return "[StartArray]";
case JSONToken.StartObject:
return "[StartObject]";
case JSONToken.String:
return "[String]" + (string) this.Value;
case JSONToken.PropertyName:
return "[PropertyName]" + (string) this.Value;
}
return base.ToString();
}
#region private methods
private bool ReadString(char quote) {
StringBuilder buff = new StringBuilder();
this.token = JSONToken.String;
bool endString = false;
int chr;
while ((chr = this.reader.Peek()) != -1) {
switch (chr) {
case '\\':
// Read away slash
chr = this.reader.Read();
// Read escape code
chr = this.reader.Read();
switch (chr) {
case 't':
buff.Append('\t');
break;
case 'b':
buff.Append('\b');
break;
case 'f':
buff.Append('\f');
break;
case 'r':
buff.Append('\r');
break;
case 'n':
buff.Append('\n');
break;
case 'u':
buff.Append((char) Convert.ToInt32(ReadLen(4), 16));
break;
default:
buff.Append((char) chr);
break;
}
break;
case '\'':
case '"':
if (chr == quote)
endString = true;
chr = this.reader.Read();
if (chr != -1 && chr != quote)
buff.Append((char) chr);
break;
default:
buff.Append((char) this.reader.Read());
break;
}
// String terminated
if (endString)
break;
}
this.ReadAway();
this.val = buff.ToString();
// Needed a property
if (this.needProp) {
this.token = JSONToken.PropertyName;
this.needProp = false;
return true;
}
if (this.location == JSONLocation.InObject && !this.needProp)
this.needProp = true;
return true;
}
private bool ReadNull() {
this.token = JSONToken.Null;
this.val = null;
this.ReadAway(3); // ull
this.ReadAway();
if (this.location == JSONLocation.InObject && !this.needProp)
this.needProp = true;
return true;
}
private bool ReadNumber(char start) {
StringBuilder buff = new StringBuilder();
int chr;
bool isFloat = false;
this.token = JSONToken.Integer;
buff.Append(start);
while ((chr = this.reader.Peek()) != -1) {
if (Char.IsNumber((char) chr) || (char) chr == '-' || (char) chr == '.') {
if (((char) chr) == '.')
isFloat = true;
buff.Append((char) this.reader.Read());
} else
break;
}
this.ReadAway();
if (isFloat) {
this.token = JSONToken.Float;
this.val = Convert.ToDouble(buff.ToString().Replace('.', ','));
} else
this.val = Convert.ToInt32(buff.ToString());
if (this.location == JSONLocation.InObject && !this.needProp)
this.needProp = true;
return true;
}
private bool ReadBool(char chr) {
this.token = JSONToken.Boolean;
this.val = chr == 't';
if (chr == 't')
this.ReadAway(3); // rue
else
this.ReadAway(4); // alse
this.ReadAway();
if (this.location == JSONLocation.InObject && !this.needProp)
this.needProp = true;
return true;
}
private void ReadAway() {
int chr;
while ((chr = this.reader.Peek()) != -1) {
if (chr != ':' && chr != ',' && !Char.IsWhiteSpace((char) chr))
break;
this.reader.Read();
}
}
private string ReadLen(int num) {
StringBuilder buff = new StringBuilder();
int chr;
for (int i=0; i<num && (chr = this.reader.Read()) != -1; i++)
buff.Append((char) chr);
return buff.ToString();
}
private void ReadAway(int num) {
for (int i=0; i<num && this.reader.Read() != -1; i++) ;
}
#endregion
}
}

View File

@@ -0,0 +1,226 @@
/*
* $Id: JSONWriter.cs 439 2007-11-26 13:26:10Z spocke $
*
* Copyright © 2007, Moxiecode Systems AB, All rights reserved.
*/
using System;
using System.Text;
using System.IO;
using System.Collections;
namespace umbraco.editorControls.tinyMCE3.webcontrol.plugin
{
/// <summary>
///
/// </summary>
public enum JSONLocation {
/// <summary> </summary>
InArray,
/// <summary> </summary>
InObject,
/// <summary> </summary>
Normal
}
/// <summary>
/// Description of JSONWriter.
/// </summary>
public class JSONWriter {
private TextWriter writer;
private JSONLocation location;
private Stack lastLocations;
private int index, lastIndex;
private bool isProp = false;
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
public JSONWriter(TextWriter writer) {
this.writer = writer;
this.location = JSONLocation.Normal;
this.lastLocations = new Stack();
this.index = 0;
this.lastIndex = 0;
}
/// <summary>
///
/// </summary>
public void WriteStartObject() {
this.WriteDelim();
this.writer.Write('{');
this.lastLocations.Push(this.location);
this.lastIndex = this.index;
this.location = JSONLocation.InObject;
this.index = 0;
}
/// <summary>
///
/// </summary>
public void WriteEndObject() {
this.writer.Write('}');
this.location = (JSONLocation) lastLocations.Pop();
this.index = this.lastIndex;
}
/// <summary>
///
/// </summary>
public void WriteStartArray() {
this.WriteDelim();
this.writer.Write('[');
this.lastLocations.Push(this.location);
this.lastIndex = this.index;
this.location = JSONLocation.InArray;
this.index = 0;
}
/// <summary>
///
/// </summary>
public void WriteEndArray() {
this.writer.Write(']');
this.location = (JSONLocation) lastLocations.Pop();
this.index = this.lastIndex;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
public void WritePropertyName(string name) {
this.WriteDelim();
this.isProp = true;
this.WriteObject(EncodeString(name));
this.writer.Write(':');
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void WriteProperty(string name, object obj) {
this.WritePropertyName(name);
this.WriteObject(obj);
}
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
public void WriteValue(object obj) {
this.WriteDelim();
this.WriteObject(obj);
}
/// <summary>
///
/// </summary>
public void WriteNull() {
this.WriteDelim();
this.writer.Write("null");
}
/// <summary>
///
/// </summary>
public void Close() {
this.writer.Close();
}
#region private methods
private void WriteObject(object obj) {
if (obj == null) {
this.writer.Write("null");
return;
}
if (obj is bool) {
this.writer.Write(((bool) obj) == true ? "true" : "false");
return;
}
if (obj is int) {
this.writer.Write(((int) obj));
return;
}
if (obj is long) {
this.writer.Write(((long) obj));
return;
}
if (obj is float || obj is double) {
string str = Convert.ToString(obj);
this.writer.Write(str.Replace(',', '.'));
return;
}
if (obj is string) {
this.writer.Write('"');
this.writer.Write(EncodeString((string) obj));
this.writer.Write('"');
return;
}
}
private void WriteDelim() {
if (this.index > 0 && !this.isProp)
this.writer.Write(',');
this.isProp = false;
this.index++;
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string EncodeString(string str) {
if (str == null)
return null;
StringBuilder strBuilder = new StringBuilder(str.Length);
char[] chars = str.ToCharArray();
for (int i=0; i<chars.Length; i++) {
// Unicode it if needed
if (chars[i] > 128 || Char.IsControl(chars[i])) {
strBuilder.Append("\\u");
strBuilder.Append(((int) chars[i]).ToString("X4"));
continue;
}
switch (chars[i]) {
case '\'':
strBuilder.Append("\\\'");
break;
case '\"':
strBuilder.Append("\\\"");
break;
case '\\':
strBuilder.Append("\\\\");
break;
default:
strBuilder.Append(chars[i]);
break;
}
}
return strBuilder.ToString();
}
#endregion
}
}