CodeProject 离线文章编辑器






4.97/5 (78投票s)
一个离线 WYSIWYG 编辑器,用于备份、编辑或创建新的 CodeProject 文章。
目录
引言
CP 文章 编辑器允许您在无需互联网连接的情况下创建/编辑 CodeProject 的文章。您还可以使用此程序登录以备份(您的文章和相关图片)并编辑您已发布的文章。它体积小巧且便携。
背景
让我们学习或回顾一些有助于理解源代码的内容。
异步操作
异步操作是独立运行的,它们有自己的线程。如果我们想在它们完成工作后执行代码,我们不能将这些代码写在启动它们的方法的下面。因为它们不会阻塞调用它们的方法。我们还必须知道的是,一个线程不能访问在另一个线程上创建的对象……
通常,我们使用 event
来处理在异步方法完成任务后必须执行的操作,或者在事件发生后执行的操作。但我为此目的使用了另一种方法,我认为它相对更容易理解。
假设我们有一个线程,并且想在我们的线程完成工作后调用一个函数
class Example
{
private Action after_MyThreadFinished;
private Form invoker;
public Example(Action after_MyThreadFinished, Form invoker)
{
this.after_MyThreadFinished = after_MyThreadFinished;
this.invoker = invoker;
}
public void doSomeWorksAsynchronously()
{
new Thread(() =>
{
// some codes that take long time...
Thread.Sleep(2000);
if (after_MyThreadFinished != null)
invoker.Invoke(after_MyThreadFinished);
}).Start();
}
}
一个线程不能直接更改由 UI 线程拥有的可视化对象。而且,我们不能确定用户不会在我们新线程中的代码中访问 UI 线程创建的可视化控件。这就是为什么我们需要一个调用者对象。
用法
private void button1_Click(object sender, EventArgs e)
{
Action myAction = new Action(() =>
{
MessageBox.Show("Finished.");
this.Text = "I can access all the objects without any trouble." +
"Because I will be invoked by the thread of this form.";
});
Example example = new Example(myAction, this);
example.doSomeWorksAsynchronously(); // It doesn't block the current thread.
}
CKEditor
CKEditor 是一个开源的所见即所得编辑器,可以轻松地集成到网页中。在这个项目中,我将它用在一个浏览器中。
我自定义了工具栏并删除了不必要的插件以减小总体大小。此外,我还修改了 image.js 插件以支持使用相对 URL。
// Original code: B.preview.setAttribute('src',s.$.src);
// Modified for CP Article Editor
// The modification has been made to convert a relative image src to an
// absolute src in preview window.
// begin
if(s.$.src.substring(0,7)=='http://' || s.$.src.substring(0,8)=='https://')
B.preview.setAttribute('src',s.$.src);
else
{
var kok=(document.getElementsByTagName('base')[0]==null?'**biseyyapma**':
document.getElementsByTagName('base')[0].getAttribute('href'));
var verilenAdres=C;
var tamAdres=kok+C;
B.preview.setAttribute('src',tamAdres);
}
// end
// Original code: --
// Modified for CP Article Editor
// The modification has been made to convert an absolute image src to a relative src.
// begin
kok=(document.getElementsByTagName('base')[0]==null?'**biseyyapma**':
document.getElementsByTagName('base')[0].getAttribute('href')),
D=(D.indexOf(kok)>-1?D.replace(kok,''):D),
// end
// Original code: C.data('cke-saved-src',D.getValue()); C.setAttribute('src',D.getValue());
// Modified for CP Article Editor
// The modification has been made to convert a relative image src to an absolute src.
// begin
var verilenAdres=D.getValue();
if(verilenAdres.substring(0,7)=='http://' || verilenAdres.substring(0,8)=='https://')
{
C.data('cke-saved-src',D.getValue());
C.setAttribute('src',D.getValue());
}
else
{
var kok=(document.getElementsByTagName('base')[0]==null?'**biseyyapma**':
document.getElementsByTagName('base')[0].getAttribute('href'));
var tamAdres=(verilenAdres.indexOf(kok)<0?kok+verilenAdres:verilenAdres)
C.data('cke-saved-src',tamAdres);
C.setAttribute('src',tamAdres);
}
// end
使用的配置
fullPage : false // We are not editing a full page
language : 'en' // I removed all other language files to decrease the size.
resize_enabled : false // Prevent resizing the editor.
uiColor : '#CCC' // Grey
tabSpaces : 4 // Each tab character is replaced with 4 spaces.
contentsCss : 'CodeProject.css' // CSS stylesheet file of codeproject template.
removePlugins : 'contextmenu,liststyle,tabletools' // For hiding ckeditor's context menu
docType : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' +
'"http://www.w3.org/TR/html4/loose.dtd">' // Document type of CodeProject.
访问和修改 HTML 文档的元素
我使用 WebBrowser
来登录和提取所需数据。这里有一些重要的方法。
读取元素的属性
webBrowser.Document.GetElementById("IdOfTheElement").GetAttribute("attribute");
更改元素的属性
webBrowser.Document.GetElementById("IdOfTheElement").SetAttribute("attribute", "new value");
从 C# 调用 WebBrowser
对象中的 JavaScript 函数
object[] args = new object[] { ... };
object returned = webBrowser.Document.InvokeScript("functionName", args);
从网站下载文件
有一个非常简单的方法可以从网站下载文件。我用这个方法下载与文章相关的图片。
WebClient webClient = new WebClient();
webClient.DownloadFile("http://www.site.com/file.extension", "C:\file.extension");
禁用 WebBrowser 中的点击声音
浏览器中没有禁用点击声音的属性。但是可以通过 CoInternetSetFeatureEnabled API 来实现。
static class ClickSoundDisabler
{
// ---------------------------------------------------
// CodeProjectArticleEditor > ClickSoundDisabler.cs
// ---------------------------------------------------
// CodeProject Article Editor
// Huseyin Atasoy
// September 2012
// ---------------------------------------------------
private const int FEATURE_DISABLE_NAVIGATION_SOUNDS = 21;
private const int SET_FEATURE_ON_PROCESS = 0x00000002;
[DllImport("urlmon.dll")]
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
private static extern int CoInternetSetFeatureEnabled(int FeatureEntry,
[MarshalAs(UnmanagedType.U4)] int dwFlags, bool fEnable);
public static void disableClickSound()
{
try
{
CoInternetSetFeatureEnabled(FEATURE_DISABLE_NAVIGATION_SOUNDS,
SET_FEATURE_ON_PROCESS, true);
}
catch{}
}
}
截图
这是程序的主窗口
如果您想备份已发布的文章进行编辑或仅保存它们,可以输入您的电子邮件和密码进行登录。登录后,您的文章将列出:
当您选择其中一篇文章时,将显示一些有关该文章的信息
即使您未连接到互联网,也可以撰写新文章或编辑现有文章
将文章传输到 CodeProject 的在线编辑器
- 从右键菜单中选择“将源复制到剪贴板”。
(请注意,所有绝对图片路径都已转换为相对路径。因此,您无需更改复制的 HTML 代码中的任何内容。) - 打开 CodeProject 在线编辑器。
- 点击“HTML”按钮切换到 HTML 模式
- 粘贴您的内容。(Ctrl+V)
- 再次点击“HTML”按钮切换回设计模式……
值得关注的点
让我们通过查看源代码来列出我们可以学到的东西
- .NET 中的所见即所得 HTML 编辑器。
- 如何在 .NET 中使用 ckeditor?
- 如何从 C# 函数调用
WebBrowser
中的 JavaScript 函数? - 自动化登录和数据提取。
- 在 C# 中使用
Action
而不是Event
来处理异步函数。 - 禁用 WebBrowser 控件中的点击声音。
- 在 C# 中从互联网下载文件。
历史
- 2013 年 12 月 15 日(v1.0.4)
- 在 CodeProject 进行一些更改后,修复了文章列表和登录方法。
- 2013 年 4 月 4 日(v1.0.3)
- 由于 CodeProject 的一些更新,登录最近失败了。已修复。
- 向 URL 追加了随机字符串,以强制 WebBrowser 重新加载缓存的页面。
- 2012 年 10 月 17 日(v1.0.2)
- 新的代码用于记住上次浏览的路径
- 对
extractMemberId()
函数进行的小改动 - “打开方式”支持
(您可以使用“打开方式”菜单,或将 cpa 文件拖放到程序图标上。) - 用于验证 CPA(CodeProject 文章)文件的唯一文件头
(因此,旧的 cpa 文件无法与此版本打开。)
- 2012 年 10 月 5 日(v1.0.1)
- CodeProject 的登录页上的“ctl00”变成了“ctl01”。因此,编写了一个新函数(
getElementId()
)来使用 Regex 类获取元素的 ID,并用此函数替换了所有可能在未来被 CodeProject 更改的旧常量。
- CodeProject 的登录页上的“ctl00”变成了“ctl01”。因此,编写了一个新函数(
- 2012 年 10 月 1 日(v1.0.0)
- 首次发布。