首页 > 代码库 > 【iOS开源代码】(2):CKEditor

【iOS开源代码】(2):CKEditor

CKEditor 是当前最为知名的 HTML 编辑器,它具有所有主流 HTML 编辑器所应当具备的特点:所见即所得、简单易用、开源并支持各种主流的浏览器(IE、Oper、FireFox、Chrome、Safari)。最重要的是,CKEditor 经过 10 年的不断完善和更新,其稳定性和兼容性已经不容质疑。

 

一、下载

CKEditor 最新版本当前为 4.3。进入 CKEditor 的下载页面(http://ckeditor.com/download),你会看到 4.3 版本又分为3个版本:基本版、标准版、完全版。

在这里我们仅使用标准版。选择标准版(Standard Package)进行下载。

下载后得到一个压缩文件ckeditor_4.3_basic.zip。

二、安装

将压缩文件解压缩到一个指定的文件夹,例如 ckeditor4.3 文件夹。然后将 ckeditor 文件夹整个地拖到你的项目中(选择“Copy Items...”和“Create folder”选项)。

这样,ckeditor4.3 目录会以“文件夹”而不是“group”的形式存在于项目中。

注意,文件夹是蓝色图标,而 group 是黄色图标。

现在可以在项目中使用 CKEditor 了。

三、使用 CKEditor

现在使用“New File...->iOS->Other->Empty”在项目中新建一个 test.html文件。注意它和 ckeditor4.3的相对位置:

编辑 test.html 如下:

<!DOCTYPE html>

<html>

    <head>

        <title>CKEditor Sample</title>

        <scriptsrc="ckeditor4.3/ckeditor.js"></script>

    </head>

    <body>

<textareaname="editor1">#{*CKEditorcontent text*}#</textarea>

<script>

       CKEDITOR.replace( ‘editor1‘ );

</script>

</body>

</html>

主要注意以下3个地方:

<scriptsrc="ckeditor4.3/ckeditor.js"></script>

这句脚本将导入 cheditor.js 脚本(即CKEditor引擎)。注意 src 属性并不以斜杠“/”开头,表明这是一个相对路径(相对于文件 test.html 本身)。如果 src 写错了,CKEditor 将无法启动。

<textareaname="editor1">#{*CKEditorcontent text*}#</textarea>

<textarea/>在这里其实只是起到了“占位符”的作用,我们给它一个名字 editor1,方便在脚本中调用这个控件,利用脚本将它替换成真正的 CKEditor 控件。#{*CKEditor content text*}# 也是占位符,以后我们可以通过这个特征字符串将其用某些内容替换,这样 CKEditor 控件会在文本框中显示指定的 HTML 内容。

CKEDITOR.replace(‘editor1‘ );

这句脚本将名为 editor1 的 <textarea/> 控件替换成 CKEditor 对象。

有了 test.html,我们需要在 ViewController 中加载它,以便使用 CKEditor。

在故事板编辑器中,在 ViewController 拖一个按钮和一个WebView。

打开 AssistantEditor,将 WebView 连接至 IBOutlet webView,将按钮的 TouchUpInside 事件连接至 IBAction send: 方法。

在 viewDidLoad 方法中,在 WebView 中加载 test.html 文件:

NSString*filePath = nil;

    filePath= [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];

   [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];

实现 send: 方法,通过 js 脚本获取当前 CKEditor 控件中的 HTML 内容:

- (IBAction)send:(id)sender {

    NSString*html=[self.webView stringByEvaluatingJavaScriptFromString:@"CKEDITOR.instances.editor1.getData()"];

    showMessage(html);

}

运行程序,如果一切正确,你将在 iPhone(请在设备上测试,不要在模拟器中测试)看到一个默认的 HTML 编辑器,编辑器中支持的所有工具栏按钮都显示出来了。编辑一些内容,点击按钮,将弹出一个消息框,显示正在编辑的 HTML 源码内容:


 

三、定制编辑器界面

1、定制工具栏

绝大部分情况下,你不需要显示全部的工具栏按钮,你可以在CKEDITOR.replace语句中定制自己的工具栏:

CKEDITOR.replace( ‘editor1‘,

    {

         removePlugins:‘elementspath‘,

              toolbar : [ [‘Source‘, ‘-‘, ‘FontSize‘, ‘-‘, ‘TextColor‘, ‘Bold‘, ‘Italic‘, ‘Underline‘],‘/‘,[‘Subscript‘,‘Superscript‘, ‘-‘,‘JustifyLeft‘,‘JustifyCenter‘,‘JustifyRight‘,‘JustifyBlock‘,‘Link‘, ‘Unlink‘ ]]

   });

其中,removePlugins: ‘elementspath‘ 将编辑器下边的元素标签工具移除。

toolbar: 中的内容则制定了我们将要使用的按钮。可以看到我们定义了许多标签,分为两个组(用“[]”分隔组,“-”为分隔条,“/”为换行),但由于标准版只实现了有限的功能,所以并不是所有标签都能被显示为工具栏按钮,比如 FontSize、TextColor、Subscript、Superscript、JustifyLeft、JustifyCenter、JustifyRight、JustifyBlock 都是 4.3 或者标准版中没有实现的,并不能在工具栏中显示。完整的按钮列表请在 ckeditor.js 中搜索“ui.addButton(”字样。


2、指定编辑器中的内容

由于我们使用了特征字符串,我们可以在 viewDidLoad 方法中将特征字符串替换为指定内容,以便显示在编辑器中:

NSMutableString *templateString = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding  error:nil];

   [templateString replaceOccurrencesOfString:@"#{*CKEditorcontent text*}#"

                                    withString:@"<h3>Hello</h3>"

                                       options: NSLiteralSearch range:NSMakeRange(0, [templateString length] - 1)];

    NSData*htmlData = http://www.mamicode.com/[templateString dataUsingEncoding: NSUTF8StringEncoding];

    if(htmlData){

        NSURL* baseURL =[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];

        [self.webView loadData:htmlDataMIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL];

   }

除此之外,我们也可以用脚本方式进行:

-(void)webViewDidFinishLoad:(UIWebView *)webView{

     [_webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(‘editor1‘).innerHTML=‘<em>Hello</em><i>World</i>!‘;"];

}

3、旋屏支持

在竖屏的情况下,CKEditor 的大小总是适应 iPhone 屏幕的。但当你旋转屏幕时,情况发生了改变,它显得略微太高了一些,屏幕似乎不能刚好显示下。

我们需要在横屏时修改它的尺寸:

-(BOOL)shouldAutorotateToInterfaceOrientation:

(UIInterfaceOrientation)toInterfaceOrientation{

    if(toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft ||

        toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {

        [self autosizeCKEditor];

    }

   

    return YES;

}

-(void)autosizeCKEditor{

    CGRect r=_webView.frame;

    NSString*script = [NSString stringWithFormat:@"CKEDITOR.instances.editor1.resize(\‘100%%\‘, \‘%.0f\‘ );",r.size.height];

    [self.webView stringByEvaluatingJavaScriptFromString:script];

}

这样当横屏时,它自动和 webView 的高度适配。

而 webView 的 autosizing 属性则被我修改为如下所示:


4、定制 inputAccessoryView

UIWebView 的 inputAccessoryView 上有两个按钮 previous 和 next。这两个按钮通常都不会有任何用处。这非常烦人,但我们可以去掉它。我们可以使用这篇博客中的技巧:

http://ios-blog.co.uk/tutorials/rich-text-editing-a-simple-start-part-1/

首先在 viewDidLoad 方法中监听键盘事件:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

实现 keyboardWillShow 方法:

UIWindow*keyboardWindow = nil;

    for (UIWindow*testWindow in [[UIApplication sharedApplication] windows]) {

         if(![[testWindow class] isEqual:[UIWindow class]]) {

            keyboardWindow = testWindow;

             break;

        }

     }

    for (UIView*possibleFormView in [keyboardWindow subviews]) {

if([[possibleFormView description] rangeOfString:@"UIPeripheralHostView"].location != NSNotFound) {

             for (UIView*subviewWhichIsPossibleFormView in [possibleFormView subviews]) {

               if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIWebFormAccessory"].location != NSNotFound) {

                   [subviewWhichIsPossibleFormView removeFromSuperview];

               }               

            }

         }

   }

这段代码中使用的仍然是无敌的“class dump”大法,首先找出键盘所在的UIWindow,然后再从中找出 WebView 的 Accessory 并删除它。

除此之外,我们也有简单一点的方法。在http://bjhomer.blogspot.com/2012/03/how-to-hide-inputaccessoryview-of.html这篇博客中,提供了一个 UIWebView 的新类别( HideInputAccessoryView),你可以用它来实现同样的目的。

在 webViewDidFinishLoad: 方法里,加入如下代码:

[self autosizeCKEditor];

   

   if (![self.htmlEditorView isHidesInputAccessoryView])

       

   {

       

       [self.htmlEditorViewhidesInputAccessoryView:YES];

       

   }

OK,这是运行的最终效果,键盘上方的 inputAccessoryView 已然被移除。

最后,我们列出所需的 UIWebView 类别完整定义:

/** UIWebView+AccessoryHiding.h **/

@interface UIWebView (HideInputAccessoryView)

 -(BOOL)isHidesInputAccessoryView;

 -(void)hidesInputAccessoryView:(BOOL)value;

@end

 

/** UIWebView+AccessoryHiding.m **/

#import"UIWebView+AccessoryHiding.h"

#import<objc/runtime.h>

 

@implementation UIWebView (HideInputAccessoryView)

 

static const char * consthackishFixClassName = "UIWebBrowserViewMinusAccessoryView";

static Class hackishFixClass = Nil;

 

- (UIView *) hackishlyFoundBrowserView {

    UIScrollView *scrollView = self.scrollView;

   

    UIView *browserView = nil;

    for (UIView*subview in scrollView.subviews) {

       if ([NSStringFromClass([subviewclass]) hasPrefix:@"UIWebBrowserView"]) {

           browserView = subview;

           break;

       }

   }

    return browserView;

}

 

- (id)methodReturningNil {

    return nil;

}

 

- (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {

    if (!hackishFixClass){

       id newClass = objc_allocateClassPair(browserViewClass,hackishFixClassName, 0);

       IMP nilImp = [selfmethodForSelector:@selector(methodReturningNil)];

       class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");

       objc_registerClassPair(newClass);

       

       hackishFixClass = newClass;

   }

}

 

- (BOOL) isHidesInputAccessoryView {

    UIView *browserView = [selfhackishlyFoundBrowserView];

    return [browserView class]== hackishFixClass;

}

 

- (void) hidesInputAccessoryView:(BOOL)value {

    UIView *browserView = [selfhackishlyFoundBrowserView];

    if (browserView == nil){

       return;

   }

   [self ensureHackishSubclassExistsOfBrowserViewClass:[browserViewclass]];

   

    if (value) {

       object_setClass(browserView, hackishFixClass);

   }

    else {

       Class normalClass = objc_getClass("UIWebBrowserView");

       object_setClass(browserView, normalClass);

   }

   [browserView reloadInputViews];

}

 

@end

 

注:目前 CKEditor 对 iOS 的支持仍然有一些问题,如果 ViewController 中存在其他可编辑控件(TextField、TextView 或 TITokenField ),则 CKEditor 将会出现异常,比如键盘不会弹出或者弹出后无法隐藏等等。




【iOS开源代码】(2):CKEditor