1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389 |
- //
- // ZSSRichTextEditorViewController.m
- // ZSSRichTextEditor
- //
- // Created by Nicholas Hubbard on 11/30/13.
- // Copyright (c) 2013 Zed Said Studio. All rights reserved.
- //
- #import <objc/runtime.h>
- #import <UIKit/UIKit.h>
- #import <WebKit/WebKit.h>
- #import "ZSSRichTextEditor.h"
- #import "ZSSBarButtonItem.h"
- #import "HRColorUtil.h"
- #import "ZSSTextView.h"
- @import JavaScriptCore;
- /**
-
- WKWebView modifications for hiding the inputAccessoryView
-
- **/
- @interface WKWebView (HackishAccessoryHiding)
- @property (nonatomic, assign) BOOL hidesInputAccessoryView;
- @end
- @implementation WKWebView (HackishAccessoryHiding)
- static const char * const hackishFixClassName = "WKWebBrowserViewMinusAccessoryView";
- static Class hackishFixClass = Nil;
- - (UIView *)hackishlyFoundBrowserView {
- UIScrollView *scrollView = self.scrollView;
-
- UIView *browserView = nil;
- for (UIView *subview in scrollView.subviews) {
- if ([NSStringFromClass([subview class]) hasPrefix:@"WKWebBrowserView"]) {
- browserView = subview;
- break;
- }
- }
- return browserView;
- }
- - (id)methodReturningNil {
- return nil;
- }
- - (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {
- if (!hackishFixClass) {
- Class newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
- newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
- IMP nilImp = [self methodForSelector:@selector(methodReturningNil)];
- class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");
- objc_registerClassPair(newClass);
-
- hackishFixClass = newClass;
- }
- }
- - (BOOL) hidesInputAccessoryView {
- UIView *browserView = [self hackishlyFoundBrowserView];
- return [browserView class] == hackishFixClass;
- }
- - (void) setHidesInputAccessoryView:(BOOL)value {
- UIView *browserView = [self hackishlyFoundBrowserView];
- if (browserView == nil) {
- return;
- }
- [self ensureHackishSubclassExistsOfBrowserViewClass:[browserView class]];
-
- if (value) {
- object_setClass(browserView, hackishFixClass);
- }
- else {
- Class normalClass = objc_getClass("WKWebBrowserView");
- object_setClass(browserView, normalClass);
- }
- [browserView reloadInputViews];
- }
- @end
- @interface ZSSRichTextEditor ()
- /*
- * Scroll view containing the toolbar
- */
- @property (nonatomic, strong) UIScrollView *toolBarScroll;
- /*
- * Toolbar containing ZSSBarButtonItems
- */
- @property (nonatomic, strong) UIToolbar *toolbar;
- /*
- * Holder for all of the toolbar components
- */
- @property (nonatomic, strong) UIView *toolbarHolder;
- /*
- * String for the HTML
- */
- @property (nonatomic, strong) NSString *htmlString;
- /*
- * WKWebView for writing/editing/displaying the content
- */
- @property (nonatomic, strong) WKWebView *editorView;
- /*
- * ZSSTextView for displaying the source code for what is displayed in the editor view
- */
- @property (nonatomic, strong) ZSSTextView *sourceView;
- /*
- * CGRect for holding the frame for the editor view
- */
- @property (nonatomic) CGRect editorViewFrame;
- /*
- * BOOL for holding if the resources are loaded or not
- */
- @property (nonatomic) BOOL resourcesLoaded;
- /*
- * Array holding the enabled editor items
- */
- @property (nonatomic, strong) NSArray *editorItemsEnabled;
- /*
- * Alert View used when inserting links/images
- */
- @property (nonatomic, strong) UIAlertView *alertView;
- /*
- * NSString holding the selected links URL value
- */
- @property (nonatomic, strong) NSString *selectedLinkURL;
- /*
- * NSString holding the selected links title value
- */
- @property (nonatomic, strong) NSString *selectedLinkTitle;
- /*
- * NSString holding the selected image URL value
- */
- @property (nonatomic, strong) NSString *selectedImageURL;
- /*
- * NSString holding the selected image Alt value
- */
- @property (nonatomic, strong) NSString *selectedImageAlt;
- /*
- * CGFloat holdign the selected image scale value
- */
- @property (nonatomic, assign) CGFloat selectedImageScale;
- /*
- * NSString holding the base64 value of the current image
- */
- @property (nonatomic, strong) NSString *imageBase64String;
- /*
- * Bar button item for the keyboard dismiss button in the toolbar
- */
- @property (nonatomic, strong) UIBarButtonItem *keyboardItem;
- /*
- * Array for custom bar button items
- */
- @property (nonatomic, strong) NSMutableArray *customBarButtonItems;
- /*
- * Array for custom ZSSBarButtonItems
- */
- @property (nonatomic, strong) NSMutableArray *customZSSBarButtonItems;
- /*
- * NSString holding the html
- */
- @property (nonatomic, strong) NSString *internalHTML;
- /*
- * NSString holding the css
- */
- @property (nonatomic, strong) NSString *customCSS;
- /*
- * BOOL for if the editor is loaded or not
- */
- @property (nonatomic) BOOL editorLoaded;
- /*
- * BOOL for if the editor is paste or not
- */
- @property (nonatomic) BOOL editorPaste;
- /*
- * Image Picker for selecting photos from users photo library
- */
- @property (nonatomic, strong) UIImagePickerController *imagePicker;
- // local var to hold first responder state after callback
- @property (nonatomic) BOOL isFirstResponderUpdated;
- /*
- * Method for getting a version of the html without quotes
- */
- - (NSString *)removeQuotesFromHTML:(NSString *)html;
- /*
- * Method for getting a tidied version of the html
- */
- - (void)tidyHTML:(NSString *)html completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
- /*
- * Method for enablign toolbar items
- */
- - (void)enableToolbarItems:(BOOL)enable;
- /*
- * Setter for isIpad BOOL
- */
- - (BOOL)isIpad;
- @end
- /*
-
- ZSSRichTextEditor
-
- */
- @implementation ZSSRichTextEditor
- //Scale image from device
- static CGFloat kJPEGCompression = 0.8;
- static CGFloat kDefaultScale = 0.5;
- #pragma mark - View Did Load Section
- - (void)viewDidLoad {
-
- [super viewDidLoad];
-
- //Initialise variables
- self.editorLoaded = NO;
- self.receiveEditorDidChangeEvents = NO;
- self.alwaysShowToolbar = NO;
- self.shouldShowKeyboard = YES;
- self.formatHTML = YES;
-
- //Initalise enabled toolbar items array
- self.enabledToolbarItems = [[NSArray alloc] init];
-
- //Frame for the source view and editor view
- CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
-
- //Source View
- [self createSourceViewWithFrame:frame];
-
- //Editor View
- [self createEditorViewWithFrame:frame];
-
- //Image Picker used to allow the user insert images from the device (base64 encoded)
- [self setUpImagePicker];
-
- //Scrolling View
- [self createToolBarScroll];
-
- //Toolbar with icons
- [self createToolbar];
-
- //Parent holding view
- [self createParentHoldingView];
-
- //Hide Keyboard
- if (![self isIpad]) {
- NSBundle* bundle = [NSBundle bundleForClass:[ZSSRichTextEditor class]];
-
- // Toolbar holder used to crop and position toolbar
- UIView *toolbarCropper = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width-44, 0, 44, 44)];
- toolbarCropper.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
- toolbarCropper.clipsToBounds = YES;
-
- UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
-
- [btn addTarget:self action:@selector(dismissKeyboard) forControlEvents:UIControlEventTouchUpInside];
- UIImage *image = [[UIImage imageNamed:@"ZSSkeyboard.png" inBundle:bundle compatibleWithTraitCollection:nil] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
- [btn setImage:image forState:UIControlStateNormal];
- [btn setTintColor:[self barButtonItemDefaultColor]];
-
- [toolbarCropper addSubview:btn];
-
- [self.toolbarHolder addSubview:toolbarCropper];
-
- UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0.6f, 44)];
- line.backgroundColor = [UIColor lightGrayColor];
- line.alpha = 0.7f;
- [toolbarCropper addSubview:line];
-
- }
-
- [self.view addSubview:self.toolbarHolder];
-
- //Build the toolbar
- [self buildToolbar];
-
- //Load Resources
- if (!self.resourcesLoaded) {
-
- [self loadResources];
-
- }
-
- }
- #pragma mark - View Will Appear Section
- - (void)viewWillAppear:(BOOL)animated {
-
- [super viewWillAppear:animated];
-
- //Add observers for keyboard showing or hiding notifications
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowOrHide:) name:UIKeyboardWillChangeFrameNotification object:nil];
- }
- #pragma mark - View Will Disappear Section
- - (void)viewWillDisappear:(BOOL)animated {
-
- [super viewWillDisappear:animated];
-
- //Remove observers for keyboard showing or hiding notifications
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
-
- }
- #pragma mark - Set Up View Section
- - (void)createSourceViewWithFrame:(CGRect)frame {
-
- self.sourceView = [[ZSSTextView alloc] initWithFrame:frame];
- self.sourceView.hidden = YES;
- self.sourceView.autocapitalizationType = UITextAutocapitalizationTypeNone;
- self.sourceView.autocorrectionType = UITextAutocorrectionTypeNo;
- self.sourceView.font = [UIFont fontWithName:@"Courier" size:13.0];
- self.sourceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- self.sourceView.autoresizesSubviews = YES;
- self.sourceView.delegate = self;
- [self.view addSubview:self.sourceView];
-
- }
- - (void)createEditorViewWithFrame:(CGRect)frame {
-
-
- //allocate config and contentController and add scriptMessageHandler
- WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
- WKUserContentController *contentController = [[WKUserContentController alloc] init];
- [contentController addScriptMessageHandler:self name:@"jsm"];
-
- config.userContentController = contentController;
- //load scripts
- NSString *scriptString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
- WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
-
- [contentController addUserScript:script];
-
-
- //set data detection to none so it doesnt conflict
- config.dataDetectorTypes = WKDataDetectorTypeNone;
-
-
- self.editorView = [[WKWebView alloc] initWithFrame:frame
- configuration: config];
-
- self.editorView.UIDelegate = self;
- self.editorView.navigationDelegate = self;
- self.editorView.hidesInputAccessoryView = YES;
-
- //TODO: Is this behavior correct? Is it the right replacement?
- // self.editorView.keyboardDisplayRequiresUserAction = NO;
- [ZSSRichTextEditor allowDisplayingKeyboardWithoutUserAction];
- self.editorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
- self.editorView.scrollView.bounces = YES;
- self.editorView.backgroundColor = [UIColor whiteColor];
- [self.view addSubview:self.editorView];
-
- }
- - (void)setUpImagePicker {
-
- self.imagePicker = [[UIImagePickerController alloc] init];
- self.imagePicker.delegate = self;
- self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
- self.imagePicker.allowsEditing = YES;
- self.selectedImageScale = kDefaultScale; //by default scale to half the size
-
- }
- - (void)createToolBarScroll {
-
- self.toolBarScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, [self isIpad] ? self.view.frame.size.width : self.view.frame.size.width - 44, 44)];
- self.toolBarScroll.backgroundColor = [UIColor clearColor];
- self.toolBarScroll.showsHorizontalScrollIndicator = NO;
-
- }
- - (void)createToolbar {
-
- self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
- self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- self.toolbar.backgroundColor = [UIColor clearColor];
- [self.toolBarScroll addSubview:self.toolbar];
- self.toolBarScroll.autoresizingMask = self.toolbar.autoresizingMask;
-
- }
- - (void)createParentHoldingView {
-
- //Background Toolbar
- UIToolbar *backgroundToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
- backgroundToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-
- //Parent holding view
- self.toolbarHolder = [[UIView alloc] init];
-
- if (_alwaysShowToolbar) {
- self.toolbarHolder.frame = CGRectMake(0, self.view.frame.size.height - 44, self.view.frame.size.width, 44);
- } else {
- self.toolbarHolder.frame = CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, 44);
- }
-
- self.toolbarHolder.autoresizingMask = self.toolbar.autoresizingMask;
- [self.toolbarHolder addSubview:self.toolBarScroll];
- [self.toolbarHolder insertSubview:backgroundToolbar atIndex:0];
-
- }
- #pragma mark - Convenience replacement for keyboardDisplayRequiresUserAction in WKWebview
- + (void)allowDisplayingKeyboardWithoutUserAction {
- Class class = NSClassFromString(@"WKContentView");
- NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0};
- NSOperatingSystemVersion iOS_12_2_0 = (NSOperatingSystemVersion){12, 2, 0};
- NSOperatingSystemVersion iOS_13_0_0 = (NSOperatingSystemVersion){13, 0, 0};
- if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_13_0_0]) {
- SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:");
- Method method = class_getInstanceMethod(class, selector);
- IMP original = method_getImplementation(method);
- IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
- ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
- });
- method_setImplementation(method, override);
- }
- else if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_12_2_0]) {
- SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
- Method method = class_getInstanceMethod(class, selector);
- IMP original = method_getImplementation(method);
- IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
- ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
- });
- method_setImplementation(method, override);
- }
- else if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) {
- SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
- Method method = class_getInstanceMethod(class, selector);
- IMP original = method_getImplementation(method);
- IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
- ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
- });
- method_setImplementation(method, override);
- } else {
- SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
- Method method = class_getInstanceMethod(class, selector);
- IMP original = method_getImplementation(method);
- IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
- ((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3);
- });
- method_setImplementation(method, override);
- }
- }
- #pragma mark - Resources Section
- - (void)loadResources {
-
- //Define correct bundle for loading resources
- NSBundle* bundle = [NSBundle bundleForClass:[ZSSRichTextEditor class]];
-
- //Create a string with the contents of editor.html
- NSString *filePath = [bundle pathForResource:@"editor" ofType:@"html"];
- NSData *htmlData = [NSData dataWithContentsOfFile:filePath];
- NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
-
- //Add jQuery.js to the html file
- NSString *jquery = [bundle pathForResource:@"jQuery" ofType:@"js"];
- NSString *jqueryString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:jquery] encoding:NSUTF8StringEncoding];
- htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!-- jQuery -->" withString:jqueryString];
-
- //Add JSBeautifier.js to the html file
- NSString *beautifier = [bundle pathForResource:@"JSBeautifier" ofType:@"js"];
- NSString *beautifierString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:beautifier] encoding:NSUTF8StringEncoding];
- htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!-- jsbeautifier -->" withString:beautifierString];
-
- //Add ZSSRichTextEditor.js to the html file
- NSString *source = [bundle pathForResource:@"ZSSRichTextEditor" ofType:@"js"];
- NSString *jsString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:source] encoding:NSUTF8StringEncoding];
- htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<!--editor-->" withString:jsString];
-
- [self.editorView loadHTMLString:htmlString baseURL:self.baseURL];
- self.resourcesLoaded = YES;
-
- }
- #pragma mark - Toolbar Section
- - (void)setEnabledToolbarItems:(NSArray *)enabledToolbarItems {
-
- _enabledToolbarItems = enabledToolbarItems;
- [self buildToolbar];
-
- }
- - (void)setToolbarItemTintColor:(UIColor *)toolbarItemTintColor {
-
- _toolbarItemTintColor = toolbarItemTintColor;
-
- // Update the color
- for (ZSSBarButtonItem *item in self.toolbar.items) {
- item.tintColor = [self barButtonItemDefaultColor];
- }
- self.keyboardItem.tintColor = toolbarItemTintColor;
-
- }
- - (void)setToolbarItemSelectedTintColor:(UIColor *)toolbarItemSelectedTintColor {
-
- _toolbarItemSelectedTintColor = toolbarItemSelectedTintColor;
-
- }
- - (NSArray *)itemsForToolbar {
-
- //Define correct bundle for loading resources
- NSBundle* bundle = [NSBundle bundleForClass:[ZSSRichTextEditor class]];
-
- NSMutableArray *items = [[NSMutableArray alloc] init];
-
- // None
- if(_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarNone])
- {
- return items;
- }
-
- BOOL customOrder = NO;
- if (_enabledToolbarItems && ![_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll]){
- customOrder = YES;
- for(int i=0; i < _enabledToolbarItems.count;i++){
- [items addObject:@""];
- }
- }
-
- // Bold
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarBold]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *bold = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSbold.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setBold)];
- bold.label = @"bold";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarBold] withObject:bold];
- } else {
- [items addObject:bold];
- }
- }
-
- // Italic
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarItalic]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *italic = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSitalic.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setItalic)];
- italic.label = @"italic";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarItalic] withObject:italic];
- } else {
- [items addObject:italic];
- }
- }
-
- // Subscript
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarSubscript]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *subscript = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSsubscript.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setSubscript)];
- subscript.label = @"subscript";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarSubscript] withObject:subscript];
- } else {
- [items addObject:subscript];
- }
- }
-
- // Superscript
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarSuperscript]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *superscript = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSsuperscript.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setSuperscript)];
- superscript.label = @"superscript";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarSuperscript] withObject:superscript];
- } else {
- [items addObject:superscript];
- }
- }
-
- // Strike Through
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarStrikeThrough]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *strikeThrough = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSstrikethrough.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setStrikethrough)];
- strikeThrough.label = @"strikeThrough";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarStrikeThrough] withObject:strikeThrough];
- } else {
- [items addObject:strikeThrough];
- }
- }
-
- // Underline
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUnderline]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *underline = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunderline.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setUnderline)];
- underline.label = @"underline";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUnderline] withObject:underline];
- } else {
- [items addObject:underline];
- }
- }
-
- // Remove Format
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRemoveFormat]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *removeFormat = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSclearstyle.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(removeFormat)];
- removeFormat.label = @"removeFormat";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRemoveFormat] withObject:removeFormat];
- } else {
- [items addObject:removeFormat];
- }
- }
-
- // Fonts
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarFonts]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
-
- ZSSBarButtonItem *fonts = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSfonts.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(showFontsPicker)];
- fonts.label = @"fonts";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarFonts] withObject:fonts];
- } else {
- [items addObject:fonts];
- }
-
- }
-
- // Undo
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUndo]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *undoButton = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSundo.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(undo:)];
- undoButton.label = @"undo";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUndo] withObject:undoButton];
- } else {
- [items addObject:undoButton];
- }
- }
-
- // Redo
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRedo]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *redoButton = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSredo.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(redo:)];
- redoButton.label = @"redo";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRedo] withObject:redoButton];
- } else {
- [items addObject:redoButton];
- }
- }
-
- // Align Left
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyLeft]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *alignLeft = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSleftjustify.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(alignLeft)];
- alignLeft.label = @"justifyLeft";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyLeft] withObject:alignLeft];
- } else {
- [items addObject:alignLeft];
- }
- }
-
- // Align Center
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyCenter]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *alignCenter = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSScenterjustify.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(alignCenter)];
- alignCenter.label = @"justifyCenter";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyCenter] withObject:alignCenter];
- } else {
- [items addObject:alignCenter];
- }
- }
-
- // Align Right
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyRight]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *alignRight = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSrightjustify.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(alignRight)];
- alignRight.label = @"justifyRight";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyRight] withObject:alignRight];
- } else {
- [items addObject:alignRight];
- }
- }
-
- // Align Justify
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarJustifyFull]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *alignFull = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSforcejustify.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(alignFull)];
- alignFull.label = @"justifyFull";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarJustifyFull] withObject:alignFull];
- } else {
- [items addObject:alignFull];
- }
- }
-
- // Paragraph
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarParagraph]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *paragraph = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSparagraph.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(paragraph)];
- paragraph.label = @"p";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarParagraph] withObject:paragraph];
- } else {
- [items addObject:paragraph];
- }
- }
-
- // Header 1
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH1]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h1 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh1.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading1)];
- h1.label = @"h1";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH1] withObject:h1];
- } else {
- [items addObject:h1];
- }
- }
-
- // Header 2
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH2]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h2 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh2.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading2)];
- h2.label = @"h2";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH2] withObject:h2];
- } else {
- [items addObject:h2];
- }
- }
-
- // Header 3
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH3]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h3 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh3.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading3)];
- h3.label = @"h3";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH3] withObject:h3];
- } else {
- [items addObject:h3];
- }
- }
-
- // Heading 4
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH4]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h4 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh4.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading4)];
- h4.label = @"h4";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH4] withObject:h4];
- } else {
- [items addObject:h4];
- }
- }
-
- // Header 5
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH5]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h5 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh5.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading5)];
- h5.label = @"h5";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH5] withObject:h5];
- } else {
- [items addObject:h5];
- }
- }
-
- // Heading 6
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarH6]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *h6 = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSh6.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(heading6)];
- h6.label = @"h6";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarH6] withObject:h6];
- } else {
- [items addObject:h6];
- }
- }
-
- // Text Color
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarTextColor]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *textColor = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSStextcolor.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(textColor)];
- textColor.label = @"textColor";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarTextColor] withObject:textColor];
- } else {
- [items addObject:textColor];
- }
- }
-
- // Background Color
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarBackgroundColor]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *bgColor = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSbgcolor.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(bgColor)];
- bgColor.label = @"backgroundColor";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarBackgroundColor] withObject:bgColor];
- } else {
- [items addObject:bgColor];
- }
- }
-
- // Unordered List
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarUnorderedList]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *ul = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunorderedlist.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setUnorderedList)];
- ul.label = @"unorderedList";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarUnorderedList] withObject:ul];
- } else {
- [items addObject:ul];
- }
- }
-
- // Ordered List
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarOrderedList]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *ol = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSorderedlist.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setOrderedList)];
- ol.label = @"orderedList";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarOrderedList] withObject:ol];
- } else {
- [items addObject:ol];
- }
- }
-
- // Horizontal Rule
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarHorizontalRule]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *hr = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSShorizontalrule.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setHR)];
- hr.label = @"horizontalRule";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarHorizontalRule] withObject:hr];
- } else {
- [items addObject:hr];
- }
- }
-
- // Indent
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarIndent]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *indent = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSindent.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setIndent)];
- indent.label = @"indent";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarIndent] withObject:indent];
- } else {
- [items addObject:indent];
- }
- }
-
- // Outdent
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarOutdent]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *outdent = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSoutdent.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(setOutdent)];
- outdent.label = @"outdent";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarOutdent] withObject:outdent];
- } else {
- [items addObject:outdent];
- }
- }
-
- // Image
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertImage]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *insertImage = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSimage.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(insertImage)];
- insertImage.label = @"image";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertImage] withObject:insertImage];
- } else {
- [items addObject:insertImage];
- }
- }
-
- // Image From Device
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertImageFromDevice]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *insertImageFromDevice = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSimageDevice.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(insertImageFromDevice)];
- insertImageFromDevice.label = @"imageFromDevice";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertImageFromDevice] withObject:insertImageFromDevice];
- } else {
- [items addObject:insertImageFromDevice];
- }
- }
-
- // Insert Link
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarInsertLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *insertLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSlink.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(insertLink)];
- insertLink.label = @"link";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarInsertLink] withObject:insertLink];
- } else {
- [items addObject:insertLink];
- }
- }
-
- // Remove Link
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarRemoveLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *removeLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSunlink.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(removeLink)];
- removeLink.label = @"removeLink";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarRemoveLink] withObject:removeLink];
- } else {
- [items addObject:removeLink];
- }
- }
-
- // Quick Link
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarQuickLink]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *quickLink = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSquicklink.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(quickLink)];
- quickLink.label = @"quickLink";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarQuickLink] withObject:quickLink];
- } else {
- [items addObject:quickLink];
- }
- }
-
- // Show Source
- if ((_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarViewSource]) || (_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarAll])) {
- ZSSBarButtonItem *showSource = [[ZSSBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ZSSviewsource.png" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(showHTMLSource:)];
- showSource.label = @"source";
- if (customOrder) {
- [items replaceObjectAtIndex:[_enabledToolbarItems indexOfObject:ZSSRichTextEditorToolbarViewSource] withObject:showSource];
- } else {
- [items addObject:showSource];
- }
- }
-
- return [NSArray arrayWithArray:items];
-
- }
- - (void)buildToolbar {
-
- // Check to see if we have any toolbar items, if not, add them all
- NSArray *items = [self itemsForToolbar];
- if (items.count == 0 && !(_enabledToolbarItems && [_enabledToolbarItems containsObject:ZSSRichTextEditorToolbarNone])) {
- _enabledToolbarItems = @[ZSSRichTextEditorToolbarAll];
- items = [self itemsForToolbar];
- }
-
- if (self.customZSSBarButtonItems != nil) {
- items = [items arrayByAddingObjectsFromArray:self.customZSSBarButtonItems];
- }
-
- // get the width before we add custom buttons
- CGFloat toolbarWidth = items.count == 0 ? 0.0f : (CGFloat)(items.count * 44);
-
- if(self.customBarButtonItems != nil)
- {
- items = [items arrayByAddingObjectsFromArray:self.customBarButtonItems];
- for(ZSSBarButtonItem *buttonItem in self.customBarButtonItems)
- {
- toolbarWidth += buttonItem.customView.frame.size.width + 11.0f;
- }
- }
-
- self.toolbar.items = items;
- for (ZSSBarButtonItem *item in items) {
- item.tintColor = [self barButtonItemDefaultColor];
- }
-
- self.toolbar.frame = CGRectMake(0, 0, toolbarWidth, 44);
- self.toolBarScroll.contentSize = CGSizeMake(self.toolbar.frame.size.width, 44);
- }
- #pragma mark - Editor Modification Section
- - (void)setCSS:(NSString *)css {
-
- self.customCSS = css;
-
- if (self.editorLoaded) {
- [self updateCSS];
- }
-
- }
- - (void)updateCSS {
-
- if (self.customCSS != NULL && [self.customCSS length] != 0) {
-
- NSString *js = [NSString stringWithFormat:@"zss_editor.setCustomCSS(\"%@\");", self.customCSS];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- }
-
- }
- - (void)setPlaceholderText {
-
- //Call the setPlaceholder javascript method if a placeholder has been set
- if (self.placeholder != NULL && [self.placeholder length] != 0) {
-
- NSString *js = [NSString stringWithFormat:@"zss_editor.setPlaceholder(\"%@\");", self.placeholder];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- }
-
- }
- - (void)setFooterHeight:(float)footerHeight {
-
- //Call the setFooterHeight javascript method
- NSString *js = [NSString stringWithFormat:@"zss_editor.setFooterHeight(\"%f\");", footerHeight];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- }
- - (void)setContentHeight:(float)contentHeight {
-
- //Call the contentHeight javascript method
- NSString *js = [NSString stringWithFormat:@"zss_editor.contentHeight = %f;", contentHeight];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- }
- #pragma mark - Editor Interaction
- - (void)focusTextEditor {
-
- //TODO: Is this behavior correct? Is it the right replacement?
- // self.editorView.keyboardDisplayRequiresUserAction = NO;
- [ZSSRichTextEditor allowDisplayingKeyboardWithoutUserAction];
-
- NSString *js = [NSString stringWithFormat:@"zss_editor.focusEditor();"];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)blurTextEditor {
- NSString *js = [NSString stringWithFormat:@"zss_editor.blurEditor();"];
- [self.editorView evaluateJavaScript:js completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setHTML:(NSString *)html {
-
- self.internalHTML = html;
-
- if (self.editorLoaded) {
- [self updateHTML];
- }
-
- }
- - (void)updateHTML {
-
- NSString *html = self.internalHTML;
- self.sourceView.text = html;
- NSString *cleanedHTML = [self removeQuotesFromHTML:self.sourceView.text];
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.setHTML(\"%@\");", cleanedHTML];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
- }];
-
- }
- - (void)getHTML:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler {
-
-
- [self.editorView evaluateJavaScript:ZSSEditorHTML completionHandler:^(NSString *result, NSError *error) {
-
- if (error != NULL) {
- NSLog(@"HTML Parsing Error: %@", error);
- }
-
- NSLog(@"%@", result);
-
- NSString *html = [self removeQuotesFromHTML:result];
-
- NSLog(@"%@", html);
-
- [self tidyHTML:html completionHandler:^(NSString *result, NSError *error) {
- completionHandler(result, error);
- }];
- }];
- }
- - (void)insertHTML:(NSString *)html {
-
- NSString *cleanedHTML = [self removeQuotesFromHTML:html];
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertHTML(\"%@\");", cleanedHTML];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)getText:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler {
-
- [self.editorView evaluateJavaScript:ZSSEditorText completionHandler:^(NSString *result, NSError *error) {
-
- if (error != NULL) {
- NSLog(@"Text Parsing Error: %@", error);
- }
-
-
- completionHandler(result, error);
- }];
- }
- - (void)updateEditor {
- [self getHTML:^(NSString *htmlResult, NSError * _Nullable error) {
- [self getText:^(NSString *textResult, NSError * _Nullable error) {
- [self editorDidChangeWithText:textResult andHTML:htmlResult];
- }];
- }];
- }
- - (void)dismissKeyboard {
- [self.view endEditing:YES];
- }
- - (BOOL)isFirstResponder {
-
- [self.editorView evaluateJavaScript:ZSSEditorContent completionHandler:^(NSNumber *result, NSError *error) {
-
- //save the result as a bool and then update the UI
- self.isFirstResponderUpdated = [result boolValue];
- if (self.isFirstResponderUpdated == true) {
- [self becomeFirstResponder];
- } else {
- [self resignFirstResponder];
- }
- }];
-
- //this state is old and will quickly be updated after the callback above completes
- //TODO: refactor to find a more elegant approach
- return self.isFirstResponderUpdated;
- }
- - (void)showHTMLSource:(ZSSBarButtonItem *)barButtonItem {
- if (self.sourceView.hidden) {
-
- [self getHTML:^(NSString *result, NSError * _Nullable error) {
- self.sourceView.text = result;
- }];
-
- self.sourceView.hidden = NO;
- barButtonItem.tintColor = [UIColor blackColor];
- self.editorView.hidden = YES;
- [self enableToolbarItems:NO];
- } else {
- [self setHTML:self.sourceView.text];
- barButtonItem.tintColor = [self barButtonItemDefaultColor];
- self.sourceView.hidden = YES;
- self.editorView.hidden = NO;
- [self enableToolbarItems:YES];
- }
- }
- - (void)removeFormat {
- NSString *trigger = @"zss_editor.removeFormating();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)alignLeft {
- NSString *trigger = @"zss_editor.setJustifyLeft();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)alignCenter {
- NSString *trigger = @"zss_editor.setJustifyCenter();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)alignRight {
- NSString *trigger = @"zss_editor.setJustifyRight();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)alignFull {
- NSString *trigger = @"zss_editor.setJustifyFull();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setBold {
- NSString *trigger = @"zss_editor.setBold();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setItalic {
- NSString *trigger = @"zss_editor.setItalic();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setSubscript {
- NSString *trigger = @"zss_editor.setSubscript();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setUnderline {
- NSString *trigger = @"zss_editor.setUnderline();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setSuperscript {
- NSString *trigger = @"zss_editor.setSuperscript();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setStrikethrough {
- NSString *trigger = @"zss_editor.setStrikeThrough();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setUnorderedList {
- NSString *trigger = @"zss_editor.setUnorderedList();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setOrderedList {
- NSString *trigger = @"zss_editor.setOrderedList();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setHR {
- NSString *trigger = @"zss_editor.setHorizontalRule();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setIndent {
- NSString *trigger = @"zss_editor.setIndent();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)setOutdent {
- NSString *trigger = @"zss_editor.setOutdent();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading1 {
- NSString *trigger = @"zss_editor.setHeading('h1');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading2 {
- NSString *trigger = @"zss_editor.setHeading('h2');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading3 {
- NSString *trigger = @"zss_editor.setHeading('h3');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading4 {
- NSString *trigger = @"zss_editor.setHeading('h4');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading5 {
- NSString *trigger = @"zss_editor.setHeading('h5');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)heading6 {
- NSString *trigger = @"zss_editor.setHeading('h6');";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)paragraph {
- NSString *trigger = @"zss_editor.setParagraph();";
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)showFontsPicker {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- //Call picker
- ZSSFontsViewController *fontPicker = [ZSSFontsViewController cancelableFontPickerViewControllerWithFontFamily:ZSSFontFamilyDefault];
- fontPicker.delegate = self;
- [self.navigationController pushViewController:fontPicker animated:YES];
-
- }
- - (void)setSelectedFontFamily:(ZSSFontFamily)fontFamily {
-
- NSString *fontFamilyString;
-
- switch (fontFamily) {
- case ZSSFontFamilyDefault:
- fontFamilyString = @"Arial, Helvetica, sans-serif";
- break;
-
- case ZSSFontFamilyGeorgia:
- fontFamilyString = @"Georgia, serif";
- break;
-
- case ZSSFontFamilyPalatino:
- fontFamilyString = @"Palatino Linotype, Book Antiqua, Palatino, serif";
- break;
-
- case ZSSFontFamilyTimesNew:
- fontFamilyString = @"Times New Roman, Times, serif";
- break;
-
- case ZSSFontFamilyTrebuchet:
- fontFamilyString = @"Trebuchet MS, Helvetica, sans-serif";
- break;
-
- case ZSSFontFamilyVerdana:
- fontFamilyString = @"Verdana, Geneva, sans-serif";
- break;
-
- case ZSSFontFamilyCourierNew:
- fontFamilyString = @"Courier New, Courier, monospace";
- break;
-
- default:
- fontFamilyString = @"Arial, Helvetica, sans-serif";
- break;
- }
-
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.setFontFamily(\"%@\");", fontFamilyString];
-
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)textColor {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- // Call the picker
- HRColorPickerViewController *colorPicker = [HRColorPickerViewController cancelableFullColorPickerViewControllerWithColor:[UIColor whiteColor]];
- colorPicker.delegate = self;
- colorPicker.tag = 1;
- colorPicker.title = NSLocalizedString(@"Text Color", nil);
- [self.navigationController pushViewController:colorPicker animated:YES];
-
- }
- - (void)bgColor {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- // Call the picker
- HRColorPickerViewController *colorPicker = [HRColorPickerViewController cancelableFullColorPickerViewControllerWithColor:[UIColor whiteColor]];
- colorPicker.delegate = self;
- colorPicker.tag = 2;
- colorPicker.title = NSLocalizedString(@"BG Color", nil);
- [self.navigationController pushViewController:colorPicker animated:YES];
-
- }
- - (void)setSelectedColor:(UIColor*)color tag:(int)tag {
-
- NSString *hex = [NSString stringWithFormat:@"#%06x",HexColorFromUIColor(color)];
- NSString *trigger;
- if (tag == 1) {
- trigger = [NSString stringWithFormat:@"zss_editor.setTextColor(\"%@\");", hex];
- } else if (tag == 2) {
- trigger = [NSString stringWithFormat:@"zss_editor.setBackgroundColor(\"%@\");", hex];
- }
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)undo:(ZSSBarButtonItem *)barButtonItem {
- [self.editorView evaluateJavaScript:@"zss_editor.undo();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)redo:(ZSSBarButtonItem *)barButtonItem {
- [self.editorView evaluateJavaScript:@"zss_editor.redo();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)insertLink {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
- // Show the dialog for inserting or editing a link
- [self showInsertLinkDialogWithLink:self.selectedLinkURL title:self.selectedLinkTitle];
-
- }
- - (void)showInsertLinkDialogWithLink:(NSString *)url title:(NSString *)title {
-
- // Insert Button Title
- NSString *insertButtonTitle = !self.selectedLinkURL ? NSLocalizedString(@"Insert", nil) : NSLocalizedString(@"Update", nil);
-
- // Picker Button
- UIButton *am = [UIButton buttonWithType:UIButtonTypeCustom];
- am.frame = CGRectMake(0, 0, 25, 25);
- [am setImage:[UIImage imageNamed:@"ZSSpicker.png" inBundle:[NSBundle bundleForClass:[ZSSRichTextEditor class]] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
- [am addTarget:self action:@selector(showInsertURLAlternatePicker) forControlEvents:UIControlEventTouchUpInside];
-
- if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Link", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.placeholder = NSLocalizedString(@"URL (required)", nil);
- if (url) {
- textField.text = url;
- }
- textField.rightView = am;
- textField.rightViewMode = UITextFieldViewModeAlways;
- textField.clearButtonMode = UITextFieldViewModeAlways;
- }];
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.placeholder = NSLocalizedString(@"Title", nil);
- textField.clearButtonMode = UITextFieldViewModeAlways;
- textField.secureTextEntry = NO;
- if (title) {
- textField.text = title;
- }
- }];
- [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
- [self focusTextEditor];
- }]];
- [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
-
- UITextField *linkURL = [alertController.textFields objectAtIndex:0];
- UITextField *title = [alertController.textFields objectAtIndex:1];
- if (!self.selectedLinkURL) {
- [self insertLink:linkURL.text title:title.text];
- //NSLog(@"insert link");
- } else {
- [self updateLink:linkURL.text title:title.text];
- }
- [self focusTextEditor];
- }]];
- [self presentViewController:alertController animated:YES completion:NULL];
-
- } else {
-
- self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Link", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
- self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
- self.alertView.tag = 2;
- UITextField *linkURL = [self.alertView textFieldAtIndex:0];
- linkURL.placeholder = NSLocalizedString(@"URL (required)", nil);
- if (url) {
- linkURL.text = url;
- }
-
- linkURL.rightView = am;
- linkURL.rightViewMode = UITextFieldViewModeAlways;
-
- UITextField *alt = [self.alertView textFieldAtIndex:1];
- alt.secureTextEntry = NO;
- alt.placeholder = NSLocalizedString(@"Title", nil);
- if (title) {
- alt.text = title;
- }
-
- [self.alertView show];
- }
-
- }
- - (void)insertLink:(NSString *)url title:(NSString *)title {
-
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertLink(\"%@\", \"%@\");", url, title];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- if (_receiveEditorDidChangeEvents) {
- [self updateEditor];
- }
- }
- - (void)updateLink:(NSString *)url title:(NSString *)title {
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateLink(\"%@\", \"%@\");", url, title];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- if (_receiveEditorDidChangeEvents) {
- [self updateEditor];
- }
- }
- - (void)dismissAlertView {
- [self.alertView dismissWithClickedButtonIndex:self.alertView.cancelButtonIndex animated:YES];
- }
- - (void)addCustomToolbarItemWithButton:(UIButton *)button {
-
- if(self.customBarButtonItems == nil)
- {
- self.customBarButtonItems = [NSMutableArray array];
- }
-
- button.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:28.5f];
- [button setTitleColor:[self barButtonItemDefaultColor] forState:UIControlStateNormal];
- [button setTitleColor:[self barButtonItemSelectedDefaultColor] forState:UIControlStateHighlighted];
-
- ZSSBarButtonItem *barButtonItem = [[ZSSBarButtonItem alloc] initWithCustomView:button];
-
- [self.customBarButtonItems addObject:barButtonItem];
-
- [self buildToolbar];
- }
- - (void)addCustomToolbarItem:(ZSSBarButtonItem *)item {
-
- if(self.customZSSBarButtonItems == nil)
- {
- self.customZSSBarButtonItems = [NSMutableArray array];
- }
- [self.customZSSBarButtonItems addObject:item];
-
- [self buildToolbar];
- }
- - (void)removeLink {
- [self.editorView evaluateJavaScript:@"zss_editor.unlink();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- if (_receiveEditorDidChangeEvents) {
- [self updateEditor];
- }
- }
- - (void)quickLink {
- [self.editorView evaluateJavaScript:@"zss_editor.quickLink();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
-
- if (_receiveEditorDidChangeEvents) {
- [self updateEditor];
- }
- }
- - (void)insertImage {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
- [self showInsertImageDialogWithLink:self.selectedImageURL alt:self.selectedImageAlt];
-
- }
- - (void)insertImageFromDevice {
-
- // Save the selection location
- [self.editorView evaluateJavaScript:@"zss_editor.prepareInsert();" completionHandler:^(NSString *result, NSError *error) {
-
- }];
- [self showInsertImageDialogFromDeviceWithScale:self.selectedImageScale alt:self.selectedImageAlt];
-
- }
- - (void)showInsertImageDialogWithLink:(NSString *)url alt:(NSString *)alt {
-
- // Insert Button Title
- NSString *insertButtonTitle = !self.selectedImageURL ? NSLocalizedString(@"Insert", nil) : NSLocalizedString(@"Update", nil);
-
- // Picker Button
- UIButton *am = [UIButton buttonWithType:UIButtonTypeCustom];
- am.frame = CGRectMake(0, 0, 25, 25);
- [am setImage:[UIImage imageNamed:@"ZSSpicker.png" inBundle:[NSBundle bundleForClass:[ZSSRichTextEditor class]] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
- [am addTarget:self action:@selector(showInsertImageAlternatePicker) forControlEvents:UIControlEventTouchUpInside];
-
- if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.placeholder = NSLocalizedString(@"URL (required)", nil);
- if (url) {
- textField.text = url;
- }
- textField.rightView = am;
- textField.rightViewMode = UITextFieldViewModeAlways;
- textField.clearButtonMode = UITextFieldViewModeAlways;
- }];
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.placeholder = NSLocalizedString(@"Alt", nil);
- textField.clearButtonMode = UITextFieldViewModeAlways;
- textField.secureTextEntry = NO;
- if (alt) {
- textField.text = alt;
- }
- }];
- [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
- [self focusTextEditor];
- }]];
- [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
-
- UITextField *imageURL = [alertController.textFields objectAtIndex:0];
- UITextField *alt = [alertController.textFields objectAtIndex:1];
- if (!self.selectedImageURL) {
- [self insertImage:imageURL.text alt:alt.text];
- } else {
- [self updateImage:imageURL.text alt:alt.text];
- }
- [self focusTextEditor];
- }]];
- [self presentViewController:alertController animated:YES completion:NULL];
-
- } else {
-
- self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
- self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
- self.alertView.tag = 1;
- UITextField *imageURL = [self.alertView textFieldAtIndex:0];
- imageURL.placeholder = NSLocalizedString(@"URL (required)", nil);
- if (url) {
- imageURL.text = url;
- }
-
- imageURL.rightView = am;
- imageURL.rightViewMode = UITextFieldViewModeAlways;
- imageURL.clearButtonMode = UITextFieldViewModeAlways;
-
- UITextField *alt1 = [self.alertView textFieldAtIndex:1];
- alt1.secureTextEntry = NO;
- alt1.placeholder = NSLocalizedString(@"Alt", nil);
- alt1.clearButtonMode = UITextFieldViewModeAlways;
- if (alt) {
- alt1.text = alt;
- }
-
- [self.alertView show];
- }
-
- }
- - (void)showInsertImageDialogFromDeviceWithScale:(CGFloat)scale alt:(NSString *)alt {
-
- // Insert button title
- NSString *insertButtonTitle = !self.selectedImageURL ? NSLocalizedString(@"Pick Image", nil) : NSLocalizedString(@"Pick New Image", nil);
-
- //If the OS version supports the new UIAlertController go for it. Otherwise use the old UIAlertView
- if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Insert Image From Device", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
-
- //Add alt text field
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.placeholder = NSLocalizedString(@"Alt", nil);
- textField.clearButtonMode = UITextFieldViewModeAlways;
- textField.secureTextEntry = NO;
- if (alt) {
- textField.text = alt;
- }
- }];
-
- //Add scale text field
- [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
- textField.clearButtonMode = UITextFieldViewModeAlways;
- textField.secureTextEntry = NO;
- textField.placeholder = NSLocalizedString(@"Image scale, 0.5 by default", nil);
- textField.keyboardType = UIKeyboardTypeDecimalPad;
- }];
-
- //Cancel action
- [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
- [self focusTextEditor];
- }]];
-
- //Insert action
- [alertController addAction:[UIAlertAction actionWithTitle:insertButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
- UITextField *textFieldAlt = [alertController.textFields objectAtIndex:0];
- UITextField *textFieldScale = [alertController.textFields objectAtIndex:1];
-
- self.selectedImageScale = [textFieldScale.text floatValue]?:kDefaultScale;
- self.selectedImageAlt = textFieldAlt.text?:@"";
-
- [self presentViewController:self.imagePicker animated:YES completion:nil];
-
- }]];
-
- [self presentViewController:alertController animated:YES completion:NULL];
-
- } else {
-
- self.alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Insert Image", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:insertButtonTitle, nil];
- self.alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
- self.alertView.tag = 3;
-
- UITextField *textFieldAlt = [self.alertView textFieldAtIndex:0];
- textFieldAlt.secureTextEntry = NO;
- textFieldAlt.placeholder = NSLocalizedString(@"Alt", nil);
- textFieldAlt.clearButtonMode = UITextFieldViewModeAlways;
- if (alt) {
- textFieldAlt.text = alt;
- }
-
- UITextField *textFieldScale = [self.alertView textFieldAtIndex:1];
- textFieldScale.placeholder = NSLocalizedString(@"Image scale, 0.5 by default", nil);
- textFieldScale.keyboardType = UIKeyboardTypeDecimalPad;
-
- [self.alertView show];
- }
-
- }
- - (void)insertImage:(NSString *)url alt:(NSString *)alt {
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertImage(\"%@\", \"%@\");", url, alt];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)updateImage:(NSString *)url alt:(NSString *)alt {
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateImage(\"%@\", \"%@\");", url, alt];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)insertImageBase64String:(NSString *)imageBase64String alt:(NSString *)alt {
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.insertImageBase64String(\"%@\", \"%@\");", imageBase64String, alt];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)updateImageBase64String:(NSString *)imageBase64String alt:(NSString *)alt {
- NSString *trigger = [NSString stringWithFormat:@"zss_editor.updateImageBase64String(\"%@\", \"%@\");", imageBase64String, alt];
- [self.editorView evaluateJavaScript:trigger completionHandler:^(NSString *result, NSError *error) {
-
- }];
- }
- - (void)updateToolBarWithButtonName:(NSString *)name {
-
- // Items that are enabled
- NSArray *itemNames = [name componentsSeparatedByString:@","];
-
- // Special case for link
- NSMutableArray *itemsModified = [[NSMutableArray alloc] init];
- for (NSString *linkItem in itemNames) {
- NSString *updatedItem = linkItem;
- if ([linkItem hasPrefix:@"link:"]) {
- updatedItem = @"link";
- self.selectedLinkURL = [linkItem stringByReplacingOccurrencesOfString:@"link:" withString:@""];
- } else if ([linkItem hasPrefix:@"link-title:"]) {
- self.selectedLinkTitle = [self stringByDecodingURLFormat:[linkItem stringByReplacingOccurrencesOfString:@"link-title:" withString:@""]];
- } else if ([linkItem hasPrefix:@"image:"]) {
- updatedItem = @"image";
- self.selectedImageURL = [linkItem stringByReplacingOccurrencesOfString:@"image:" withString:@""];
- } else if ([linkItem hasPrefix:@"image-alt:"]) {
- self.selectedImageAlt = [self stringByDecodingURLFormat:[linkItem stringByReplacingOccurrencesOfString:@"image-alt:" withString:@""]];
- } else {
- self.selectedImageURL = nil;
- self.selectedImageAlt = nil;
- self.selectedLinkURL = nil;
- self.selectedLinkTitle = nil;
- }
- [itemsModified addObject:updatedItem];
- }
- itemNames = [NSArray arrayWithArray:itemsModified];
-
- self.editorItemsEnabled = itemNames;
-
- // Highlight items
- NSArray *items = self.toolbar.items;
- for (ZSSBarButtonItem *item in items) {
- if ([itemNames containsObject:item.label]) {
- item.tintColor = [self barButtonItemSelectedDefaultColor];
- } else {
- item.tintColor = [self barButtonItemDefaultColor];
- }
- }
-
- }
- #pragma mark - UITextView Delegate
- - (void)textViewDidChange:(UITextView *)textView {
- CGRect line = [textView caretRectForPosition:textView.selectedTextRange.start];
- CGFloat overflow = line.origin.y + line.size.height - ( textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top );
- if ( overflow > 0 ) {
- // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
- // Scroll caret to visible area
- CGPoint offset = textView.contentOffset;
- offset.y += overflow + 7; // leave 7 pixels margin
- // Cannot animate with setContentOffset:animated: or caret will not appear
- [UIView animateWithDuration:.2 animations:^{
- [textView setContentOffset:offset];
- }];
- }
-
- }
- #pragma mark - WKScriptMessageHandler Delegate
- - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
- NSString *messageString = (NSString *)message.body;
- NSLog(@"Message received: %@", messageString);
-
- /*
-
- Callback for when text is changed, written by @madebydouglas derived from richardortiz84 https://github.com/nnhubbard/ZSSRichTextEditor/issues/5
-
- */
-
- if ([messageString isEqualToString:@"paste"]) {
- self.editorPaste = YES;
- }
-
- if ([messageString isEqualToString:@"input"]) {
-
- if (_receiveEditorDidChangeEvents) {
- [self updateEditor];
- }
-
- [self getText:^(NSString * result, NSError * _Nullable error) {
- [self checkForMentionOrHashtagInText:result];
- }];
-
- if (self.editorPaste) {
- [self blurTextEditor];
- self.editorPaste = NO;
- }
- }
- }
- #pragma mark - WKNavigationDelegate Delegate
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
-
-
- NSString *query = [navigationAction.request.URL query];
-
- NSString *urlString = [navigationAction.request.URL absoluteString];
- decisionHandler(WKNavigationActionPolicyAllow);
- NSLog(@"web request");
- NSLog(@"%@", urlString);
- NSLog(@"%@", query);
-
- if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
- //On the old UIWebView delegate it returned false Bool here
- //TODO: what should we do now?
-
- } else if ([urlString rangeOfString:@"callback://0/"].location != NSNotFound) {
-
- // We recieved the callback
- NSString *className = [urlString stringByReplacingOccurrencesOfString:@"callback://0/" withString:@""];
- [self updateToolBarWithButtonName:className];
-
- } else if ([urlString rangeOfString:@"debug://"].location != NSNotFound) {
-
- NSLog(@"Debug Found");
-
- // We recieved the callback
- NSString *debug = [urlString stringByReplacingOccurrencesOfString:@"debug://" withString:@""];
- debug = [debug stringByReplacingPercentEscapesUsingEncoding:NSStringEncodingConversionAllowLossy];
- NSLog(@"%@", debug);
-
- } else if ([urlString rangeOfString:@"scroll://"].location != NSNotFound) {
-
- NSInteger position = [[urlString stringByReplacingOccurrencesOfString:@"scroll://" withString:@""] integerValue];
- [self editorDidScrollWithPosition:position];
-
- }
-
- }
- - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
- self.editorLoaded = YES;
-
- if (!self.internalHTML) {
- self.internalHTML = @"";
- }
- [self updateHTML];
-
- if(self.placeholder) {
- [self setPlaceholderText];
- }
-
- if (self.customCSS) {
- [self updateCSS];
- }
-
- if (self.shouldShowKeyboard) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self focusTextEditor];
- });
- }
-
- /*
-
- Create listeners for when text is changed, solution by @madebydouglas derived from richardortiz84 https://github.com/nnhubbard/ZSSRichTextEditor/issues/5
-
- */
-
- NSString *inputListener = @"document.getElementById('zss_editor_content').addEventListener('input', function() {window.webkit.messageHandlers.jsm.postMessage('input');});";
- NSString *pasteListener = @"document.getElementById('zss_editor_content').addEventListener('paste', function() {window.webkit.messageHandlers.jsm.postMessage('paste');});";
-
- [self.editorView evaluateJavaScript:inputListener completionHandler:^(NSString *result, NSError *error) {
- if (error != NULL) {
- NSLog(@"%@", error);
- }
- }];
-
- [self.editorView evaluateJavaScript:pasteListener completionHandler:^(NSString *result, NSError *error) {
- if (error != NULL) {
- NSLog(@"%@", error);
- }
- }];
- }
- #pragma mark - Mention & Hashtag Support Section
- - (void)checkForMentionOrHashtagInText:(NSString *)text {
-
- if ([text containsString:@" "] && [text length] > 0) {
-
- NSString *lastWord = nil;
- NSString *matchedWord = nil;
- BOOL ContainsHashtag = NO;
- BOOL ContainsMention = NO;
-
- NSRange range = [text rangeOfString:@" " options:NSBackwardsSearch];
- lastWord = [text substringFromIndex:range.location];
-
- if (lastWord != nil) {
-
- //Check if last word typed starts with a #
- NSRegularExpression *hashtagRegex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:nil];
- NSArray *hashtagMatches = [hashtagRegex matchesInString:lastWord options:0 range:NSMakeRange(0, lastWord.length)];
-
- for (NSTextCheckingResult *match in hashtagMatches) {
-
- NSRange wordRange = [match rangeAtIndex:1];
- NSString *word = [lastWord substringWithRange:wordRange];
- matchedWord = word;
- ContainsHashtag = YES;
-
- }
-
- if (!ContainsHashtag) {
-
- //Check if last word typed starts with a @
- NSRegularExpression *mentionRegex = [NSRegularExpression regularExpressionWithPattern:@"@(\\w+)" options:0 error:nil];
- NSArray *mentionMatches = [mentionRegex matchesInString:lastWord options:0 range:NSMakeRange(0, lastWord.length)];
-
- for (NSTextCheckingResult *match in mentionMatches) {
-
- NSRange wordRange = [match rangeAtIndex:1];
- NSString *word = [lastWord substringWithRange:wordRange];
- matchedWord = word;
- ContainsMention = YES;
-
- }
-
- }
-
- }
-
- if (ContainsHashtag) {
-
- [self hashtagRecognizedWithWord:matchedWord];
-
- }
-
- if (ContainsMention) {
-
- [self mentionRecognizedWithWord:matchedWord];
-
- }
-
- }
-
- }
- #pragma mark - Callbacks
- //Blank implementation
- - (void)editorDidScrollWithPosition:(NSInteger)position {}
- //Blank implementation
- - (void)editorDidChangeWithText:(NSString *)text andHTML:(NSString *)html {}
- //Blank implementation
- - (void)hashtagRecognizedWithWord:(NSString *)word {}
- //Blank implementation
- - (void)mentionRecognizedWithWord:(NSString *)word {}
- #pragma mark - AlertView
- - (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView {
-
- if (alertView.tag == 1) {
- UITextField *textField = [alertView textFieldAtIndex:0];
- UITextField *textField2 = [alertView textFieldAtIndex:1];
- if ([textField.text length] == 0 || [textField2.text length] == 0) {
- return NO;
- }
- } else if (alertView.tag == 2) {
- UITextField *textField = [alertView textFieldAtIndex:0];
- if ([textField.text length] == 0) {
- return NO;
- }
- }
-
- return YES;
- }
- - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
-
- if (alertView.tag == 1) {
- if (buttonIndex == 1) {
- UITextField *imageURL = [alertView textFieldAtIndex:0];
- UITextField *alt = [alertView textFieldAtIndex:1];
- if (!self.selectedImageURL) {
- [self insertImage:imageURL.text alt:alt.text];
- } else {
- [self updateImage:imageURL.text alt:alt.text];
- }
- }
- } else if (alertView.tag == 2) {
- if (buttonIndex == 1) {
- UITextField *linkURL = [alertView textFieldAtIndex:0];
- UITextField *title = [alertView textFieldAtIndex:1];
- if (!self.selectedLinkURL) {
- [self insertLink:linkURL.text title:title.text];
- } else {
- [self updateLink:linkURL.text title:title.text];
- }
- }
- } else if (alertView.tag == 3) {
- if (buttonIndex == 1) {
- UITextField *textFieldAlt = [alertView textFieldAtIndex:0];
- UITextField *textFieldScale = [alertView textFieldAtIndex:1];
-
- self.selectedImageScale = [textFieldScale.text floatValue]?:kDefaultScale;
- self.selectedImageAlt = textFieldAlt.text?:@"";
-
- [self presentViewController:self.imagePicker animated:YES completion:nil];
-
- }
- }
- }
- #pragma mark - Asset Picker
- - (void)showInsertURLAlternatePicker {
- // Blank method. User should implement this in their subclass
- }
- - (void)showInsertImageAlternatePicker {
- // Blank method. User should implement this in their subclass
- }
- #pragma mark - Image Picker Delegate
- - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
- //Dismiss the Image Picker
- [picker.presentingViewController dismissViewControllerAnimated:YES completion:nil];
- }
- - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info{
-
- UIImage *selectedImage = info[UIImagePickerControllerEditedImage]?:info[UIImagePickerControllerOriginalImage];
-
- //Scale the image
- CGSize targetSize = CGSizeMake(selectedImage.size.width * self.selectedImageScale, selectedImage.size.height * self.selectedImageScale);
- UIGraphicsBeginImageContext(targetSize);
- [selectedImage drawInRect:CGRectMake(0,0,targetSize.width,targetSize.height)];
- UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //Compress the image, as it is going to be encoded rather than linked
- NSData *scaledImageData = UIImageJPEGRepresentation(scaledImage, kJPEGCompression);
-
- //Encode the image data as a base64 string
- NSString *imageBase64String = [scaledImageData base64EncodedStringWithOptions:0];
-
- //Decide if we have to insert or update
- if (!self.imageBase64String) {
- [self insertImageBase64String:imageBase64String alt:self.selectedImageAlt];
- } else {
- [self updateImageBase64String:imageBase64String alt:self.selectedImageAlt];
- }
-
- self.imageBase64String = imageBase64String;
-
- //Dismiss the Image Picker
- [picker.presentingViewController dismissViewControllerAnimated:YES completion:nil];
- }
- #pragma mark - Keyboard status
- - (void)keyboardWillShowOrHide:(NSNotification *)notification {
- // User Info
- NSDictionary *info = notification.userInfo;
- CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
- int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
- CGRect keyboardEnd = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
-
- // Toolbar Sizes
- CGFloat sizeOfToolbar = self.toolbarHolder.frame.size.height;
-
- // Keyboard Size
- CGFloat keyboardHeight = keyboardEnd.size.height;
-
- // Correct Curve
- UIViewAnimationOptions animationOptions = curve << 16;
-
- const int extraHeight = 10;
-
- if (keyboardEnd.origin.y < [[UIScreen mainScreen] bounds].size.height) {
-
- [UIView animateWithDuration:duration delay:0 options:animationOptions animations:^{
-
- // Toolbar
- CGRect toolbarFrame = self.toolbarHolder.frame;
- CGRect kbRect = [self.toolbarHolder.superview convertRect:keyboardEnd fromView:nil];
- toolbarFrame.origin.y = kbRect.origin.y - sizeOfToolbar;
- self.toolbarHolder.frame = toolbarFrame;
-
- // Editor View
- CGRect editorFrame = self.editorView.frame;
- editorFrame.size.height = toolbarFrame.origin.y - extraHeight;
- self.editorView.frame = editorFrame;
- self.editorViewFrame = self.editorView.frame;
- self.editorView.scrollView.contentInset = UIEdgeInsetsZero;
- self.editorView.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
-
- // Source View
- CGRect sourceFrame = self.sourceView.frame;
- sourceFrame.size.height = (self.view.frame.size.height - keyboardHeight) - sizeOfToolbar - extraHeight;
- self.sourceView.frame = sourceFrame;
-
- // Provide editor with keyboard height and editor view height
- [self setFooterHeight:(keyboardHeight - 8)];
- [self setContentHeight: self.editorViewFrame.size.height];
-
- } completion:nil];
-
- } else {
-
- [UIView animateWithDuration:duration delay:0 options:animationOptions animations:^{
-
- CGRect frame = self.toolbarHolder.frame;
-
- if (self->_alwaysShowToolbar) {
- CGFloat bottomSafeAreaInset = 0.0;
- if (@available(iOS 11.0, *)) {
- bottomSafeAreaInset = self.view.safeAreaInsets.bottom;
- }
- frame.origin.y = self.view.frame.size.height - sizeOfToolbar - bottomSafeAreaInset;
- } else {
- frame.origin.y = self.view.frame.size.height + keyboardHeight;
- }
-
- self.toolbarHolder.frame = frame;
-
- // Editor View
- CGRect editorFrame = self.editorView.frame;
-
- if (self->_alwaysShowToolbar) {
- editorFrame.size.height = ((self.view.frame.size.height - sizeOfToolbar) - extraHeight);
- } else {
- editorFrame.size.height = self.view.frame.size.height;
- }
-
- self.editorView.frame = editorFrame;
- self.editorViewFrame = self.editorView.frame;
- self.editorView.scrollView.contentInset = UIEdgeInsetsZero;
- self.editorView.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
-
- // Source View
- CGRect sourceFrame = self.sourceView.frame;
-
- if (self->_alwaysShowToolbar) {
- sourceFrame.size.height = ((self.view.frame.size.height - sizeOfToolbar) - extraHeight);
- } else {
- sourceFrame.size.height = self.view.frame.size.height;
- }
-
- self.sourceView.frame = sourceFrame;
-
- [self setFooterHeight:0];
- [self setContentHeight:self.editorViewFrame.size.height];
-
- } completion:nil];
-
- }
-
- }
- #pragma mark - Utilities
- - (NSString *)removeQuotesFromHTML:(NSString *)html {
- html = [html stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
- html = [html stringByReplacingOccurrencesOfString:@"“" withString:@"""];
- html = [html stringByReplacingOccurrencesOfString:@"”" withString:@"""];
- html = [html stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
- html = [html stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
- return html;
- }
- - (void)tidyHTML:(NSString *)html completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler {
- html = [html stringByReplacingOccurrencesOfString:@"<br>" withString:@"<br />"];
- html = [html stringByReplacingOccurrencesOfString:@"<hr>" withString:@"<hr />"];
- if (self.formatHTML) {
-
- html = [NSString stringWithFormat:@"style_html(\"%@\");", html];
- [self.editorView evaluateJavaScript:html completionHandler:^(NSString *result, NSError *error) {
-
- if (error != NULL) {
- NSLog(@"HTML Tidying Error: %@", error);
- }
-
- NSLog(@"%@", result);
-
- completionHandler(result, error);
- }];
-
- } else {
- completionHandler(html, NULL);
- }
- }
- - (UIColor *)barButtonItemDefaultColor {
-
- if (self.toolbarItemTintColor) {
- return self.toolbarItemTintColor;
- }
-
- return [UIColor colorWithRed:0.0f/255.0f green:122.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
- }
- - (UIColor *)barButtonItemSelectedDefaultColor {
-
- if (self.toolbarItemSelectedTintColor) {
- return self.toolbarItemSelectedTintColor;
- }
-
- return [UIColor blackColor];
- }
- - (BOOL)isIpad {
- return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
- }
- - (NSString *)stringByDecodingURLFormat:(NSString *)string {
- NSString *result = [string stringByReplacingOccurrencesOfString:@"+" withString:@" "];
- result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- return result;
- }
- - (void)enableToolbarItems:(BOOL)enable {
- NSArray *items = self.toolbar.items;
- for (ZSSBarButtonItem *item in items) {
- if (![item.label isEqualToString:@"source"]) {
- item.enabled = enable;
- }
- }
- }
- #pragma mark - Memory Warning Section
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- }
- @end
|