Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 308 lines (244 sloc) 8.449 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
f241869 @mikeabdullah Split out -startJavascriptCDATA and -endJavascriptCDATA.
mikeabdullah authored
164 - (void)startJavascriptCDATA;
165 {
166 [self writeString:@"\n/* "];
167 [self startCDATA];
168 [self writeString:@" */"];
169 }
170
171 - (void)endJavascriptCDATA;
172 {
173 [self writeString:@"\n/* "];
174 [self endCDATA];
175 [self writeString:@" */\n"];
176 }
177
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
178 - (void)writeScriptSrc:(NSString *)src // Note: You should either use src OR contents, not both.
179 orContents:(NSString *)contents // However you can specify contents for comments, which is OK.
180 useCDATA:(BOOL)useCDATA;
181 {
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
182 // Use clean API when possible…
37c85e9 @mikeabdullah -writeJavascriptWithSrc: actually makes more sense.
mikeabdullah authored
183 if (src && !contents) return [self writeJavascriptWithSrc:src];
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
184
185
186 // …otherwise bodge it:
187
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
188 [self openTag:@"script"];
189
190 [self writeAttribute:@"type" value:@"text/javascript"];
191 if (src) [self writeAttribute:@"src" value:src];
192 [self didStartElement];
193 if (contents)
194 {
195 // DO NOT USE startNewline since we don't want indentation
58fe1d1 @mikeabdullah Use CDATA API for script writing.
mikeabdullah authored
196 if (useCDATA)
197 {
198 [self writeString:@"\n/* "];
199 [self startCDATA];
200 [self writeString:@" */"];
201 }
202
203 [self writeString:@"\n"];
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
204 [self writeString:contents];
58fe1d1 @mikeabdullah Use CDATA API for script writing.
mikeabdullah authored
205 [self writeString:@"\n"];
206
207 if (useCDATA)
208 {
209 [self writeString:@"\n/* "];
210 [self endCDATA];
211 [self writeString:@" */\n"];
212 }
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
213 }
214
215 [self endElement];
216 }
217
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
218 #pragma mark Style
219
220 - (void)startStyleElementWithType:(NSString *)type;
221 {
222 [self openTag:@"style"];
223 if (type) [self writeAttribute:@"type" value:type];
224 [self didStartElement];
225 }
226
227 #pragma mark Elements Stack
228
229 - (BOOL)topElementIsList;
230 {
231 NSString *tagName = [self topElement];
232 BOOL result = [tagName isEqualToString:@"UL"] || [tagName isEqualToString:@"OL"];
233 return result;
234 }
235
c35c721 @mikeabdullah Only a handful of HTML elements are allowed to be empty.
mikeabdullah authored
236 #pragma mark (X)HTML
237
238 - (BOOL)elementCanBeEmpty:(NSString *)tagName;
239 {
240 if ([tagName caseInsensitiveCompare:@"BR"] == NSOrderedSame ||
241 [tagName caseInsensitiveCompare:@"IMG"] == NSOrderedSame ||
242 [tagName caseInsensitiveCompare:@"HR"] == NSOrderedSame ||
243 [tagName caseInsensitiveCompare:@"META"] == NSOrderedSame ||
244 [tagName caseInsensitiveCompare:@"LINK"] == NSOrderedSame ||
245 [tagName caseInsensitiveCompare:@"INPUT"] == NSOrderedSame ||
246 [tagName caseInsensitiveCompare:@"BASE"] == NSOrderedSame ||
247 [tagName caseInsensitiveCompare:@"BASEFONT"] == NSOrderedSame ||
248 [tagName caseInsensitiveCompare:@"PARAM"] == NSOrderedSame ||
249 [tagName caseInsensitiveCompare:@"AREA"] == NSOrderedSame) return YES;
250
251 return NO;
252 }
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
253
254 - (BOOL)canWriteElementInline:(NSString *)tagName;
255 {
256 switch ([tagName length])
257 {
258 case 1:
259 if ([tagName caseInsensitiveCompare:@"A"] == NSOrderedSame ||
260 [tagName caseInsensitiveCompare:@"B"] == NSOrderedSame ||
261 [tagName caseInsensitiveCompare:@"I"] == NSOrderedSame) return YES;
262 break;
263
264 case 2:
265 if ([tagName caseInsensitiveCompare:@"BR"] == NSOrderedSame ||
266 [tagName caseInsensitiveCompare:@"EM"] == NSOrderedSame) return YES;
267 break;
268
269 case 3:
270 if ([tagName caseInsensitiveCompare:@"IMG"] == NSOrderedSame ||
271 [tagName caseInsensitiveCompare:@"SUP"] == NSOrderedSame ||
272 [tagName caseInsensitiveCompare:@"SUB"] == NSOrderedSame ||
273 [tagName caseInsensitiveCompare:@"BIG"] == NSOrderedSame) return YES;
274 break;
275
276 case 4:
277 if ([tagName caseInsensitiveCompare:@"SPAN"] == NSOrderedSame ||
278 [tagName caseInsensitiveCompare:@"FONT"] == NSOrderedSame) return YES;
279 break;
280
281 case 5:
282 if ([tagName caseInsensitiveCompare:@"SMALL"] == NSOrderedSame) return YES;
283 break;
284
285 case 6:
286 if ([tagName caseInsensitiveCompare:@"STRONG"] == NSOrderedSame) return YES;
287 break;
288 }
289
290 return [super canWriteElementInline:tagName];
291 }
292
293 #pragma mark Element Primitives
294
295 - (void)closeEmptyElementTag; // /> OR > depending on -isXHTML
296 {
297 if ([self isXHTML])
298 {
299 [super closeEmptyElementTag];
300 }
301 else
302 {
303 [self writeString:@">"];
304 }
305 }
306
307 @end
Something went wrong with that request. Please try again.