ZSSTextView.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // ZSSTextView.m
  3. // ZSSRichTextEditor
  4. //
  5. // Created by Nicholas Hubbard on 1/29/14.
  6. // Copyright (c) 2014 Zed Said Studio. All rights reserved.
  7. //
  8. #import "ZSSTextView.h"
  9. #import <CoreText/CoreText.h>
  10. #define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f]
  11. @implementation ZSSTextView
  12. - (id)initWithFrame:(CGRect)frame
  13. {
  14. self = [super initWithFrame:frame];
  15. if (self) {
  16. [self commonSetup];
  17. }
  18. return self;
  19. }
  20. - (void)commonSetup
  21. {
  22. _defaultFont = [UIFont systemFontOfSize:14.0f];
  23. _boldFont = [UIFont boldSystemFontOfSize:14.0f];
  24. _italicFont = [UIFont fontWithName:@"HelveticaNeue-Oblique" size:14.0f];
  25. self.font = _defaultFont;
  26. [self addObserver:self forKeyPath:NSStringFromSelector(@selector(defaultFont)) options:NSKeyValueObservingOptionNew context:0];
  27. [self addObserver:self forKeyPath:NSStringFromSelector(@selector(boldFont)) options:NSKeyValueObservingOptionNew context:0];
  28. [self addObserver:self forKeyPath:NSStringFromSelector(@selector(italicFont)) options:NSKeyValueObservingOptionNew context:0];
  29. if (_italicFont == nil && ([UIFontDescriptor class] != nil))
  30. {
  31. // This works around a bug in 7.0.3 where HelveticaNeue-Italic is not present as a UIFont option
  32. _italicFont = (__bridge_transfer UIFont*)CTFontCreateWithName(CFSTR("HelveticaNeue-Italic"), 14.0f, NULL);
  33. }
  34. self.tokens = [self solverTokens];
  35. }
  36. - (NSArray *)solverTokens
  37. {
  38. NSArray *solverTokens = @[
  39. [CYRToken tokenWithName:@"html_tags"
  40. expression:@"(<\\/?[a-z][^<>]*>)"
  41. attributes:@{
  42. NSForegroundColorAttributeName : RGB(25, 0, 151)}],
  43. [CYRToken tokenWithName:@"a_tag"
  44. expression:@"(<\\/?[a][^<>]*>)"
  45. attributes:@{
  46. NSForegroundColorAttributeName : RGB(24, 104, 10)}],
  47. [CYRToken tokenWithName:@"img_tag"
  48. expression:@"(<\\/?[img][^<>]*>)"
  49. attributes:@{
  50. NSForegroundColorAttributeName : RGB(148, 0, 151)}],
  51. [CYRToken tokenWithName:@"html_entities"
  52. expression:@"(&#34;|&#38;|&#39;|&#60;|&#62;|&#160;|&#161;|&#162;|&#163;|&#164;|&#165;|&#166;|&#167;|&#168;|&#169;|&#170;|&#171;|&#172;|&#173;|&#174;|&#175;|&#176;|&#177;|&#178;|&#179;|&#180;|&#181;|&#182;|&#183;|&#184;|&#185;|&#186;|&#187;|&#188;|&#189;|&#190;|&#191;|&#192;|&#193;|&#194;|&#195;|&#196;|&#197;|&#198;|&#199;|&#200;|&#201;|&#202;|&#203;|&#204;|&#205;|&#206;|&#207;|&#208;|&#209;|&#210;|&#211;|&#212;|&#213;|&#214;|&#215;|&#216;|&#217;|&#218;|&#219;|&#220;|&#221;|&#222;|&#223;|&#224;|&#225;|&#226;|&#227;|&#228;|&#229;|&#230;|&#231;|&#232;|&#233;|&#234;|&#235;|&#236;|&#237;|&#238;|&#239;|&#240;|&#241;|&#242;|&#243;|&#244;|&#245;|&#246;|&#247;|&#248;|&#249;|&#250;|&#251;|&#252;|&#253;|&#254;|&#255;|&#338;|&#339;|&#352;|&#353;|&#376;|&#402;|&#710;|&#732;|&#913;|&#914;|&#915;|&#916;|&#917;|&#918;|&#919;|&#920;|&#921;|&#922;|&#923;|&#924;|&#925;|&#926;|&#927;|&#928;|&#929;|&#931;|&#932;|&#933;|&#934;|&#935;|&#936;|&#937;|&#945;|&#946;|&#947;|&#948;|&#949;|&#950;|&#951;|&#952;|&#953;|&#954;|&#955;|&#956;|&#957;|&#958;|&#959;|&#960;|&#961;|&#962;|&#963;|&#964;|&#965;|&#966;|&#967;|&#968;|&#969;|&#977;|&#978;|&#982;|&#8194;|&#8195;|&#8201;|&#8204;|&#8205;|&#8206;|&#8207;|&#8211;|&#8212;|&#8216;|&#8217;|&#8218;|&#8220;|&#8221;|&#8222;|&#8224;|&#8225;|&#8226;|&#8230;|&#8240;|&#8242;|&#8243;|&#8249;|&#8250;|&#8254;|&#8260;|&#8364;|&#8465;|&#8472;|&#8476;|&#8482;|&#8501;|&#8592;|&#8593;|&#8594;|&#8595;|&#8596;|&#8629;|&#8656;|&#8657;|&#8658;|&#8659;|&#8660;|&#8704;|&#8706;|&#8707;|&#8709;|&#8711;|&#8712;|&#8713;|&#8715;|&#8719;|&#8721;|&#8722;|&#8727;|&#8730;|&#8733;|&#8734;|&#8736;|&#8743;|&#8744;|&#8745;|&#8746;|&#8747;|&#8756;|&#8764;|&#8773;|&#8776;|&#8800;|&#8801;|&#8804;|&#8805;|&#8834;|&#8835;|&#8836;|&#8838;|&#8839;|&#8853;|&#8855;|&#8869;|&#8901;|&#8968;|&#8969;|&#8970;|&#8971;|&#9001;|&#9002;|&#9674;|&#9824;|&#9827;|&#9829;|&#9830;|&quot;|&amp;|&apos;|&lt;|&gt;|&nbsp;|&iexcl;|&cent;|&pound;|&curren;|&yen;|&brvbar;|&sect;|&uml;|&copy;|&ordf;|&laquo;|&not;|&shy;|&reg;|&macr;|&deg;|&plusmn;|&sup2;|&sup3;|&acute;|&micro;|&para;|&middot;|&cedil;|&sup1;|&ordm;|&raquo;|&frac14;|&frac12;|&frac34;|&iquest;|&Agrave;|&Aacute;|&Acirc;|&Atilde;|&Auml;|&Aring;|&AElig;|&Ccedil;|&Egrave;|&Eacute;|&Ecirc;|&Euml;|&Igrave;|&Iacute;|&Icirc;|&Iuml;|&ETH;|&Ntilde;|&Ograve;|&Oacute;|&Ocirc;|&Otilde;|&Ouml;|&times;|&Oslash;|&Ugrave;|&Uacute;|&Ucirc;|&Uuml;|&Yacute;|&THORN;|&szlig;|&agrave;|&aacute;|&acirc;|&atilde;|&auml;|&aring;|&aelig;|&ccedil;|&egrave;|&eacute;|&ecirc;|&euml;|&igrave;|&iacute;|&icirc;|&iuml;|&eth;|&ntilde;|&ograve;|&oacute;|&ocirc;|&otilde;|&ouml;|&divide;|&oslash;|&Ugrave;|&Uacute;|&Ucirc;|&Uuml;|&yacute;|&thorn;|&yuml;|&OElig;|&oelig;|&Scaron;|&scaron;|&Yuml;|&fnof;|&circ;|&tilde;|&Alpha;|&Beta;|&Gamma;|&Delta;|&Epsilon;|&Zeta;|&Eta;|&Theta;|&Iota;|&Kappa;|&Lambda;|&Mu;|&Nu;|&Xi;|&Omicron;|&Pi;|&Rho;|&Sigma;|&Tau;|&Upsilon;|&Phi;|&Chi;|&Psi;|&Omega;|&alpha;|&beta;|&gamma;|&delta;|&epsilon;|&zeta;|&eta;|&theta;|&iota;|&kappa;|&lambda;|&mu;|&nu;|&xi;|&omicron;|&pi;|&rho;|&sigmaf;|&sigma;|&tau;|&upsilon;|&phi;|&chi;|&psi;|&omega;|&thetasym;|&Upsih;|&piv;|&ensp;|&emsp;|&thinsp;|&zwnj;|&zwj;|&lrm;|&rlm;|&ndash;|&mdash;|&lsquo;|&rsquo;|&sbquo;|&ldquo;|&rdquo;|&bdquo;|&dagger;|&Dagger;|&bull;|&hellip;|&permil;|&prime;|&Prime;|&lsaquo;|&rsaquo;|&oline;|&frasl;|&euro;|&image;|&weierp;|&real;|&trade;|&alefsym;|&larr;|&uarr;|&rarr;|&darr;|&harr;|&crarr;|&lArr;|&UArr;|&rArr;|&dArr;|&hArr;|&forall;|&part;|&exist;|&empty;|&nabla;|&isin;|&notin;|&ni;|&prod;|&sum;|&minus;|&lowast;|&radic;|&prop;|&infin;|&ang;|&and;|&or;|&cap;|&cup;|&int;|&there4;|&sim;|&cong;|&asymp;|&ne;|&equiv;|&le;|&ge;|&sub;|&sup;|&nsub;|&sube;|&supe;|&oplus;|&otimes;|&perp;|&sdot;|&lceil;|&rceil;|&lfloor;|&rfloor;|&lang;|&rang;|&loz;|&spades;|&clubs;|&hearts;|&diams;)"
  53. attributes:@{
  54. NSForegroundColorAttributeName : [UIColor blackColor],
  55. NSFontAttributeName: self.boldFont,
  56. NSDocumentTypeDocumentAttribute: NSPlainTextDocumentType}],
  57. [CYRToken tokenWithName:@"comment"
  58. expression:@"<!--(.*?)-->"
  59. attributes:@{
  60. NSForegroundColorAttributeName : RGB(31, 131, 0),
  61. NSFontAttributeName : self.italicFont
  62. }],
  63. [CYRToken tokenWithName:@"attributes"
  64. expression:@"(?<==)('|\").*?\\1(?=.*?>)"
  65. attributes:@{
  66. NSForegroundColorAttributeName : RGB(0, 12, 255)
  67. }]
  68. ];
  69. return solverTokens;
  70. }
  71. #pragma mark - Cleanup
  72. - (void)dealloc {
  73. [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(defaultFont))];
  74. [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(boldFont))];
  75. [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(italicFont))];
  76. }
  77. #pragma mark - KVO
  78. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  79. {
  80. if ([keyPath isEqualToString:NSStringFromSelector(@selector(defaultFont))] ||
  81. [keyPath isEqualToString:NSStringFromSelector(@selector(boldFont))] ||
  82. [keyPath isEqualToString:NSStringFromSelector(@selector(italicFont))])
  83. {
  84. // Reset the tokens, this will clear any existing formatting
  85. self.tokens = [self solverTokens];
  86. }
  87. else
  88. {
  89. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  90. }
  91. }
  92. #pragma mark - Overrides
  93. - (void)setDefaultFont:(UIFont *)defaultFont
  94. {
  95. _defaultFont = defaultFont;
  96. self.font = defaultFont;
  97. }
  98. @end