Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 315 lines (246 sloc) 8.702 kB
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
1 //
2 // KSHTMLWriter.m
3 // Sandvox
4 //
5 // Created by Mike on 23/02/2010.
6 // Copyright 2010 Karelia Software. All rights reserved.
7 //
8
9 #import "KSHTMLWriter.h"
10
11
12 @implementation KSHTMLWriter
13
72adfa1 @mikeabdullah Documenting .isXHTML generation better.
mikeabdullah authored
14 #pragma mark Creating an HTML Writer
15
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
16 - (id)initWithOutputWriter:(id <KSWriter>)stream;
17 {
18 [super initWithOutputWriter:stream];
19 _isXHTML = YES;
20 return self;
21 }
22
23 - (id)initWithOutputWriter:(id <KSWriter>)stream isXHTML:(BOOL)isXHTML;
24 {
25 if (self = [self initWithOutputWriter:stream])
26 {
27 _isXHTML = isXHTML;
28 }
29
30 return self;
31 }
32
72adfa1 @mikeabdullah Documenting .isXHTML generation better.
mikeabdullah authored
33 #pragma mark XHTML
34
35 @synthesize XHTML = _isXHTML;
36
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
37 #pragma mark Document
38
39 - (void)startDocument:(NSString *)DTD isXHTML:(BOOL)isXHTML;
40 {
41 _isXHTML = isXHTML;
42 [self startDocument:DTD];
43 }
44
45 #pragma mark HTML Fragments
46
47 - (void)writeHTMLString:(NSString *)html;
48 {
49 [self writeString:html];
50 }
51
52 - (void)writeHTMLFormat:(NSString *)format , ...
53 {
54 va_list argList;
55 va_start(argList, format);
56 NSString *aString = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
57 va_end(argList);
58
59 [self writeHTMLString:aString];
60 }
61
62 #pragma mark General
63
64 - (void)startElement:(NSString *)tagName;
65 {
66 [self startElement:tagName className:nil];
67 }
68
69 - (void)startElement:(NSString *)tagName className:(NSString *)className;
70 {
71 [self startElement:tagName idName:nil className:className];
72 }
73
74 - (void)startElement:(NSString *)tagName idName:(NSString *)idName className:(NSString *)className;
75 {
76 [self openTag:tagName];
77 if (idName) [self writeAttribute:@"id" value:idName];
78 if (className) [self writeAttribute:@"class" value:className];
79 [self didStartElement];
80 }
81
82 #pragma mark Line Break
83
84 - (void)writeLineBreak;
85 {
86 [self startElement:@"br"];
87 [self endElement];
88 }
89
90 #pragma mark Higher-level Tag Writing
91
92 - (void)startAnchorElementWithHref:(NSString *)href title:(NSString *)titleString target:(NSString *)targetString rel:(NSString *)relString;
93 {
94 [self openTag:@"a"];
95 if (href) [self writeAttribute:@"href" value:href];
96 if (targetString) [self writeAttribute:@"target" value:targetString];
97 if (titleString) [self writeAttribute:@"title" value:titleString];
98 if (relString) [self writeAttribute:@"rel" value:relString];
99 [self didStartElement];
100 }
101
102 - (void)writeImageWithIdName:(NSString *)idName
103 className:(NSString *)className
104 src:(NSString *)src
105 alt:(NSString *)alt
106 width:(NSString *)width
107 height:(NSString *)height;
108 {
109 [self openTag:@"img"];
110
111 if (idName) [self writeAttribute:@"id" value:idName];
112 if (className) [self writeAttribute:@"class" value:className];
113
114 [self writeAttribute:@"src" value:src];
115 [self writeAttribute:@"alt" value:alt];
116 if (width) [self writeAttribute:@"width" value:width];
117 if (height) [self writeAttribute:@"height" value:height];
118
119 [self didStartElement];
120 [self endElement];
121 }
122
123 // TODO: disable indentation & newlines when we are in an anchor tag, somehow.
124
125 #pragma mark Link
126
127 - (void)writeLinkWithHref:(NSString *)href
128 type:(NSString *)type
129 rel:(NSString *)rel
130 title:(NSString *)title
131 media:(NSString *)media;
132 {
133 [self openTag:@"link"];
134
135 if (rel) [self writeAttribute:@"rel" value:rel];
136 if (type) [self writeAttribute:@"type" value:type];
137 [self writeAttribute:@"href" value:href];
138 if (title) [self writeAttribute:@"title" value:title];
139 if (media) [self writeAttribute:@"media" value:media];
140
141 [self didStartElement];
142 [self endElement];
143 }
144
145 - (void)writeLinkToStylesheet:(NSString *)href
146 title:(NSString *)title
147 media:(NSString *)media;
148 {
149 [self writeLinkWithHref:href type:@"text/css" rel:@"stylesheet" title:title media:media];
150 }
151
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
152 #pragma mark Scripts
153
37c85e9 @mikeabdullah -writeJavascriptWithSrc: actually makes more sense.
mikeabdullah authored
154 - (void)writeJavascriptWithSrc:(NSString *)src;
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
155 {
37c85e9 @mikeabdullah -writeJavascriptWithSrc: actually makes more sense.
mikeabdullah authored
156 [self openTag:@"script"];
157 [self writeAttribute:@"type" value:@"text/javascript"]; // in theory, HTML5 pages could omit this
158 [self writeAttribute:@"src" value:src];
159 [self didStartElement];
160
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
161 [self endElement];
162 }
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
163
4d9ca24 @mikeabdullah -writeJavascript:useCDATA: convenience method.
mikeabdullah authored
164 - (void)writeJavascript:(NSString *)script useCDATA:(BOOL)useCDATA;
165 {
166 [self openTag:@"script"];
167 [self writeAttribute:@"type" value:@"text/javascript"]; // in theory, HTML5 pages could omit this
168 [self didStartElement];
169
170 if (useCDATA) [self startJavascriptCDATA];
171
172 [self writeString:@"\n"];
173 [self writeString:script];
174 [self writeString:@"\n"];
175
176 if (useCDATA) [self endJavascriptCDATA];
177
178 [self endElement];
179 }
180
f241869 @mikeabdullah Split out -startJavascriptCDATA and -endJavascriptCDATA.
mikeabdullah authored
181 - (void)startJavascriptCDATA;
182 {
183 [self writeString:@"\n/* "];
184 [self startCDATA];
185 [self writeString:@" */"];
186 }
187
188 - (void)endJavascriptCDATA;
189 {
190 [self writeString:@"\n/* "];
191 [self endCDATA];
192 [self writeString:@" */\n"];
193 }
194
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
195 - (void)writeScriptSrc:(NSString *)src // Note: You should either use src OR contents, not both.
196 orContents:(NSString *)contents // However you can specify contents for comments, which is OK.
197 useCDATA:(BOOL)useCDATA;
198 {
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
199 // Use clean API when possible…
37c85e9 @mikeabdullah -writeJavascriptWithSrc: actually makes more sense.
mikeabdullah authored
200 if (src && !contents) return [self writeJavascriptWithSrc:src];
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
201
202
203 // …otherwise bodge it:
204
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
205 [self openTag:@"script"];
206
207 [self writeAttribute:@"type" value:@"text/javascript"];
208 if (src) [self writeAttribute:@"src" value:src];
209 [self didStartElement];
210 if (contents)
211 {
212 // DO NOT USE startNewline since we don't want indentation
11da4a5 @mikeabdullah Switch over to -startJavascriptCDATA and -endJavascriptCDATA.
mikeabdullah authored
213 if (useCDATA) [self startJavascriptCDATA];
58fe1d1 @mikeabdullah Use CDATA API for script writing.
mikeabdullah authored
214
215 [self writeString:@"\n"];
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
216 [self writeString:contents];
58fe1d1 @mikeabdullah Use CDATA API for script writing.
mikeabdullah authored
217 [self writeString:@"\n"];
218
11da4a5 @mikeabdullah Switch over to -startJavascriptCDATA and -endJavascriptCDATA.
mikeabdullah authored
219 if (useCDATA) [self endJavascriptCDATA];
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
220 }
221
222 [self endElement];
223 }
224
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
225 #pragma mark Style
226
227 - (void)startStyleElementWithType:(NSString *)type;
228 {
229 [self openTag:@"style"];
230 if (type) [self writeAttribute:@"type" value:type];
231 [self didStartElement];
232 }
233
234 #pragma mark Elements Stack
235
236 - (BOOL)topElementIsList;
237 {
238 NSString *tagName = [self topElement];
239 BOOL result = [tagName isEqualToString:@"UL"] || [tagName isEqualToString:@"OL"];
240 return result;
241 }
242
c35c721 @mikeabdullah Only a handful of HTML elements are allowed to be empty.
mikeabdullah authored
243 #pragma mark (X)HTML
244
245 - (BOOL)elementCanBeEmpty:(NSString *)tagName;
246 {
247 if ([tagName caseInsensitiveCompare:@"BR"] == NSOrderedSame ||
248 [tagName caseInsensitiveCompare:@"IMG"] == NSOrderedSame ||
249 [tagName caseInsensitiveCompare:@"HR"] == NSOrderedSame ||
250 [tagName caseInsensitiveCompare:@"META"] == NSOrderedSame ||
251 [tagName caseInsensitiveCompare:@"LINK"] == NSOrderedSame ||
252 [tagName caseInsensitiveCompare:@"INPUT"] == NSOrderedSame ||
253 [tagName caseInsensitiveCompare:@"BASE"] == NSOrderedSame ||
254 [tagName caseInsensitiveCompare:@"BASEFONT"] == NSOrderedSame ||
255 [tagName caseInsensitiveCompare:@"PARAM"] == NSOrderedSame ||
256 [tagName caseInsensitiveCompare:@"AREA"] == NSOrderedSame) return YES;
257
258 return NO;
259 }
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
260
261 - (BOOL)canWriteElementInline:(NSString *)tagName;
262 {
263 switch ([tagName length])
264 {
265 case 1:
266 if ([tagName caseInsensitiveCompare:@"A"] == NSOrderedSame ||
267 [tagName caseInsensitiveCompare:@"B"] == NSOrderedSame ||
268 [tagName caseInsensitiveCompare:@"I"] == NSOrderedSame) return YES;
269 break;
270
271 case 2:
272 if ([tagName caseInsensitiveCompare:@"BR"] == NSOrderedSame ||
273 [tagName caseInsensitiveCompare:@"EM"] == NSOrderedSame) return YES;
274 break;
275
276 case 3:
277 if ([tagName caseInsensitiveCompare:@"IMG"] == NSOrderedSame ||
278 [tagName caseInsensitiveCompare:@"SUP"] == NSOrderedSame ||
279 [tagName caseInsensitiveCompare:@"SUB"] == NSOrderedSame ||
280 [tagName caseInsensitiveCompare:@"BIG"] == NSOrderedSame) return YES;
281 break;
282
283 case 4:
284 if ([tagName caseInsensitiveCompare:@"SPAN"] == NSOrderedSame ||
285 [tagName caseInsensitiveCompare:@"FONT"] == NSOrderedSame) return YES;
286 break;
287
288 case 5:
289 if ([tagName caseInsensitiveCompare:@"SMALL"] == NSOrderedSame) return YES;
290 break;
291
292 case 6:
293 if ([tagName caseInsensitiveCompare:@"STRONG"] == NSOrderedSame) return YES;
294 break;
295 }
296
297 return [super canWriteElementInline:tagName];
298 }
299
300 #pragma mark Element Primitives
301
302 - (void)closeEmptyElementTag; // /> OR > depending on -isXHTML
303 {
304 if ([self isXHTML])
305 {
306 [super closeEmptyElementTag];
307 }
308 else
309 {
310 [self writeString:@">"];
311 }
312 }
313
314 @end
Something went wrong with that request. Please try again.