ScrewTurn Wiki各种问题解决方法.
更换编辑器
鉴于ScrewTurn的编辑器很不好使用,我将其替换成了CKEditor.将替换方法记录如下.
第一步:安装CKEditor for ASP.NET
下载地点在http://ckeditor.com/download.由于我之前用的是ScrewTurn的ASP.NET版本,因此需要下载.NET版本
解压之后将_Samples/bin/CKEditor.NET.dll拷贝到ScrewTurn/bin文件夹中.并将CKEditor/ckeditor文件夹拷贝入ScrewTurn网站根目录下.
修改Web.config添加如下配置
<system.web> <pages> <controls> <add tagPrefix="CKEditor" assembly="CKEditor.NET" namespace="CKEditor.NET"/> </controls> </pages> </system.web>
第二部:修改ScrewTurn代码
ScrewTurn原有的Editor定义在Editor.ashx中,主要在Edit.aspx, Post.aspx和两个Admin页面中使用.在这里我们只替换掉Edit.aspx中的Editor控件,其他类似.
修改Edit.aspx中的
<st:Editor ID="editor" runat="server" OnSelectedTabChanged="editor_SelectedTabChanged" />
为
<p> <CKEditor:CKEditorControl ID="editor" runat="server" Toolbar="Full"></CKEditor:CKEditorControl> </p>
其中的Toolbar="Full"表示工具栏中的项目,具体可以参考CKEditor的文档.
然后修改Editor.aspx.cs中所有对于editor的引用.主要是将原editor.content的get和set方法改成用CKEditor的Text属性,由于CKEditor没有Wiki Markup和可见即所得模式的区别,原来的两种模式的更改和载入的代码页可以去掉.
之后重新生成网站就大功告成了.
修正TAB无法切换问题
ScrewTurn使用了一个非常老的AJAX库Anthem,这个库的代码写的非常之诡异,导致ScrewTurn中很多使用AJAX的TAB切换无法正常操作.
修复方法如下
在ScrewTurn\References\Lib\Anthem.NET下,有Anthem的源码压缩包,解压之后包含了一个js文件和若干cs文件.js文件中的Anthem_Callback方法会向url?Anthem_CallBack=true Post一个获取数据的XHttpRequest.之后就由UpdatePage方法来更新页面.造成问题的如下一段代码
if (result.controls) { for (var controlID in result.controls) { var containerID = "Anthem_" + controlID.split("$").join("_") + "__"; var control = document.getElementById(containerID); if (control) { control.innerHTML = result.controls[controlID]; if (result.controls[controlID] == "") { control.style.display = "none"; } else { control.style.display = ""; } } } }
这段代码会遍历result中的controls列表,然后生成containerID,之后去修改containerID对应的DOM元素的内容.
当标签无法切换的时候可以根据返回值生成的ID和页面中元素的ID是不对应的.
究其原因,是因为Manager.cs中生成页面id和生成AJAX返回值使用了不同的方法.
public static void WriteBeginControlMarker(HtmlTextWriter writer, string parentTagName, Control control) { writer.Write("<{0} id=\"{1}\">", parentTagName, "Anthem_" + control.ClientID + "__"); IUpdatableControl updatableControl = control as IUpdatableControl; if (updatableControl != null && updatableControl.UpdateAfterCallBack && IsCallBack) { writer.Write(_beginControlMarker); writer.Write(GetUniqueIDWithDollars(control)); writer.Write("-->"); } }
这里可以看到,页面元素中的ID是使用control.ClientID生成的.
而AJAX返回的响应中的生成代码在如下两段
private Hashtable GetControls(string html) { Hashtable controls = new Hashtable(); // Find the first begin marker. int i = html.IndexOf(_beginControlMarker); // Keep looping while we've got markers. while (i != -1) { i += _beginControlMarker.Length; // Find the end of the begin marker. int j = html.IndexOf("-->", i); if (j == -1) { break; } else { // The string between i and j should be the ClientID. string id = html.Substring(i, j - i); // Point past the end of the begin marker. i = j + 3; string endMarker = _endControlMarker + id + "-->"; // Find the end marker for the current control. j = html.IndexOf(endMarker, i); if (j == -1) { break; } else { // The string between i and j is now the HTML. string control = html.Substring(i, j - i); controls[id] = control; // Point past the end of the end marker. i = j + endMarker.Length; } } // Find the next begin marker. i = html.IndexOf(_beginControlMarker, i); } return controls; }
if (_updatePage) { string html = HttpContext.Current.Response.ContentEncoding.GetString(htmlBuffer.GetBuffer()); viewState = GetViewState(html); #if V2 viewStateEncrypted = GetViewStateEncrypted(html); eventValidation = GetEventValidation(html); #endif controls = GetControls(html); foreach (object o in _targets.Values) { Control c = o as Control; if (c != null && !c.Visible) { if (c.ID!= null && controls.ContainsKey(c.ID)) controls[c.ID] = ""; } } scripts = GetScripts(html); }
在GetControls方法中,该库使用了在WriteBeginControlMarker写入的control.ClientID来生成controls表,之后又使用control.ID来生成controls表.
在msdn中,我们可以看到这三者的不同
UniqueID:此属性与 ID 属性不同,因为 UniqueID 属性包含服务器控件的命名容器的标识符。
ClientID: 如果 Web 服务器控件作为 HTML 元素呈现时, HTML 元素的 id 属性设置为 ClientID 属性的值。
这样一来,AJAX的返回显然有可能和页面中的元素ID不一致.
如果需要修正这个问题,只需要把这三个ID改成同一个(我使用的是UniqueID),然后重新生成Anthem.dll拷贝入网站的bin目录下就可以了.