ZSSRichTextEditor.m 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073
  1. //
  2. // ZSSRichTextEditorViewController.m
  3. // ZSSRichTextEditor
  4. //
  5. // Created by Nicholas Hubbard on 11/30/13.
  6. // Copyright (c) 2013 Zed Said Studio. All rights reserved.
  7. //
  8. #import <objc/runtime.h>
  9. #import <UIKit/UIKit.h>
  10. #import "ZSSRichTextEditor.h"
  11. #import "ZSSBarButtonItem.h"
  12. #import "HRColorUtil.h"
  13. #import "ZSSTextView.h"
  14. @import JavaScriptCore;
  15. /**
  16. UIWebView modifications for hiding the inputAccessoryView
  17. **/
  18. @interface UIWebView (HackishAccessoryHiding)
  19. @property (nonatomic, assign) BOOL hidesInputAccessoryView;
  20. @end
  21. @implementation UIWebView (HackishAccessoryHiding)
  22. static const char * const hackishFixClassName = "UIWebBrowserViewMinusAccessoryView";
  23. static Class hackishFixClass = Nil;
  24. - (UIView *)hackishlyFoundBrowserView {
  25. UIScrollView *scrollView = self.scrollView;
  26. UIView *browserView = nil;
  27. for (UIView *subview in scrollView.subviews) {
  28. if ([NSStringFromClass([subview class]) hasPrefix:@"UIWebBrowserView"]) {
  29. browserView = subview;
  30. break;
  31. }
  32. }
  33. return browserView;
  34. }
  35. - (id)methodReturningNil {
  36. return nil;
  37. }
  38. - (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {
  39. if (!hackishFixClass) {
  40. Class newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
  41. newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
  42. IMP nilImp = [self methodForSelector:@selector(methodReturningNil)];
  43. class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");
  44. objc_registerClassPair(newClass);
  45. hackishFixClass = newClass;
  46. }
  47. }
  48. - (BOOL) hidesInputAccessoryView {
  49. UIView *browserView = [self hackishlyFoundBrowserView];
  50. return [browserView class] == hackishFixClass;
  51. }
  52. - (void) setHidesInputAccessoryView:(BOOL)value {
  53. UIView *browserView = [self hackishlyFoundBrowserView];
  54. if (browserView == nil) {
  55. return;
  56. }
  57. [self ensureHackishSubclassExistsOfBrowserViewClass:[browserView class]];
  58. if (value) {
  59. object_setClass(browserView, hackishFixClass);
  60. }
  61. else {
  62. Class normalClass = objc_getClass("UIWebBrowserView");
  63. object_setClass(browserView, normalClass);
  64. }
  65. [browserView reloadInputViews];
  66. }
  67. @end
  68. @interface ZSSRichTextEditor ()
  69. /*
  70. * Scroll view containing the toolbar
  71. */
  72. @property (nonatomic, strong) UIScrollView *toolBarScroll;
  73. /*
  74. * Toolbar containing ZSSBarButtonItems
  75. */
  76. @property (nonatomic, strong) UIToolbar *toolbar;
  77. /*
  78. * Holder for all of the toolbar components
  79. */
  80. @property (nonatomic, strong) UIView *toolbarHolder;
  81. /*
  82. * String for the HTML
  83. */
  84. @property (nonatomic, strong) NSString *htmlString;
  85. /*
  86. * UIWebView for writing/editing/displaying the content
  87. */
  88. @property (nonatomic, strong) UIWebView *editorView;
  89. /*
  90. * ZSSTextView for displaying the source code for what is displayed in the editor view
  91. */
  92. @property (nonatomic, strong) ZSSTextView *sourceView;
  93. /*
  94. * CGRect for holding the frame for the editor view
  95. */
  96. @property (nonatomic) CGRect editorViewFrame;
  97. /*
  98. * BOOL for holding if the resources are loaded or not
  99. */
  100. @property (nonatomic) BOOL resourcesLoaded;
  101. /*
  102. * Array holding the enabled editor items
  103. */
  104. @property (nonatomic, strong) NSArray *editorItemsEnabled;
  105. /*
  106. * Alert View used when inserting links/images
  107. */
  108. @property (nonatomic, strong) UIAlertView *alertView;
  109. /*
  110. * NSString holding the selected links URL value
  111. */
  112. @property (nonatomic, strong) NSString *selectedLinkURL;
  113. /*
  114. * NSString holding the selected links title value
  115. */
  116. @property (nonatomic, strong) NSString *selectedLinkTitle;
  117. /*
  118. * NSString holding the selected image URL value
  119. */
  120. @property (nonatomic, strong) NSString *selectedImageURL;
  121. /*
  122. * NSString holding the selected image Alt value
  123. */
  124. @property (nonatomic, strong) NSString *selectedImageAlt;
  125. /*
  126. * CGFloat holdign the selected image scale value
  127. */
  128. @property (nonatomic, assign) CGFloat selectedImageScale;
  129. /*
  130. * NSString holding the base64 value of the current image
  131. */
  132. @property (nonatomic, strong) NSString *imageBase64String;
  133. /*
  134. * Bar button item for the keyboard dismiss button in the toolbar
  135. */
  136. @property (nonatomic, strong) UIBarButtonItem *keyboardItem;
  137. /*
  138. * Array for custom bar button items
  139. */
  140. @property (nonatomic, strong) NSMutableArray *customBarButtonItems;
  141. /*
  142. * Array for custom ZSSBarButtonItems
  143. */
  144. @property (nonatomic, strong) NSMutableArray *customZSSBarButtonItems;
  145. /*
  146. * NSString holding the html
  147. */
  148. @property (nonatomic, strong) NSString *internalHTML;
  149. /*
  150. * NSString holding the css
  151. */
  152. @property (nonatomic, strong) NSString *customCSS;
  153. /*
  154. * BOOL for if the editor is loaded or not
  155. */
  156. @property (nonatomic) BOOL editorLoaded;
  157. /*
  158. * Image Picker for selecting photos from users photo library
  159. */
  160. @property (nonatomic, strong) UIImagePickerController *imagePicker;
  161. /*
  162. * Method for getting a version of the html without quotes
  163. */
  164. - (NSString *)removeQuotesFromHTML:(NSString *)html;
  165. /*
  166. * Method for getting a tidied version of the html
  167. */
  168. - (NSString *)tidyHTML:(NSString *)html;
  169. /*
  170. * Method for enablign toolbar items
  171. */
  172. - (void)enableToolbarItems:(BOOL)enable;
  173. /*
  174. * Setter for isIpad BOOL
  175. */
  176. - (BOOL)isIpad;
  177. @end
  178. /*
  179. ZSSRichTextEditor
  180. */
  181. @implementation ZSSRichTextEditor
  182. //Scale image from device
  183. static CGFloat kJPEGCompression = 0.8;
  184. static CGFloat kDefaultScale = 0.3;
  185. #pragma mark - View Did Load Section
  186. - (void)viewDidLoad {
  187. [super viewDidLoad];
  188. //Initialise variables
  189. self.editorLoaded = NO;
  190. self.receiveEditorDidChangeEvents = NO;
  191. self.alwaysShowToolbar = NO;
  192. self.shouldShowKeyboard = YES;
  193. self.formatHTML = YES;
  194. //Initalise enabled toolbar items array
  195. self.enabledToolbarItems = [[NSArray alloc] init];
  196. //Frame for the source view and editor view
  197. CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
  198. //Source View
  199. [self createSourceViewWithFrame:frame];
  200. //Editor View
  201. [self createEditorViewWithFrame:frame];
  202. //Image Picker used to allow the user insert images from the device (base64 encoded)
  203. [self setUpImagePicker];
  204. //Scrolling View
  205. [self createToolBarScroll];
  206. //Toolbar with icons
  207. [self createToolbar];
  208. //Parent holding view
  209. [self createParentHoldingView];
  210. //Hide Keyboard
  211. if (![self isIpad]) {
  212. // Toolbar holder used to crop and position toolbar
  213. UIView *toolbarCropper = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width-44, 0, 44, 44)];
  214. toolbarCropper.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
  215. toolbarCropper.clipsToBounds = YES;
  216. // Use a toolbar so that we can tint
  217. UIToolbar *keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(-7, -1, 44, 44)];
  218. [toolbarCropper addSubview:keyboardToolbar];
  219. self.keyboardItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSkeyboard.png"] style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)];
  220. keyboardToolbar.items = @[self.keyboardItem];
  221. [self.toolbarHolder addSubview:toolbarCropper];
  222. UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0.6f, 44)];
  223. line.backgroundColor = [UIColor lightGrayColor];
  224. line.alpha = 0.7f;
  225. [toolbarCropper addSubview:line];
  226. }
  227. [self.view addSubview:self.toolbarHolder];
  228. //Build the toolbar
  229. [self buildToolbar];
  230. //Load Resources
  231. if (!self.resourcesLoaded) {
  232. [self loadResources];
  233. }
  234. }
  235. #pragma mark - View Will Appear Section
  236. - (void)viewWillAppear:(BOOL)animated {
  237. [super viewWillAppear:animated];
  238. //Add observers for keyboard showing or hiding notifications
  239. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowOrHide:) name:UIKeyboardWillShowNotification object:nil];
  240. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowOrHide:) name:UIKeyboardWillHideNotification object:nil];
  241. }
  242. #pragma mark - View Will Disappear Section
  243. - (void)viewWillDisappear:(BOOL)animated {
  244. [super viewWillDisappear:animated];
  245. //Remove observers for keyboard showing or hiding notifications
  246. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
  247. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
  248. }
  249. #pragma mark - Set Up View Section
  250. - (void)createSourceViewWithFrame:(CGRect)frame {
  251. self.sourceView = [[ZSSTextView alloc] initWithFrame:frame];
  252. self.sourceView.hidden = YES;
  253. self.sourceView.autocapitalizationType = UITextAutocapitalizationTypeNone;
  254. self.sourceView.autocorrectionType = UITextAutocorrectionTypeNo;
  255. self.sourceView.font = [UIFont fontWithName:@"Courier" size:13.0];
  256. self.sourceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  257. self.sourceView.autoresizesSubviews = YES;
  258. self.sourceView.delegate = self;
  259. [self.view addSubview:self.sourceView];
  260. }
  261. - (void)createEditorViewWithFrame:(CGRect)frame {
  262. self.editorView = [[UIWebView alloc] initWithFrame:frame];
  263. self.editorView.delegate = self;
  264. self.editorView.hidesInputAccessoryView = YES;
  265. self.editorView.keyboardDisplayRequiresUserAction = NO;
  266. self.editorView.scalesPageToFit = YES;
  267. self.editorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
  268. self.editorView.dataDetectorTypes = UIDataDetectorTypeNone;
  269. self.editorView.scrollView.bounces = NO;
  270. self.editorView.backgroundColor = [UIColor whiteColor];
  271. [self.view addSubview:self.editorView];
  272. }
  273. - (void)setUpImagePicker {
  274. self.imagePicker = [[UIImagePickerController alloc] init];
  275. self.imagePicker.delegate = self;
  276. self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  277. self.imagePicker.allowsEditing = YES;
  278. self.selectedImageScale = kDefaultScale; //by default scale to half the size
  279. }
  280. - (void)createToolBarScroll {
  281. self.toolBarScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, [self isIpad] ? self.view.frame.size.width : self.view.frame.size.width - 44, 44)];
  282. self.toolBarScroll.backgroundColor = [UIColor clearColor];
  283. self.toolBarScroll.showsHorizontalScrollIndicator = NO;
  284. }
  285. - (void)createToolbar {
  286. self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
  287. self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  288. self.toolbar.backgroundColor = [UIColor clearColor];
  289. [self.toolBarScroll addSubview:self.toolbar];
  290. self.toolBarScroll.autoresizingMask = self.toolbar.autoresizingMask;
  291. }
  292. - (void)createParentHoldingView {
  293. //Background Toolbar
  294. UIToolbar *backgroundToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
  295. backgroundToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  296. //Parent holding view
  297. self.toolbarHolder = [[UIView alloc] init];
  298. if (_alwaysShowToolbar) {
  299. self.toolbarHolder.frame = CGRectMake(0, self.view.frame.size.height - 44, self.view.frame.size.width, 44);
  300. } else {
  301. self.toolbarHolder.frame = CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, 44);
  302. }
  303. self.toolbarHolder.autoresizingMask = self.toolbar.autoresizingMask;
  304. [self.toolbarHolder addSubview:self.toolBarScroll];
  305. [self.toolbarHolder insertSubview:backgroundToolbar atIndex:0];
  306. }
  307. #pragma mark - Resources Section
  308. - (void)loadResources {
  309. //Create a string with the contents of editor.html
  310. NSString *filePath = [[NSBundle mainBundle] pathForResource:@"editor" ofType:@"html"];
  311. NSData *htmlData = [NSData dataWithContentsOfFile:filePath];
  312. NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
  313. //Add jQuery.js to the html file
  314. NSString *jquery = [[NSBundle mainBundle] pathForResource:@"jQuery" ofType:@"js"];
  315. NSString *jqueryString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:jquery] encoding:NSUTF8StringEncoding];
  316. htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!-- jQuery -->" withString:jqueryString];
  317. //Add JSBeautifier.js to the html file
  318. NSString *beautifier = [[NSBundle mainBundle] pathForResource:@"JSBeautifier" ofType:@"js"];
  319. NSString *beautifierString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:beautifier] encoding:NSUTF8StringEncoding];
  320. htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!-- jsbeautifier -->" withString:beautifierString];
  321. //Add ZSSRichTextEditor.js to the html file
  322. NSString *source = [[NSBundle mainBundle] pathForResource:@"ZSSRichTextEditor" ofType:@"js"];
  323. NSString *jsString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:source] encoding:NSUTF8StringEncoding];
  324. htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!--editor-->" withString:jsString];
  325. [self.editorView loadHTMLString:htmlString baseURL:self.baseURL];
  326. self.resourcesLoaded = YES;
  327. }
  328. #pragma mark - Toolbar Section
  329. - (void)setEnabledToolbarItems:(NSArray *)enabledToolbarItems {
  330. _enabledToolbarItems = enabledToolbarItems;
  331. [self buildToolbar];
  332. }
  333. - (void)setToolbarItemTintColor:(UIColor *)toolbarItemTintColor {
  334. _toolbarItemTintColor = toolbarItemTintColor;
  335. // Update the color
  336. for (ZSSBarButtonItem *item in self.toolbar.items) {
  337. item.tintColor = [self barButtonItemDefaultColor];
  338. }
  339. self.keyboardItem.tintColor = toolbarItemTintColor;
  340. }
  341. - (void)setToolbarItemSelectedTintColor:(UIColor *)toolbarItemSelectedTintColor {
  342. _toolbarItemSelectedTintColor = toolbarItemSelectedTintColor;
  343. }
  344. - (NSArray *)itemsForToolbar {
  345. NSMutableArray *items = [[NSMutableArray alloc] init];
  346. // None
  347. if(_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarNone])
  348. {
  349. return items;
  350. }
  351. BOOL customOrder = NO;
  352. if (_enabledToolbarItems && ![_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll]){
  353. customOrder = YES;
  354. for(int i=0; i < _enabledToolbarItems.count;i++){
  355. [items addObject:@""];
  356. }
  357. }
  358. // Bold
  359. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarBold]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  360. ZSSBarButtonItem *bold = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSbold.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setBold)];
  361. bold.label = @"bold";
  362. if (customOrder) {
  363. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarBold] withObject:bold];
  364. } else {
  365. [items addObject:bold];
  366. }
  367. }
  368. // Italic
  369. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarItalic]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  370. ZSSBarButtonItem *italic = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSitalic.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setItalic)];
  371. italic.label = @"italic";
  372. if (customOrder) {
  373. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarItalic] withObject:italic];
  374. } else {
  375. [items addObject:italic];
  376. }
  377. }
  378. // Subscript
  379. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarSubscript]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  380. ZSSBarButtonItem *subscript = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSsubscript.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setSubscript)];
  381. subscript.label = @"subscript";
  382. if (customOrder) {
  383. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarSubscript] withObject:subscript];
  384. } else {
  385. [items addObject:subscript];
  386. }
  387. }
  388. // Superscript
  389. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarSuperscript]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  390. ZSSBarButtonItem *superscript = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSsuperscript.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setSuperscript)];
  391. superscript.label = @"superscript";
  392. if (customOrder) {
  393. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarSuperscript] withObject:superscript];
  394. } else {
  395. [items addObject:superscript];
  396. }
  397. }
  398. // Strike Through
  399. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarStrikeThrough]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  400. ZSSBarButtonItem *strikeThrough = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSstrikethrough.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setStrikethrough)];
  401. strikeThrough.label = @"strikeThrough";
  402. if (customOrder) {
  403. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarStrikeThrough] withObject:strikeThrough];
  404. } else {
  405. [items addObject:strikeThrough];
  406. }
  407. }
  408. // Underline
  409. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUnderline]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  410. ZSSBarButtonItem *underline = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunderline.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setUnderline)];
  411. underline.label = @"underline";
  412. if (customOrder) {
  413. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUnderline] withObject:underline];
  414. } else {
  415. [items addObject:underline];
  416. }
  417. }
  418. // Remove Format
  419. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRemoveFormat]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  420. ZSSBarButtonItem *removeFormat = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSclearstyle.png"] style:UIBarButtonItemStylePlain target:self action:@selector(removeFormat)];
  421. removeFormat.label = @"removeFormat";
  422. if (customOrder) {
  423. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRemoveFormat] withObject:removeFormat];
  424. } else {
  425. [items addObject:removeFormat];
  426. }
  427. }
  428. // Fonts
  429. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarFonts]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  430. ZSSBarButtonItem *fonts = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSfonts.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showFontsPicker)];
  431. fonts.label = @"fonts";
  432. if (customOrder) {
  433. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarFonts] withObject:fonts];
  434. } else {
  435. [items addObject:fonts];
  436. }
  437. }
  438. // Undo
  439. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUndo]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  440. ZSSBarButtonItem *undoButton = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSundo.png"] style:UIBarButtonItemStylePlain target:self action:@selector(undo:)];
  441. undoButton.label = @"undo";
  442. if (customOrder) {
  443. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUndo] withObject:undoButton];
  444. } else {
  445. [items addObject:undoButton];
  446. }
  447. }
  448. // Redo
  449. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRedo]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  450. ZSSBarButtonItem *redoButton = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSredo.png"] style:UIBarButtonItemStylePlain target:self action:@selector(redo:)];
  451. redoButton.label = @"redo";
  452. if (customOrder) {
  453. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRedo] withObject:redoButton];
  454. } else {
  455. [items addObject:redoButton];
  456. }
  457. }
  458. // Align Left
  459. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyLeft]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  460. ZSSBarButtonItem *alignLeft = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSleftjustify.png"] style:UIBarButtonItemStylePlain target:self action:@selector(alignLeft)];
  461. alignLeft.label = @"justifyLeft";
  462. if (customOrder) {
  463. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyLeft] withObject:alignLeft];
  464. } else {
  465. [items addObject:alignLeft];
  466. }
  467. }
  468. // Align Center
  469. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyCenter]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  470. ZSSBarButtonItem *alignCenter = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSScenterjustify.png"] style:UIBarButtonItemStylePlain target:self action:@selector(alignCenter)];
  471. alignCenter.label = @"justifyCenter";
  472. if (customOrder) {
  473. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyCenter] withObject:alignCenter];
  474. } else {
  475. [items addObject:alignCenter];
  476. }
  477. }
  478. // Align Right
  479. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyRight]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  480. ZSSBarButtonItem *alignRight = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSrightjustify.png"] style:UIBarButtonItemStylePlain target:self action:@selector(alignRight)];
  481. alignRight.label = @"justifyRight";
  482. if (customOrder) {
  483. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyRight] withObject:alignRight];
  484. } else {
  485. [items addObject:alignRight];
  486. }
  487. }
  488. // Align Justify
  489. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyFull]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  490. ZSSBarButtonItem *alignFull = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSforcejustify.png"] style:UIBarButtonItemStylePlain target:self action:@selector(alignFull)];
  491. alignFull.label = @"justifyFull";
  492. if (customOrder) {
  493. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyFull] withObject:alignFull];
  494. } else {
  495. [items addObject:alignFull];
  496. }
  497. }
  498. // Paragraph
  499. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarParagraph]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  500. ZSSBarButtonItem *paragraph = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSparagraph.png"] style:UIBarButtonItemStylePlain target:self action:@selector(paragraph)];
  501. paragraph.label = @"p";
  502. if (customOrder) {
  503. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarParagraph] withObject:paragraph];
  504. } else {
  505. [items addObject:paragraph];
  506. }
  507. }
  508. // Header 1
  509. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH1]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  510. ZSSBarButtonItem *h1 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh1.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading1)];
  511. h1.label = @"h1";
  512. if (customOrder) {
  513. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH1] withObject:h1];
  514. } else {
  515. [items addObject:h1];
  516. }
  517. }
  518. // Header 2
  519. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH2]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  520. ZSSBarButtonItem *h2 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh2.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading2)];
  521. h2.label = @"h2";
  522. if (customOrder) {
  523. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH2] withObject:h2];
  524. } else {
  525. [items addObject:h2];
  526. }
  527. }
  528. // Header 3
  529. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH3]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  530. ZSSBarButtonItem *h3 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh3.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading3)];
  531. h3.label = @"h3";
  532. if (customOrder) {
  533. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH3] withObject:h3];
  534. } else {
  535. [items addObject:h3];
  536. }
  537. }
  538. // Heading 4
  539. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH4]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  540. ZSSBarButtonItem *h4 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh4.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading4)];
  541. h4.label = @"h4";
  542. if (customOrder) {
  543. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH4] withObject:h4];
  544. } else {
  545. [items addObject:h4];
  546. }
  547. }
  548. // Header 5
  549. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH5]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  550. ZSSBarButtonItem *h5 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh5.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading5)];
  551. h5.label = @"h5";
  552. if (customOrder) {
  553. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH5] withObject:h5];
  554. } else {
  555. [items addObject:h5];
  556. }
  557. }
  558. // Heading 6
  559. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH6]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  560. ZSSBarButtonItem *h6 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh6.png"] style:UIBarButtonItemStylePlain target:self action:@selector(heading6)];
  561. h6.label = @"h6";
  562. if (customOrder) {
  563. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH6] withObject:h6];
  564. } else {
  565. [items addObject:h6];
  566. }
  567. }
  568. // Text Color
  569. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarTextColor]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  570. ZSSBarButtonItem *textColor = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSStextcolor.png"] style:UIBarButtonItemStylePlain target:self action:@selector(textColor)];
  571. textColor.label = @"textColor";
  572. if (customOrder) {
  573. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarTextColor] withObject:textColor];
  574. } else {
  575. [items addObject:textColor];
  576. }
  577. }
  578. // Background Color
  579. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarBackgroundColor]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  580. ZSSBarButtonItem *bgColor = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSbgcolor.png"] style:UIBarButtonItemStylePlain target:self action:@selector(bgColor)];
  581. bgColor.label = @"backgroundColor";
  582. if (customOrder) {
  583. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarBackgroundColor] withObject:bgColor];
  584. } else {
  585. [items addObject:bgColor];
  586. }
  587. }
  588. // Unordered List
  589. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUnorderedList]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  590. ZSSBarButtonItem *ul = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunorderedlist.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setUnorderedList)];
  591. ul.label = @"unorderedList";
  592. if (customOrder) {
  593. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUnorderedList] withObject:ul];
  594. } else {
  595. [items addObject:ul];
  596. }
  597. }
  598. // Ordered List
  599. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarOrderedList]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  600. ZSSBarButtonItem *ol = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSorderedlist.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setOrderedList)];
  601. ol.label = @"orderedList";
  602. if (customOrder) {
  603. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarOrderedList] withObject:ol];
  604. } else {
  605. [items addObject:ol];
  606. }
  607. }
  608. // Horizontal Rule
  609. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarHorizontalRule]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  610. ZSSBarButtonItem *hr = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSShorizontalrule.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setHR)];
  611. hr.label = @"horizontalRule";
  612. if (customOrder) {
  613. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarHorizontalRule] withObject:hr];
  614. } else {
  615. [items addObject:hr];
  616. }
  617. }
  618. // Indent
  619. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarIndent]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  620. ZSSBarButtonItem *indent = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSindent.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setIndent)];
  621. indent.label = @"indent";
  622. if (customOrder) {
  623. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarIndent] withObject:indent];
  624. } else {
  625. [items addObject:indent];
  626. }
  627. }
  628. // Outdent
  629. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarOutdent]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  630. ZSSBarButtonItem *outdent = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSoutdent.png"] style:UIBarButtonItemStylePlain target:self action:@selector(setOutdent)];
  631. outdent.label = @"outdent";
  632. if (customOrder) {
  633. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarOutdent] withObject:outdent];
  634. } else {
  635. [items addObject:outdent];
  636. }
  637. }
  638. // Image
  639. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertImage]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  640. ZSSBarButtonItem *insertImage = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSimage.png"] style:UIBarButtonItemStylePlain target:self action:@selector(insertImage)];
  641. insertImage.label = @"image";
  642. if (customOrder) {
  643. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertImage] withObject:insertImage];
  644. } else {
  645. [items addObject:insertImage];
  646. }
  647. }
  648. // Image From Device
  649. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertImageFromDevice]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  650. ZSSBarButtonItem *insertImageFromDevice = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSimageDevice.png"] style:UIBarButtonItemStylePlain target:self action:@selector(insertImageFromDevice)];
  651. insertImageFromDevice.label = @"imageFromDevice";
  652. if (customOrder) {
  653. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertImageFromDevice] withObject:insertImageFromDevice];
  654. } else {
  655. [items addObject:insertImageFromDevice];
  656. }
  657. }
  658. // Insert Link
  659. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  660. ZSSBarButtonItem *insertLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSlink.png"] style:UIBarButtonItemStylePlain target:self action:@selector(insertLink)];
  661. insertLink.label = @"link";
  662. if (customOrder) {
  663. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertLink] withObject:insertLink];
  664. } else {
  665. [items addObject:insertLink];
  666. }
  667. }
  668. // Remove Link
  669. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRemoveLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  670. ZSSBarButtonItem *removeLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunlink.png"] style:UIBarButtonItemStylePlain target:self action:@selector(removeLink)];
  671. removeLink.label = @"removeLink";
  672. if (customOrder) {
  673. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRemoveLink] withObject:removeLink];
  674. } else {
  675. [items addObject:removeLink];
  676. }
  677. }
  678. // Quick Link
  679. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarQuickLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  680. ZSSBarButtonItem *quickLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSquicklink.png"] style:UIBarButtonItemStylePlain target:self action:@selector(quickLink)];
  681. quickLink.label = @"quickLink";
  682. if (customOrder) {
  683. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarQuickLink] withObject:quickLink];
  684. } else {
  685. [items addObject:quickLink];
  686. }
  687. }
  688. // Show Source
  689. if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarViewSource]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
  690. ZSSBarButtonItem *showSource = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSviewsource.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showHTMLSource:)];
  691. showSource.label = @"source";
  692. if (customOrder) {
  693. [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarViewSource] withObject:showSource];
  694. } else {
  695. [items addObject:showSource];
  696. }
  697. }
  698. return [NSArray arrayWithArray:items];
  699. }
  700. - (void)buildToolbar {
  701. // Check to see if we have any toolbar items, if not, add them all
  702. NSArray *items = [self itemsForToolbar];
  703. if (items.count == 0 && !(_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarNone])) {
  704. _enabledToolbarItems = @[ZSSRichTextEditorToolbarAll];
  705. items = [self itemsForToolbar];
  706. }
  707. if (self.customZSSBarButtonItems != nil) {
  708. items = [items arrayByAddingObjectsFromArray:self.customZSSBarButtonItems];
  709. }
  710. // get the width before we add custom buttons
  711. CGFloat toolbarWidth = items.count == 0 ? 0.0f : (CGFloat)(items.count * 39) - 10;
  712. if(self.customBarButtonItems != nil)
  713. {
  714. items = [items arrayByAddingObjectsFromArray:self.customBarButtonItems];
  715. for(ZSSBarButtonItem *buttonItem in self.customBarButtonItems)
  716. {
  717. toolbarWidth += buttonItem.customView.frame.size.width + 11.0f;
  718. }
  719. }
  720. self.toolbar.items = items;
  721. for (ZSSBarButtonItem *item in items) {
  722. item.tintColor = [self barButtonItemDefaultColor];
  723. }
  724. self.toolbar.frame = CGRectMake(0, 0, toolbarWidth, 44);
  725. self.toolBarScroll.contentSize = CGSizeMake(self.toolbar.frame.size.width, 44);
  726. }
  727. #pragma mark - Editor Modification Section
  728. - (void)setCSS:(NSString *)css {
  729. self.customCSS = css;
  730. if (self.editorLoaded) {
  731. [self updateCSS];
  732. }
  733. }
  734. - (void)updateCSS {
  735. if (self.customCSS != NULL && [self.customCSS length] != 0) {
  736. NSString *js = [NSString stringWithFormat:@"zss_editor.setCustomCSS(\"%@\");", self.customCSS];
  737. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  738. }
  739. }
  740. - (void)setPlaceholderText {
  741. //Call the setPlaceholder javascript method if a placeholder has been set
  742. if (self.placeholder != NULL && [self.placeholder length] != 0) {
  743. NSString *js = [NSString stringWithFormat:@"zss_editor.setPlaceholder(\"%@\");", self.placeholder];
  744. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  745. }
  746. }
  747. - (void)setFooterHeight:(float)footerHeight {
  748. //Call the setFooterHeight javascript method
  749. NSString *js = [NSString stringWithFormat:@"zss_editor.setFooterHeight(\"%f\");", footerHeight];
  750. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  751. }
  752. - (void)setContentHeight:(float)contentHeight {
  753. //Call the contentHeight javascript method
  754. NSString *js = [NSString stringWithFormat:@"zss_editor.contentHeight = %f;", contentHeight];
  755. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  756. }
  757. #pragma mark - Editor Interaction
  758. - (void)focusTextEditor {
  759. self.editorView.keyboardDisplayRequiresUserAction = NO;
  760. NSString *js = [NSString stringWithFormat:@"zss_editor.focusEditor();"];
  761. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  762. }
  763. - (void)blurTextEditor {
  764. NSString *js = [NSString stringWithFormat:@"zss_editor.blurEditor();"];
  765. [self.editorView stringByEvaluatingJavaScriptFromString:js];
  766. }
  767. - (void)setHTML:(NSString *)html {
  768. self.internalHTML = html;
  769. if (self.editorLoaded) {
  770. [self updateHTML];
  771. }
  772. }
  773. - (void)updateHTML {
  774. NSString *html = self.internalHTML;
  775. self.sourceView.text = html;
  776. NSString *cleanedHTML = [self removeQuotesFromHTML:self.sourceView.text];
  777. NSString *trigger = [NSString stringWithFormat:@"zss_editor.setHTML(\"%@\");", cleanedHTML];
  778. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  779. }
  780. - (NSString *)getHTML {
  781. NSString *html = [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.getHTML();"];
  782. html = [self removeQuotesFromHTML:html];
  783. html = [self tidyHTML:html];
  784. return html;
  785. }
  786. - (void)insertHTML:(NSString *)html {
  787. NSString *cleanedHTML = [self removeQuotesFromHTML:html];
  788. NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertHTML(\"%@\");", cleanedHTML];
  789. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  790. }
  791. - (NSString *)getText {
  792. return [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.getText();"];
  793. }
  794. - (void)dismissKeyboard {
  795. [self.view endEditing:YES];
  796. }
  797. - (void)showHTMLSource:(ZSSBarButtonItem *)barButtonItem {
  798. if (self.sourceView.hidden) {
  799. self.sourceView.text = [self getHTML];
  800. self.sourceView.hidden = NO;
  801. barButtonItem.tintColor = [UIColor blackColor];
  802. self.editorView.hidden = YES;
  803. [self enableToolbarItems:NO];
  804. } else {
  805. [self setHTML:self.sourceView.text];
  806. barButtonItem.tintColor = [self barButtonItemDefaultColor];
  807. self.sourceView.hidden = YES;
  808. self.editorView.hidden = NO;
  809. [self enableToolbarItems:YES];
  810. }
  811. }
  812. - (void)removeFormat {
  813. NSString *trigger = @"zss_editor.removeFormating();";
  814. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  815. }
  816. - (void)alignLeft {
  817. NSString *trigger = @"zss_editor.setJustifyLeft();";
  818. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  819. }
  820. - (void)alignCenter {
  821. NSString *trigger = @"zss_editor.setJustifyCenter();";
  822. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  823. }
  824. - (void)alignRight {
  825. NSString *trigger = @"zss_editor.setJustifyRight();";
  826. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  827. }
  828. - (void)alignFull {
  829. NSString *trigger = @"zss_editor.setJustifyFull();";
  830. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  831. }
  832. - (void)setBold {
  833. NSString *trigger = @"zss_editor.setBold();";
  834. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  835. }
  836. - (void)setItalic {
  837. NSString *trigger = @"zss_editor.setItalic();";
  838. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  839. }
  840. - (void)setSubscript {
  841. NSString *trigger = @"zss_editor.setSubscript();";
  842. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  843. }
  844. - (void)setUnderline {
  845. NSString *trigger = @"zss_editor.setUnderline();";
  846. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  847. }
  848. - (void)setSuperscript {
  849. NSString *trigger = @"zss_editor.setSuperscript();";
  850. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  851. }
  852. - (void)setStrikethrough {
  853. NSString *trigger = @"zss_editor.setStrikeThrough();";
  854. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  855. }
  856. - (void)setUnorderedList {
  857. NSString *trigger = @"zss_editor.setUnorderedList();";
  858. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  859. }
  860. - (void)setOrderedList {
  861. NSString *trigger = @"zss_editor.setOrderedList();";
  862. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  863. }
  864. - (void)setHR {
  865. NSString *trigger = @"zss_editor.setHorizontalRule();";
  866. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  867. }
  868. - (void)setIndent {
  869. NSString *trigger = @"zss_editor.setIndent();";
  870. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  871. }
  872. - (void)setOutdent {
  873. NSString *trigger = @"zss_editor.setOutdent();";
  874. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  875. }
  876. - (void)heading1 {
  877. NSString *trigger = @"zss_editor.setHeading('h1');";
  878. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  879. }
  880. - (void)heading2 {
  881. NSString *trigger = @"zss_editor.setHeading('h2');";
  882. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  883. }
  884. - (void)heading3 {
  885. NSString *trigger = @"zss_editor.setHeading('h3');";
  886. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  887. }
  888. - (void)heading4 {
  889. NSString *trigger = @"zss_editor.setHeading('h4');";
  890. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  891. }
  892. - (void)heading5 {
  893. NSString *trigger = @"zss_editor.setHeading('h5');";
  894. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  895. }
  896. - (void)heading6 {
  897. NSString *trigger = @"zss_editor.setHeading('h6');";
  898. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  899. }
  900. - (void)paragraph {
  901. NSString *trigger = @"zss_editor.setParagraph();";
  902. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  903. }
  904. - (void)showFontsPicker {
  905. // Save the selection location
  906. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  907. //Call picker
  908. ZSSFontsViewController *fontPicker = [ZSSFontsViewController cancelableFontPickerViewControllerWithFontFamily:ZSSFontFamilyDefault];
  909. fontPicker.delegate = self;
  910. [self.navigationController pushViewController:fontPicker animated:YES];
  911. }
  912. - (void)setSelectedFontFamily:(ZSSFontFamily)fontFamily {
  913. NSString *fontFamilyString;
  914. switch (fontFamily) {
  915. case ZSSFontFamilyDefault:
  916. fontFamilyString = @"Arial, Helvetica, sans-serif";
  917. break;
  918. case ZSSFontFamilyGeorgia:
  919. fontFamilyString = @"Georgia, serif";
  920. break;
  921. case ZSSFontFamilyPalatino:
  922. fontFamilyString = @"Palatino Linotype, Book Antiqua, Palatino, serif";
  923. break;
  924. case ZSSFontFamilyTimesNew:
  925. fontFamilyString = @"Times New Roman, Times, serif";
  926. break;
  927. case ZSSFontFamilyTrebuchet:
  928. fontFamilyString = @"Trebuchet MS, Helvetica, sans-serif";
  929. break;
  930. case ZSSFontFamilyVerdana:
  931. fontFamilyString = @"Verdana, Geneva, sans-serif";
  932. break;
  933. case ZSSFontFamilyCourierNew:
  934. fontFamilyString = @"Courier New, Courier, monospace";
  935. break;
  936. default:
  937. fontFamilyString = @"Arial, Helvetica, sans-serif";
  938. break;
  939. }
  940. NSString *trigger = [NSString stringWithFormat:@"zss_editor.setFontFamily(\"%@\");", fontFamilyString];
  941. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  942. }
  943. - (void)textColor {
  944. // Save the selection location
  945. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  946. // Call the picker
  947. HRColorPickerViewController *colorPicker = [HRColorPickerViewController cancelableFullColorPickerViewControllerWithColor:[UIColor whiteColor]];
  948. colorPicker.delegate = self;
  949. colorPicker.tag = 1;
  950. colorPicker.title = NSLocalizedString(@"Text Color", nil);
  951. [self.navigationController pushViewController:colorPicker animated:YES];
  952. }
  953. - (void)bgColor {
  954. // Save the selection location
  955. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  956. // Call the picker
  957. HRColorPickerViewController *colorPicker = [HRColorPickerViewController cancelableFullColorPickerViewControllerWithColor:[UIColor whiteColor]];
  958. colorPicker.delegate = self;
  959. colorPicker.tag = 2;
  960. colorPicker.title = NSLocalizedString(@"BG Color", nil);
  961. [self.navigationController pushViewController:colorPicker animated:YES];
  962. }
  963. - (void)setSelectedColor:(UIColor*)color tag:(int)tag {
  964. NSString *hex = [NSString stringWithFormat:@"#%06x",HexColorFromUIColor(color)];
  965. NSString *trigger;
  966. if (tag == 1) {
  967. trigger = [NSString stringWithFormat:@"zss_editor.setTextColor(\"%@\");", hex];
  968. } else if (tag == 2) {
  969. trigger = [NSString stringWithFormat:@"zss_editor.setBackgroundColor(\"%@\");", hex];
  970. }
  971. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  972. }
  973. - (void)undo:(ZSSBarButtonItem *)barButtonItem {
  974. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.undo();"];
  975. }
  976. - (void)redo:(ZSSBarButtonItem *)barButtonItem {
  977. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.redo();"];
  978. }
  979. - (void)insertLink {
  980. // Save the selection location
  981. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  982. // Show the dialog for inserting or editing a link
  983. [self showInsertLinkDialogWithLink:self.selectedLinkURL title:self.selectedLinkTitle];
  984. }
  985. - (void)showInsertLinkDialogWithLink:(NSString *)url title:(NSString *)title {
  986. // Insert Button Title
  987. NSString *insertButtonTitle = !self.selectedLinkURL ? NSLocalizedString(@"Insert", nil) : NSLocalizedString(@"Update", nil);
  988. // Picker Button
  989. UIButton *am = [UIButton buttonWithType:UIButtonTypeCustom];
  990. am.frame = CGRectMake(0, 0, 25, 25);
  991. [am setImage:[UIImage imageNamed:@"ZSSpicker.png"] forState:UIControlStateNormal];
  992. [am addTarget:self action:@selector(showInsertURLAlternatePicker) forControlEvents:UIControlEventTouchUpInside];
  993. if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
  994. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Link", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
  995. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  996. textField.placeholder = NSLocalizedString(@"URL (required)", nil);
  997. if (url) {
  998. textField.text = url;
  999. }
  1000. textField.rightView = am;
  1001. textField.rightViewMode = UITextFieldViewModeAlways;
  1002. textField.clearButtonMode = UITextFieldViewModeAlways;
  1003. }];
  1004. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  1005. textField.placeholder = NSLocalizedString(@"Title", nil);
  1006. textField.clearButtonMode = UITextFieldViewModeAlways;
  1007. textField.secureTextEntry = NO;
  1008. if (title) {
  1009. textField.text = title;
  1010. }
  1011. }];
  1012. [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  1013. [self focusTextEditor];
  1014. }]];
  1015. [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  1016. UITextField *linkURL = [alertController.textFields objectAtIndex:0];
  1017. UITextField *title = [alertController.textFields objectAtIndex:1];
  1018. if (!self.selectedLinkURL) {
  1019. [self insertLink:linkURL.text title:title.text];
  1020. //NSLog(@"insert link");
  1021. } else {
  1022. [self updateLink:linkURL.text title:title.text];
  1023. }
  1024. [self focusTextEditor];
  1025. }]];
  1026. [self presentViewController:alertController animated:YES completion:NULL];
  1027. } else {
  1028. self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Link", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
  1029. self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
  1030. self.alertView.tag = 2;
  1031. UITextField *linkURL = [self.alertView textFieldAtIndex:0];
  1032. linkURL.placeholder = NSLocalizedString(@"URL (required)", nil);
  1033. if (url) {
  1034. linkURL.text = url;
  1035. }
  1036. linkURL.rightView = am;
  1037. linkURL.rightViewMode = UITextFieldViewModeAlways;
  1038. UITextField *alt = [self.alertView textFieldAtIndex:1];
  1039. alt.secureTextEntry = NO;
  1040. alt.placeholder = NSLocalizedString(@"Title", nil);
  1041. if (title) {
  1042. alt.text = title;
  1043. }
  1044. [self.alertView show];
  1045. }
  1046. }
  1047. - (void)insertLink:(NSString *)url title:(NSString *)title {
  1048. NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertLink(\"%@\", \"%@\");", url, title];
  1049. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1050. }
  1051. - (void)updateLink:(NSString *)url title:(NSString *)title {
  1052. NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateLink(\"%@\", \"%@\");", url, title];
  1053. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1054. }
  1055. - (void)dismissAlertView {
  1056. [self.alertView dismissWithClickedButtonIndex:self.alertView.cancelButtonIndex animated:YES];
  1057. }
  1058. - (void)addCustomToolbarItemWithButton:(UIButton *)button {
  1059. if(self.customBarButtonItems == nil)
  1060. {
  1061. self.customBarButtonItems = [NSMutableArray array];
  1062. }
  1063. button.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:28.5f];
  1064. [button setTitleColor:[self barButtonItemDefaultColor] forState:UIControlStateNormal];
  1065. [button setTitleColor:[self barButtonItemSelectedDefaultColor] forState:UIControlStateHighlighted];
  1066. ZSSBarButtonItem *barButtonItem = [[ZSSBarButtonItem alloc] initWithCustomView:button];
  1067. [self.customBarButtonItems addObject:barButtonItem];
  1068. [self buildToolbar];
  1069. }
  1070. - (void)addCustomToolbarItem:(ZSSBarButtonItem *)item {
  1071. if(self.customZSSBarButtonItems == nil)
  1072. {
  1073. self.customZSSBarButtonItems = [NSMutableArray array];
  1074. }
  1075. [self.customZSSBarButtonItems addObject:item];
  1076. [self buildToolbar];
  1077. }
  1078. - (void)removeLink {
  1079. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.unlink();"];
  1080. }
  1081. - (void)quickLink {
  1082. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.quickLink();"];
  1083. }
  1084. - (void)insertImage {
  1085. // Save the selection location
  1086. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  1087. [self showInsertImageDialogWithLink:self.selectedImageURL alt:self.selectedImageAlt];
  1088. }
  1089. - (void)insertImageFromDevice {
  1090. // Save the selection location
  1091. [self.editorView stringByEvaluatingJavaScriptFromString:@"zss_editor.prepareInsert();"];
  1092. [self showInsertImageDialogFromDeviceWithScale:self.selectedImageScale alt:self.selectedImageAlt];
  1093. }
  1094. - (void)showInsertImageDialogWithLink:(NSString *)url alt:(NSString *)alt {
  1095. // Insert Button Title
  1096. NSString *insertButtonTitle = !self.selectedImageURL ? NSLocalizedString(@"Insert", nil) : NSLocalizedString(@"Update", nil);
  1097. // Picker Button
  1098. UIButton *am = [UIButton buttonWithType:UIButtonTypeCustom];
  1099. am.frame = CGRectMake(0, 0, 25, 25);
  1100. [am setImage:[UIImage imageNamed:@"ZSSpicker.png"] forState:UIControlStateNormal];
  1101. [am addTarget:self action:@selector(showInsertImageAlternatePicker) forControlEvents:UIControlEventTouchUpInside];
  1102. if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
  1103. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
  1104. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  1105. textField.placeholder = NSLocalizedString(@"URL (required)", nil);
  1106. if (url) {
  1107. textField.text = url;
  1108. }
  1109. textField.rightView = am;
  1110. textField.rightViewMode = UITextFieldViewModeAlways;
  1111. textField.clearButtonMode = UITextFieldViewModeAlways;
  1112. }];
  1113. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  1114. textField.placeholder = NSLocalizedString(@"Alt", nil);
  1115. textField.clearButtonMode = UITextFieldViewModeAlways;
  1116. textField.secureTextEntry = NO;
  1117. if (alt) {
  1118. textField.text = alt;
  1119. }
  1120. }];
  1121. [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  1122. [self focusTextEditor];
  1123. }]];
  1124. [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  1125. UITextField *imageURL = [alertController.textFields objectAtIndex:0];
  1126. UITextField *alt = [alertController.textFields objectAtIndex:1];
  1127. if (!self.selectedImageURL) {
  1128. [self insertImage:imageURL.text alt:alt.text];
  1129. } else {
  1130. [self updateImage:imageURL.text alt:alt.text];
  1131. }
  1132. [self focusTextEditor];
  1133. }]];
  1134. [self presentViewController:alertController animated:YES completion:NULL];
  1135. } else {
  1136. self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
  1137. self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
  1138. self.alertView.tag = 1;
  1139. UITextField *imageURL = [self.alertView textFieldAtIndex:0];
  1140. imageURL.placeholder = NSLocalizedString(@"URL (required)", nil);
  1141. if (url) {
  1142. imageURL.text = url;
  1143. }
  1144. imageURL.rightView = am;
  1145. imageURL.rightViewMode = UITextFieldViewModeAlways;
  1146. imageURL.clearButtonMode = UITextFieldViewModeAlways;
  1147. UITextField *alt1 = [self.alertView textFieldAtIndex:1];
  1148. alt1.secureTextEntry = NO;
  1149. alt1.placeholder = NSLocalizedString(@"Alt", nil);
  1150. alt1.clearButtonMode = UITextFieldViewModeAlways;
  1151. if (alt) {
  1152. alt1.text = alt;
  1153. }
  1154. [self.alertView show];
  1155. }
  1156. }
  1157. - (void)showInsertImageDialogFromDeviceWithScale:(CGFloat)scale alt:(NSString *)alt {
  1158. // Insert button title
  1159. NSString *insertButtonTitle = !self.selectedImageURL ? NSLocalizedString(@"Pick Image", nil) : NSLocalizedString(@"Pick New Image", nil);
  1160. //If the OS version supports the new UIAlertController go for it. Otherwise use the old UIAlertView
  1161. if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
  1162. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Image From Device", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
  1163. //Add alt text field
  1164. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  1165. textField.placeholder = NSLocalizedString(@"Alt", nil);
  1166. textField.clearButtonMode = UITextFieldViewModeAlways;
  1167. textField.secureTextEntry = NO;
  1168. if (alt) {
  1169. textField.text = alt;
  1170. }
  1171. }];
  1172. //Add scale text field
  1173. [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
  1174. textField.clearButtonMode = UITextFieldViewModeAlways;
  1175. textField.secureTextEntry = NO;
  1176. textField.placeholder = NSLocalizedString(@"Image scale, 0.3 by default", nil);
  1177. textField.keyboardType = UIKeyboardTypeDecimalPad;
  1178. }];
  1179. //Cancel action
  1180. [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  1181. [self focusTextEditor];
  1182. }]];
  1183. //Insert action
  1184. [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  1185. UITextField *textFieldAlt = [alertController.textFields objectAtIndex:0];
  1186. UITextField *textFieldScale = [alertController.textFields objectAtIndex:1];
  1187. self.selectedImageScale = [textFieldScale.text floatValue]?:kDefaultScale;
  1188. self.selectedImageAlt = textFieldAlt.text?:@"";
  1189. [self presentViewController:self.imagePicker animated:YES completion:nil];
  1190. }]];
  1191. [self presentViewController:alertController animated:YES completion:NULL];
  1192. } else {
  1193. self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
  1194. self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
  1195. self.alertView.tag = 3;
  1196. UITextField *textFieldAlt = [self.alertView textFieldAtIndex:0];
  1197. textFieldAlt.secureTextEntry = NO;
  1198. textFieldAlt.placeholder = NSLocalizedString(@"Alt", nil);
  1199. textFieldAlt.clearButtonMode = UITextFieldViewModeAlways;
  1200. if (alt) {
  1201. textFieldAlt.text = alt;
  1202. }
  1203. UITextField *textFieldScale = [self.alertView textFieldAtIndex:1];
  1204. textFieldScale.placeholder = NSLocalizedString(@"Image scale, 0.3 by default", nil);
  1205. textFieldScale.keyboardType = UIKeyboardTypeDecimalPad;
  1206. [self.alertView show];
  1207. }
  1208. }
  1209. - (void)insertImage:(NSString *)url alt:(NSString *)alt {
  1210. NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertImage(\"%@\", \"%@\");", url, alt];
  1211. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1212. }
  1213. - (void)updateImage:(NSString *)url alt:(NSString *)alt {
  1214. NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateImage(\"%@\", \"%@\");", url, alt];
  1215. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1216. }
  1217. - (void)insertImageBase64String:(NSString *)imageBase64String alt:(NSString *)alt {
  1218. NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertImageBase64String(\"%@\", \"%@\");", imageBase64String, alt];
  1219. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1220. }
  1221. - (void)updateImageBase64String:(NSString *)imageBase64String alt:(NSString *)alt {
  1222. NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateImageBase64String(\"%@\", \"%@\");", imageBase64String, alt];
  1223. [self.editorView stringByEvaluatingJavaScriptFromString:trigger];
  1224. }
  1225. - (void)updateToolBarWithButtonName:(NSString *)name {
  1226. // Items that are enabled
  1227. NSArray *itemNames = [name componentsSeparatedByString:@","];
  1228. // Special case for link
  1229. NSMutableArray *itemsModified = [[NSMutableArray alloc] init];
  1230. for (NSString *linkItem in itemNames) {
  1231. NSString *updatedItem = linkItem;
  1232. if ([linkItem hasPrefix:@"link:"]) {
  1233. updatedItem = @"link";
  1234. self.selectedLinkURL = [linkItem stringByReplacingOccurrencesOfString:@"link:" withString:@""];
  1235. } else if ([linkItem hasPrefix:@"link-title:"]) {
  1236. self.selectedLinkTitle = [self stringByDecodingURLFormat:[linkItem stringByReplacingOccurrencesOfString:@"link-title:" withString:@""]];
  1237. } else if ([linkItem hasPrefix:@"image:"]) {
  1238. updatedItem = @"image";
  1239. self.selectedImageURL = [linkItem stringByReplacingOccurrencesOfString:@"image:" withString:@""];
  1240. } else if ([linkItem hasPrefix:@"image-alt:"]) {
  1241. self.selectedImageAlt = [self stringByDecodingURLFormat:[linkItem stringByReplacingOccurrencesOfString:@"image-alt:" withString:@""]];
  1242. } else {
  1243. self.selectedImageURL = nil;
  1244. self.selectedImageAlt = nil;
  1245. self.selectedLinkURL = nil;
  1246. self.selectedLinkTitle = nil;
  1247. }
  1248. [itemsModified addObject:updatedItem];
  1249. }
  1250. itemNames = [NSArray arrayWithArray:itemsModified];
  1251. self.editorItemsEnabled = itemNames;
  1252. // Highlight items
  1253. NSArray *items = self.toolbar.items;
  1254. for (ZSSBarButtonItem *item in items) {
  1255. if ([itemNames containsObject:item.label]) {
  1256. item.tintColor = [self barButtonItemSelectedDefaultColor];
  1257. } else {
  1258. item.tintColor = [self barButtonItemDefaultColor];
  1259. }
  1260. }
  1261. }
  1262. #pragma mark - UITextView Delegate
  1263. - (void)textViewDidChange:(UITextView *)textView {
  1264. CGRect line = [textView caretRectForPosition:textView.selectedTextRange.start];
  1265. CGFloat overflow = line.origin.y + line.size.height - ( textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top );
  1266. if ( overflow > 0 ) {
  1267. // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
  1268. // Scroll caret to visible area
  1269. CGPoint offset = textView.contentOffset;
  1270. offset.y += overflow + 7; // leave 7 pixels margin
  1271. // Cannot animate with setContentOffset:animated: or caret will not appear
  1272. [UIView animateWithDuration:.2 animations:^{
  1273. [textView setContentOffset:offset];
  1274. }];
  1275. }
  1276. }
  1277. #pragma mark - UIWebView Delegate
  1278. - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
  1279. NSString *urlString = [[request URL] absoluteString];
  1280. //NSLog(@"web request");
  1281. //NSLog(@"%@", urlString);
  1282. if (navigationType == UIWebViewNavigationTypeLinkClicked) {
  1283. return NO;
  1284. } else if ([urlString rangeOfString:@"callback://0/"].location != NSNotFound) {
  1285. // We recieved the callback
  1286. NSString *className = [urlString stringByReplacingOccurrencesOfString:@"callback://0/" withString:@""];
  1287. [self updateToolBarWithButtonName:className];
  1288. } else if ([urlString rangeOfString:@"debug://"].location != NSNotFound) {
  1289. NSLog(@"Debug Found");
  1290. // We recieved the callback
  1291. NSString *debug = [urlString stringByReplacingOccurrencesOfString:@"debug://" withString:@""];
  1292. debug = [debug stringByReplacingPercentEscapesUsingEncoding:NSStringEncodingConversionAllowLossy];
  1293. NSLog(@"%@", debug);
  1294. } else if ([urlString rangeOfString:@"scroll://"].location != NSNotFound) {
  1295. NSInteger position = [[urlString stringByReplacingOccurrencesOfString:@"scroll://" withString:@""] integerValue];
  1296. [self editorDidScrollWithPosition:position];
  1297. }
  1298. return YES;
  1299. }
  1300. - (void)webViewDidFinishLoad:(UIWebView *)webView {
  1301. self.editorLoaded = YES;
  1302. if (!self.internalHTML) {
  1303. self.internalHTML = @"";
  1304. }
  1305. [self updateHTML];
  1306. if(self.placeholder) {
  1307. [self setPlaceholderText];
  1308. }
  1309. if (self.customCSS) {
  1310. [self updateCSS];
  1311. }
  1312. if (self.shouldShowKeyboard) {
  1313. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1314. [self focusTextEditor];
  1315. });
  1316. }
  1317. /*
  1318. Callback for when text is changed, solution posted by richardortiz84 https://github.com/nnhubbard/ZSSRichTextEditor/issues/5
  1319. */
  1320. JSContext *ctx = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
  1321. ctx[@"contentUpdateCallback"] = ^(JSValue *msg) {
  1322. if (_receiveEditorDidChangeEvents) {
  1323. [self editorDidChangeWithText:[self getText] andHTML:[self getHTML]];
  1324. }
  1325. [self checkForMentionOrHashtagInText:[self getText]];
  1326. };
  1327. [ctx evaluateScript:@"document.getElementById('zss_editor_content').addEventListener('input', contentUpdateCallback, false);"];
  1328. }
  1329. #pragma mark - Mention & Hashtag Support Section
  1330. - (void)checkForMentionOrHashtagInText:(NSString *)text {
  1331. if ([text containsString:@" "] && [text length] > 0) {
  1332. NSString *lastWord = nil;
  1333. NSString *matchedWord = nil;
  1334. BOOL ContainsHashtag = NO;
  1335. BOOL ContainsMention = NO;
  1336. NSRange range = [text rangeOfString:@" " options:NSBackwardsSearch];
  1337. lastWord = [text substringFromIndex:range.location];
  1338. if (lastWord != nil) {
  1339. //Check if last word typed starts with a #
  1340. NSRegularExpression *hashtagRegex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:nil];
  1341. NSArray *hashtagMatches = [hashtagRegex matchesInString:lastWord options:0 range:NSMakeRange(0, lastWord.length)];
  1342. for (NSTextCheckingResult *match in hashtagMatches) {
  1343. NSRange wordRange = [match rangeAtIndex:1];
  1344. NSString *word = [lastWord substringWithRange:wordRange];
  1345. matchedWord = word;
  1346. ContainsHashtag = YES;
  1347. }
  1348. if (!ContainsHashtag) {
  1349. //Check if last word typed starts with a @
  1350. NSRegularExpression *mentionRegex = [NSRegularExpression regularExpressionWithPattern:@"@(\\w+)" options:0 error:nil];
  1351. NSArray *mentionMatches = [mentionRegex matchesInString:lastWord options:0 range:NSMakeRange(0, lastWord.length)];
  1352. for (NSTextCheckingResult *match in mentionMatches) {
  1353. NSRange wordRange = [match rangeAtIndex:1];
  1354. NSString *word = [lastWord substringWithRange:wordRange];
  1355. matchedWord = word;
  1356. ContainsMention = YES;
  1357. }
  1358. }
  1359. }
  1360. if (ContainsHashtag) {
  1361. [self hashtagRecognizedWithWord:matchedWord];
  1362. }
  1363. if (ContainsMention) {
  1364. [self mentionRecognizedWithWord:matchedWord];
  1365. }
  1366. }
  1367. }
  1368. #pragma mark - Callbacks
  1369. //Blank implementation
  1370. - (void)editorDidScrollWithPosition:(NSInteger)position {}
  1371. //Blank implementation
  1372. - (void)editorDidChangeWithText:(NSString *)text andHTML:(NSString *)html {}
  1373. //Blank implementation
  1374. - (void)hashtagRecognizedWithWord:(NSString *)word {}
  1375. //Blank implementation
  1376. - (void)mentionRecognizedWithWord:(NSString *)word {}
  1377. #pragma mark - AlertView
  1378. - (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView {
  1379. if (alertView.tag == 1) {
  1380. UITextField *textField = [alertView textFieldAtIndex:0];
  1381. UITextField *textField2 = [alertView textFieldAtIndex:1];
  1382. if ([textField.text length] == 0 || [textField2.text length] == 0) {
  1383. return NO;
  1384. }
  1385. } else if (alertView.tag == 2) {
  1386. UITextField *textField = [alertView textFieldAtIndex:0];
  1387. if ([textField.text length] == 0) {
  1388. return NO;
  1389. }
  1390. }
  1391. return YES;
  1392. }
  1393. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  1394. if (alertView.tag == 1) {
  1395. if (buttonIndex == 1) {
  1396. UITextField *imageURL = [alertView textFieldAtIndex:0];
  1397. UITextField *alt = [alertView textFieldAtIndex:1];
  1398. if (!self.selectedImageURL) {
  1399. [self insertImage:imageURL.text alt:alt.text];
  1400. } else {
  1401. [self updateImage:imageURL.text alt:alt.text];
  1402. }
  1403. }
  1404. } else if (alertView.tag == 2) {
  1405. if (buttonIndex == 1) {
  1406. UITextField *linkURL = [alertView textFieldAtIndex:0];
  1407. UITextField *title = [alertView textFieldAtIndex:1];
  1408. if (!self.selectedLinkURL) {
  1409. [self insertLink:linkURL.text title:title.text];
  1410. } else {
  1411. [self updateLink:linkURL.text title:title.text];
  1412. }
  1413. }
  1414. } else if (alertView.tag == 3) {
  1415. if (buttonIndex == 1) {
  1416. UITextField *textFieldAlt = [alertView textFieldAtIndex:0];
  1417. UITextField *textFieldScale = [alertView textFieldAtIndex:1];
  1418. self.selectedImageScale = [textFieldScale.text floatValue]?:kDefaultScale;
  1419. self.selectedImageAlt = textFieldAlt.text?:@"";
  1420. [self presentViewController:self.imagePicker animated:YES completion:nil];
  1421. }
  1422. }
  1423. }
  1424. #pragma mark - Asset Picker
  1425. - (void)showInsertURLAlternatePicker {
  1426. // Blank method. User should implement this in their subclass
  1427. }
  1428. - (void)showInsertImageAlternatePicker {
  1429. // Blank method. User should implement this in their subclass
  1430. }
  1431. #pragma mark - Image Picker Delegate
  1432. - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
  1433. //Dismiss the Image Picker
  1434. [self.navigationController dismissViewControllerAnimated:YES completion:nil];
  1435. }
  1436. - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info{
  1437. UIImage *selectedImage = info[UIImagePickerControllerEditedImage]?:info[UIImagePickerControllerOriginalImage];
  1438. //Scale the image
  1439. CGSize targetSize = CGSizeMake(selectedImage.size.width * self.selectedImageScale, selectedImage.size.height * self.selectedImageScale);
  1440. UIGraphicsBeginImageContext(targetSize);
  1441. [selectedImage drawInRect:CGRectMake(0,0,targetSize.width,targetSize.height)];
  1442. UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
  1443. UIGraphicsEndImageContext();
  1444. //Compress the image, as it is going to be encoded rather than linked
  1445. NSData *scaledImageData = UIImageJPEGRepresentation(scaledImage, kJPEGCompression);
  1446. //Encode the image data as a base64 string
  1447. NSString *imageBase64String = [scaledImageData base64EncodedStringWithOptions:0];
  1448. //Decide if we have to insert or update
  1449. if (!self.imageBase64String) {
  1450. [self insertImageBase64String:imageBase64String alt:self.selectedImageAlt];
  1451. } else {
  1452. [self updateImageBase64String:imageBase64String alt:self.selectedImageAlt];
  1453. }
  1454. self.imageBase64String = imageBase64String;
  1455. //Dismiss the Image Picker
  1456. [self.navigationController dismissViewControllerAnimated:YES completion:nil];
  1457. }
  1458. #pragma mark - Keyboard status
  1459. - (void)keyboardWillShowOrHide:(NSNotification *)notification {
  1460. // Orientation
  1461. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  1462. // User Info
  1463. NSDictionary *info = notification.userInfo;
  1464. CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
  1465. int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
  1466. CGRect keyboardEnd = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
  1467. // Toolbar Sizes
  1468. CGFloat sizeOfToolbar = self.toolbarHolder.frame.size.height;
  1469. // Keyboard Size
  1470. //Checks if IOS8, gets correct keyboard height
  1471. CGFloat keyboardHeight = UIInterfaceOrientationIsLandscape(orientation) ? ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.000000) ? keyboardEnd.size.height : keyboardEnd.size.width : keyboardEnd.size.height;
  1472. // Correct Curve
  1473. UIViewAnimationOptions animationOptions = curve << 16;
  1474. const int extraHeight = 10;
  1475. if ([notification.name isEqualToString:UIKeyboardWillShowNotification]) {
  1476. [UIView animateWithDuration:duration delay:0 options:animationOptions animations:^{
  1477. // Toolbar
  1478. CGRect frame = self.toolbarHolder.frame;
  1479. frame.origin.y = self.view.frame.size.height - (keyboardHeight + sizeOfToolbar);
  1480. self.toolbarHolder.frame = frame;
  1481. // Editor View
  1482. CGRect editorFrame = self.editorView.frame;
  1483. editorFrame.size.height = (self.view.frame.size.height - keyboardHeight) - sizeOfToolbar - extraHeight;
  1484. self.editorView.frame = editorFrame;
  1485. self.editorViewFrame = self.editorView.frame;
  1486. self.editorView.scrollView.contentInset = UIEdgeInsetsZero;
  1487. self.editorView.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
  1488. // Source View
  1489. CGRect sourceFrame = self.sourceView.frame;
  1490. sourceFrame.size.height = (self.view.frame.size.height - keyboardHeight) - sizeOfToolbar - extraHeight;
  1491. self.sourceView.frame = sourceFrame;
  1492. // Provide editor with keyboard height and editor view height
  1493. [self setFooterHeight:(keyboardHeight - 8)];
  1494. [self setContentHeight: self.editorViewFrame.size.height];
  1495. } completion:nil];
  1496. } else {
  1497. [UIView animateWithDuration:duration delay:0 options:animationOptions animations:^{
  1498. CGRect frame = self.toolbarHolder.frame;
  1499. if (_alwaysShowToolbar) {
  1500. frame.origin.y = self.view.frame.size.height - sizeOfToolbar;
  1501. } else {
  1502. frame.origin.y = self.view.frame.size.height + keyboardHeight;
  1503. }
  1504. self.toolbarHolder.frame = frame;
  1505. // Editor View
  1506. CGRect editorFrame = self.editorView.frame;
  1507. if (_alwaysShowToolbar) {
  1508. editorFrame.size.height = ((self.view.frame.size.height - sizeOfToolbar) - extraHeight);
  1509. } else {
  1510. editorFrame.size.height = self.view.frame.size.height;
  1511. }
  1512. self.editorView.frame = editorFrame;
  1513. self.editorViewFrame = self.editorView.frame;
  1514. self.editorView.scrollView.contentInset = UIEdgeInsetsZero;
  1515. self.editorView.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
  1516. // Source View
  1517. CGRect sourceFrame = self.sourceView.frame;
  1518. if (_alwaysShowToolbar) {
  1519. sourceFrame.size.height = ((self.view.frame.size.height - sizeOfToolbar) - extraHeight);
  1520. } else {
  1521. sourceFrame.size.height = self.view.frame.size.height;
  1522. }
  1523. self.sourceView.frame = sourceFrame;
  1524. } completion:nil];
  1525. }
  1526. }
  1527. #pragma mark - Utilities
  1528. - (NSString *)removeQuotesFromHTML:(NSString *)html {
  1529. html = [html stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
  1530. html = [html stringByReplacingOccurrencesOfString:@"“" withString:@"&quot;"];
  1531. html = [html stringByReplacingOccurrencesOfString:@"”" withString:@"&quot;"];
  1532. html = [html stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
  1533. html = [html stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
  1534. return html;
  1535. }
  1536. - (NSString *)tidyHTML:(NSString *)html {
  1537. html = [html stringByReplacingOccurrencesOfString:@"<br>" withString:@"<br />"];
  1538. html = [html stringByReplacingOccurrencesOfString:@"<hr>" withString:@"<hr />"];
  1539. if (self.formatHTML) {
  1540. html = [self.editorView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"style_html(\"%@\");", html]];
  1541. }
  1542. return html;
  1543. }
  1544. - (UIColor *)barButtonItemDefaultColor {
  1545. if (self.toolbarItemTintColor) {
  1546. return self.toolbarItemTintColor;
  1547. }
  1548. return [UIColor colorWithRed:0.0f/255.0f green:122.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
  1549. }
  1550. - (UIColor *)barButtonItemSelectedDefaultColor {
  1551. if (self.toolbarItemSelectedTintColor) {
  1552. return self.toolbarItemSelectedTintColor;
  1553. }
  1554. return [UIColor blackColor];
  1555. }
  1556. - (BOOL)isIpad {
  1557. return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
  1558. }
  1559. - (NSString *)stringByDecodingURLFormat:(NSString *)string {
  1560. NSString *result = [string stringByReplacingOccurrencesOfString:@"+" withString:@" "];
  1561. result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  1562. return result;
  1563. }
  1564. - (void)enableToolbarItems:(BOOL)enable {
  1565. NSArray *items = self.toolbar.items;
  1566. for (ZSSBarButtonItem *item in items) {
  1567. if (![item.label isEqualToString:@"source"]) {
  1568. item.enabled = enable;
  1569. }
  1570. }
  1571. }
  1572. #pragma mark - Memory Warning Section
  1573. - (void)didReceiveMemoryWarning {
  1574. [super didReceiveMemoryWarning];
  1575. }
  1576. @end