Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 536 lines (432 sloc) 16.33 kb
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
1 //
2 // KSHTMLWriter.m
3 //
efecaa1 @mikeabdullah Settle on BSD license.
mikeabdullah authored
4 // Copyright (c) 2010, Mike Abdullah and Karelia Software
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL MIKE ABDULLAH OR KARELIA SOFTWARE BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
25 //
26
efecaa1 @mikeabdullah Settle on BSD license.
mikeabdullah authored
27
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
28 #import "KSHTMLWriter.h"
29
06fa83e @mikeabdullah On reflection, it makes more sense to represent only the attributes of a...
mikeabdullah authored
30 #import "KSXMLAttributes.h"
3aeccf6 @mikeabdullah KSXMLWriter uses a KSElementInfo object internally.
mikeabdullah authored
31
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
32
0225a1a @mikeabdullah Lots of lovely doctype constants
mikeabdullah authored
33 NSString *KSHTMLWriterDocTypeHTML_4_01_Strict = @"HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"";
34 NSString *KSHTMLWriterDocTypeHTML_4_01_Transitional = @"HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"";
35 NSString *KSHTMLWriterDocTypeHTML_4_01_Frameset = @"HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" \"http://www.w3.org/TR/html4/frameset.dtd\"";
36 NSString *KSHTMLWriterDocTypeXHTML_1_0_Strict = @"html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"";
37 NSString *KSHTMLWriterDocTypeXHTML_1_0_Transitional = @"html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"";
38 NSString *KSHTMLWriterDocTypeXHTML_1_0_Frameset = @"html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\"";
39 NSString *KSHTMLWriterDocTypeXHTML_1_1 = @"html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"";
40 NSString *KSHTMLWriterDocTypeHTML_5 = @"html";
41
42
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
43 @interface KSHTMLWriter ()
44 @property(nonatomic, copy, readwrite) NSString *docType;
45 @end
46
47
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
48 @implementation KSHTMLWriter
49
72adfa1 @mikeabdullah Documenting .isXHTML generation better.
mikeabdullah authored
50 #pragma mark Creating an HTML Writer
51
5f5a663 @mikeabdullah Consistently use "writer" or "output" terminology.
mikeabdullah authored
52 - (id)initWithOutputWriter:(id <KSWriter>)output;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
53 {
5f5a663 @mikeabdullah Consistently use "writer" or "output" terminology.
mikeabdullah authored
54 [super initWithOutputWriter:output];
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
55
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
56 [self setDocType:KSHTMLWriterDocTypeHTML_5];
fba7c04 HTML Writer tracks all element IDs written, so can tell you if an ID is ...
Mike authored
57 _IDs = [[NSMutableSet alloc] init];
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
58 _classNames = [[NSMutableArray alloc] init];
59
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
60 return self;
61 }
62
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
63 - (id)initWithOutputWriter:(id <KSWriter>)output docType:(NSString *)docType encoding:(NSStringEncoding)encoding;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
64 {
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
65 if (self = [self initWithOutputWriter:output encoding:encoding])
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
66 {
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
67 [self setDocType:docType];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
68 }
69
70 return self;
71 }
72
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
73 - (void)dealloc
74 {
fba7c04 HTML Writer tracks all element IDs written, so can tell you if an ID is ...
Mike authored
75 [_IDs release];
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
76 [_classNames release];
77
78 [super dealloc];
79 }
80
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
81 #pragma mark DTD
72adfa1 @mikeabdullah Documenting .isXHTML generation better.
mikeabdullah authored
82
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
83 - (void)startDocumentWithDocType:(NSString *)docType encoding:(NSStringEncoding)encoding;
84 {
85 [self setDocType:docType];
86 [super startDocumentWithDocType:docType encoding:encoding];
87 }
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
88
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
89 @synthesize docType = _docType;
90 - (void)setDocType:(NSString *)docType;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
91 {
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
92 docType = [docType copy];
93 [_docType release]; _docType = docType;
94
3e35588 @mikeabdullah Convenience class method to know if a doctype will produce XHTML
mikeabdullah authored
95 _isXHTML = [[self class] isDocTypeXHTML:docType];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
96 }
97
265ea17 @mikeabdullah Make use of the new docType support
mikeabdullah authored
98 - (BOOL)isXHTML; { return _isXHTML; }
99
3e35588 @mikeabdullah Convenience class method to know if a doctype will produce XHTML
mikeabdullah authored
100 + (BOOL)isDocTypeXHTML:(NSString *)docType;
101 {
102 BOOL result = !([docType isEqualToString:KSHTMLWriterDocTypeHTML_4_01_Strict] ||
103 [docType isEqualToString:KSHTMLWriterDocTypeHTML_4_01_Transitional] ||
104 [docType isEqualToString:KSHTMLWriterDocTypeHTML_4_01_Frameset]);
105 return result;
106 }
107
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
108 #pragma mark CSS Class Name
109
5df9cd7 @mikeabdullah Don't bother exposing -[KSHTMLWriter elementClassName]. Can use [[[write...
mikeabdullah authored
110 - (NSString *)currentElementClassName;
ecfabe0 @mikeabdullah Expose -className.
mikeabdullah authored
111 {
112 NSString *result = nil;
113 if ([_classNames count])
114 {
115 result = [_classNames componentsJoinedByString:@" "];
116 }
117 return result;
118 }
119
5df9cd7 @mikeabdullah Don't bother exposing -[KSHTMLWriter elementClassName]. Can use [[[write...
mikeabdullah authored
120 - (void)pushClassName:(NSString *)className;
121 {
98928dc @mikeabdullah Log if trying to add a CSS class twice to an element during debug builds...
mikeabdullah authored
122 #ifdef DEBUG
123 if ([_classNames containsObject:className])
124 {
125 NSLog(@"Adding class \"%@\" to an element twice", className);
126 }
127 #endif
128
5df9cd7 @mikeabdullah Don't bother exposing -[KSHTMLWriter elementClassName]. Can use [[[write...
mikeabdullah authored
129 [_classNames addObject:className];
130 }
131
30bbf6a Allow values for attributes to be type id, not
Dan Wood authored
132 - (void)pushAttribute:(NSString *)attribute value:(id)value;
e96c6c8 @mikeabdullah Calling [htmlWriter pushElementAttribute:@"class" value:@"foo"] automati...
mikeabdullah authored
133 {
134 if ([attribute isEqualToString:@"class"])
135 {
fba7c04 HTML Writer tracks all element IDs written, so can tell you if an ID is ...
Mike authored
136 return [self pushClassName:value];
e96c6c8 @mikeabdullah Calling [htmlWriter pushElementAttribute:@"class" value:@"foo"] automati...
mikeabdullah authored
137 }
fba7c04 HTML Writer tracks all element IDs written, so can tell you if an ID is ...
Mike authored
138
139 // Keep track of IDs in use
140 if ([attribute isEqualToString:@"id"]) [_IDs addObject:value];
141 [super pushAttribute:attribute value:value];
e96c6c8 @mikeabdullah Calling [htmlWriter pushElementAttribute:@"class" value:@"foo"] automati...
mikeabdullah authored
142 }
143
06fa83e @mikeabdullah On reflection, it makes more sense to represent only the attributes of a...
mikeabdullah authored
144 - (KSXMLAttributes *)currentAttributes;
589179c @mikeabdullah Include -className in -elementAttributes.
mikeabdullah authored
145 {
06fa83e @mikeabdullah On reflection, it makes more sense to represent only the attributes of a...
mikeabdullah authored
146 KSXMLAttributes *result = [super currentAttributes];
589179c @mikeabdullah Include -className in -elementAttributes.
mikeabdullah authored
147
3aeccf6 @mikeabdullah KSXMLWriter uses a KSElementInfo object internally.
mikeabdullah authored
148 // Add in buffered class info
5df9cd7 @mikeabdullah Don't bother exposing -[KSHTMLWriter elementClassName]. Can use [[[write...
mikeabdullah authored
149 NSString *class = [self currentElementClassName];
3aeccf6 @mikeabdullah KSXMLWriter uses a KSElementInfo object internally.
mikeabdullah authored
150 if (class) [result addAttribute:@"class" value:class];
589179c @mikeabdullah Include -className in -elementAttributes.
mikeabdullah authored
151
152 return result;
153 }
154
0e37440 @mikeabdullah Merge branch 'release-1.2'
mikeabdullah authored
155 - (BOOL)hasCurrentAttributes;
d7376e3 @mikeabdullah Sister method: -[KSXMLWriter currentElementHasAttributes]
mikeabdullah authored
156 {
0e37440 @mikeabdullah Merge branch 'release-1.2'
mikeabdullah authored
157 return ([super hasCurrentAttributes] || [_classNames count]);
d7376e3 @mikeabdullah Sister method: -[KSXMLWriter currentElementHasAttributes]
mikeabdullah authored
158 }
159
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
160 #pragma mark HTML Fragments
161
162 - (void)writeHTMLString:(NSString *)html;
163 {
164 [self writeString:html];
165 }
166
167 - (void)writeHTMLFormat:(NSString *)format , ...
168 {
169 va_list argList;
170 va_start(argList, format);
171 NSString *aString = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
172 va_end(argList);
173
174 [self writeHTMLString:aString];
175 }
176
177 #pragma mark General
178
bc8ed57 @mikeabdullah -writeElement:idName:className:content: convenience.
mikeabdullah authored
179 - (void)writeElement:(NSString *)name idName:(NSString *)idName className:(NSString *)className content:(void (^)(void))content;
180 {
181 if (idName) [self pushAttribute:@"id" value:idName];
182 if (className) [self pushAttribute:@"class" value:className];
183
184 [self writeElement:name content:content];
185 }
186
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
187 - (void)startElement:(NSString *)tagName className:(NSString *)className;
188 {
189 [self startElement:tagName idName:nil className:className];
190 }
191
192 - (void)startElement:(NSString *)tagName idName:(NSString *)idName className:(NSString *)className;
193 {
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
194 if (idName) [self pushAttribute:@"id" value:idName];
195 if (className) [self pushAttribute:@"class" value:className];
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
196
197 [self startElement:tagName];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
198 }
199
fba7c04 HTML Writer tracks all element IDs written, so can tell you if an ID is ...
Mike authored
200 - (BOOL)isIDValid:(NSString *)anID; // NO if the ID has already been used
201 {
202 BOOL result = ![_IDs containsObject:anID];
203 return result;
204 }
205
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
206 #pragma mark Line Break
207
208 - (void)writeLineBreak;
209 {
210 [self startElement:@"br"];
211 [self endElement];
212 }
213
62da5a7 @mikeabdullah Block-based API for writing anchor elements.
mikeabdullah authored
214 #pragma mark Anchors
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
215
216 - (void)startAnchorElementWithHref:(NSString *)href title:(NSString *)titleString target:(NSString *)targetString rel:(NSString *)relString;
217 {
62da5a7 @mikeabdullah Block-based API for writing anchor elements.
mikeabdullah authored
218 // TODO: Remove this method once Sandvox no longer needs it
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
219 if (href) [self pushAttribute:@"href" value:href];
220 if (targetString) [self pushAttribute:@"target" value:targetString];
221 if (titleString) [self pushAttribute:@"title" value:titleString];
222 if (relString) [self pushAttribute:@"rel" value:relString];
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
223
224 [self startElement:@"a"];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
225 }
226
62da5a7 @mikeabdullah Block-based API for writing anchor elements.
mikeabdullah authored
227 - (void)writeAnchorElementWithHref:(NSString *)href title:(NSString *)titleString target:(NSString *)targetString rel:(NSString *)relString content:(void (^)(void))content;
228 {
229 [self startAnchorElementWithHref:href title:titleString target:targetString rel:relString];
230 content();
231 [self endElement];
232 }
233
234 #pragma mark Images
235
ac684bc @mikeabdullah Don't need to pass id and class directly when writing an image.
mikeabdullah authored
236 - (void)writeImageWithSrc:(NSString *)src
237 alt:(NSString *)alt
30bbf6a Allow values for attributes to be type id, not
Dan Wood authored
238 width:(id)width
239 height:(id)height;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
240 {
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
241 [self pushAttribute:@"src" value:src];
242 [self pushAttribute:@"alt" value:alt];
243 if (width) [self pushAttribute:@"width" value:width];
244 if (height) [self pushAttribute:@"height" value:height];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
245
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
246 [self startElement:@"img"];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
247 [self endElement];
248 }
249
250 #pragma mark Link
251
252 - (void)writeLinkWithHref:(NSString *)href
253 type:(NSString *)type
254 rel:(NSString *)rel
255 title:(NSString *)title
256 media:(NSString *)media;
257 {
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
258 if (rel) [self pushAttribute:@"rel" value:rel];
e982500 @mikeabdullah <LINK>s don't have text/css as default type any more because some links ...
mikeabdullah authored
259 if (type) [self pushAttribute:@"type" value:type];
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
260 [self pushAttribute:@"href" value:href];
261 if (title) [self pushAttribute:@"title" value:title];
262 if (media) [self pushAttribute:@"media" value:media];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
263
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
264 [self startElement:@"link"];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
265 [self endElement];
266 }
267
268 - (void)writeLinkToStylesheet:(NSString *)href
269 title:(NSString *)title
270 media:(NSString *)media;
271 {
e982500 @mikeabdullah <LINK>s don't have text/css as default type any more because some links ...
mikeabdullah authored
272 [self writeLinkWithHref:href type:@"text/css" rel:@"stylesheet" title:title media:media];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
273 }
274
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
275 #pragma mark Scripts
276
3a9930c @mikeabdullah -writeJavascriptWithSrc:encoding: method that tries to do the right with...
mikeabdullah authored
277 - (void)writeJavascriptWithSrc:(NSString *)src encoding:(NSStringEncoding)encoding;
278 {
279 // According to the HTML spec, charset only needs to be specified if the script is a different encoding to the document
280 NSString *charset = nil;
281 if (encoding != [self encoding])
282 {
283 charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(encoding));
284 }
285
286 [self writeJavascriptWithSrc:src charset:charset];
287 }
288
b695665 Src may be nil; it's handled in support classes
Dan Wood authored
289 - (void)writeJavascriptWithSrc:(NSString *)src charset:(NSString *)charset; // src may be nil
290 {
1d5ee5f @mikeabdullah If linking to a script, generally should specify charset
mikeabdullah authored
291 if (charset) [self pushAttribute:@"charset" value:charset];
1ca811e @mikeabdullah Split out -startJavascriptElementWithSrc:
mikeabdullah authored
292 [self startJavascriptElementWithSrc:src];
60c7e89 @mikeabdullah Simpler method for pulling in an external script.
mikeabdullah authored
293 [self endElement];
294 }
de567f7 added method to output JavaScript (via Dan)
Terrence Talbot authored
295
4d9ca24 @mikeabdullah -writeJavascript:useCDATA: convenience method.
mikeabdullah authored
296 - (void)writeJavascript:(NSString *)script useCDATA:(BOOL)useCDATA;
297 {
1ca811e @mikeabdullah Split out -startJavascriptElementWithSrc:
mikeabdullah authored
298 [self startJavascriptElementWithSrc:nil];
4d9ca24 @mikeabdullah -writeJavascript:useCDATA: convenience method.
mikeabdullah authored
299
300 if (useCDATA) [self startJavascriptCDATA];
301 [self writeString:script];
302 if (useCDATA) [self endJavascriptCDATA];
303
304 [self endElement];
305 }
306
1ca811e @mikeabdullah Split out -startJavascriptElementWithSrc:
mikeabdullah authored
307 - (void)startJavascriptElementWithSrc:(NSString *)src; // src may be nil
308 {
4af9cd9 @mikeabdullah HTML5 doesn't bother specifying the type of <SCRIPT>s
mikeabdullah authored
309 // HTML5 doesn't need the script type specified, but older doc types do for standards-compliance
310 if (![[self docType] isEqualToString:KSHTMLWriterDocTypeHTML_5])
311 {
312 [self pushAttribute:@"type" value:@"text/javascript"];
313 }
314
315 // Script
3530727 Don't specify charset for inline javascript, only
Dan Wood authored
316 if (src)
317 {
318 [self pushAttribute:@"src" value:src];
319 }
1d5ee5f @mikeabdullah If linking to a script, generally should specify charset
mikeabdullah authored
320
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
321 [self startElement:@"script"];
8a9783e @mikeabdullah Embedded scripts should start on a newline.
mikeabdullah authored
322
323 // Embedded scripts should start on their own line for clarity
2d68556 @mikeabdullah Embedded scripts should also write their end tag on a new line.
mikeabdullah authored
324 if (!src)
325 {
326 [self writeString:@"\n"];
327 [self stopWritingInline];
328 }
1ca811e @mikeabdullah Split out -startJavascriptElementWithSrc:
mikeabdullah authored
329 }
330
f241869 @mikeabdullah Split out -startJavascriptCDATA and -endJavascriptCDATA.
mikeabdullah authored
331 - (void)startJavascriptCDATA;
332 {
333 [self writeString:@"\n/* "];
334 [self startCDATA];
335 [self writeString:@" */"];
336 }
337
338 - (void)endJavascriptCDATA;
339 {
340 [self writeString:@"\n/* "];
341 [self endCDATA];
342 [self writeString:@" */\n"];
343 }
344
0bc7e19 Add new convenience method for writing <param name="foo" value="bar" />
Dan Wood authored
345 #pragma mark Param
346
347 - (void)writeParamElementWithName:(NSString *)name value:(NSString *)value;
348 {
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
349 if (name) [self pushAttribute:@"name" value:name];
350 if (value) [self pushAttribute:@"value" value:value];
0bc7e19 Add new convenience method for writing <param name="foo" value="bar" />
Dan Wood authored
351 [self startElement:@"param"];
352 [self endElement];
353 }
354
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
355 #pragma mark Style
356
6dd07ee @mikeabdullah Convenience method for writing inline CSS.
mikeabdullah authored
357 - (void)writeStyleElementWithCSSString:(NSString *)css;
358 {
359 [self startStyleElementWithType:@"text/css"];
360 [self writeString:css]; // browsers don't expect styles to be XML escaped
361 [self endElement];
362 }
363
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
364 - (void)startStyleElementWithType:(NSString *)type;
365 {
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
366 if (type) [self pushAttribute:@"type" value:type];
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
367 [self startElement:@"style"];
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
368 }
369
370 #pragma mark Elements Stack
371
1b3d197 @mikeabdullah KSHTMLWriter gains:
mikeabdullah authored
372 - (BOOL)hasListOpen;
373 {
374 return ([self hasOpenElement:@"ul"] || [self hasOpenElement:@"ol"]);
375 }
376
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
377 - (BOOL)topElementIsList;
378 {
1b3d197 @mikeabdullah KSHTMLWriter gains:
mikeabdullah authored
379 return [[self class] elementIsList:[self topElement]];
380 }
381
382 + (BOOL)elementIsList:(NSString *)element;
383 {
384 BOOL result = ([element isEqualToString:@"ul"] ||
385 [element isEqualToString:@"ol"]);
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
386 return result;
387 }
388
c35c721 @mikeabdullah Only a handful of HTML elements are allowed to be empty.
mikeabdullah authored
389 #pragma mark (X)HTML
390
391 - (BOOL)elementCanBeEmpty:(NSString *)tagName;
392 {
f23f8c7 @mikeabdullah XML Writing should be case-sensitive.
mikeabdullah authored
393 if ([tagName isEqualToString:@"br"] ||
394 [tagName isEqualToString:@"img"] ||
395 [tagName isEqualToString:@"hr"] ||
396 [tagName isEqualToString:@"meta"] ||
397 [tagName isEqualToString:@"link"] ||
398 [tagName isEqualToString:@"input"] ||
399 [tagName isEqualToString:@"base"] ||
400 [tagName isEqualToString:@"basefont"] ||
401 [tagName isEqualToString:@"param"] ||
402 [tagName isEqualToString:@"area"] ||
403 [tagName isEqualToString:@"source"]) return YES;
c35c721 @mikeabdullah Only a handful of HTML elements are allowed to be empty.
mikeabdullah authored
404
405 return NO;
406 }
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
407
408 - (BOOL)canWriteElementInline:(NSString *)tagName;
409 {
410 switch ([tagName length])
411 {
412 case 1:
f23f8c7 @mikeabdullah XML Writing should be case-sensitive.
mikeabdullah authored
413 if ([tagName isEqualToString:@"a"] ||
414 [tagName isEqualToString:@"b"] ||
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
415 [tagName isEqualToString:@"i"] ||
58a8fbc @mikeabdullah Somehow <U> got left off the list of inline elements.
mikeabdullah authored
416 [tagName isEqualToString:@"u"] ||
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
417 [tagName isEqualToString:@"q"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
418 break;
419
420 case 2:
f23f8c7 @mikeabdullah XML Writing should be case-sensitive.
mikeabdullah authored
421 if ([tagName isEqualToString:@"br"] ||
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
422 [tagName isEqualToString:@"em"] ||
423 [tagName isEqualToString:@"tt"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
424 break;
425
426 case 3:
f23f8c7 @mikeabdullah XML Writing should be case-sensitive.
mikeabdullah authored
427 if ([tagName isEqualToString:@"img"] ||
428 [tagName isEqualToString:@"sup"] ||
429 [tagName isEqualToString:@"sub"] ||
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
430 [tagName isEqualToString:@"big"] ||
431 [tagName isEqualToString:@"del"] ||
432 [tagName isEqualToString:@"ins"] ||
433 [tagName isEqualToString:@"dfn"] ||
434 [tagName isEqualToString:@"map"] ||
435 [tagName isEqualToString:@"var"] ||
436 [tagName isEqualToString:@"bdo"] ||
437 [tagName isEqualToString:@"kbd"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
438 break;
439
440 case 4:
f23f8c7 @mikeabdullah XML Writing should be case-sensitive.
mikeabdullah authored
441 if ([tagName isEqualToString:@"span"] ||
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
442 [tagName isEqualToString:@"font"] ||
443 [tagName isEqualToString:@"abbr"] ||
444 [tagName isEqualToString:@"cite"] ||
445 [tagName isEqualToString:@"code"] ||
446 [tagName isEqualToString:@"samp"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
447 break;
448
449 case 5:
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
450 if ([tagName isEqualToString:@"small"] ||
451 [tagName isEqualToString:@"input"] ||
452 [tagName isEqualToString:@"label"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
453 break;
454
455 case 6:
782c637 @mikeabdullah Expand the list of known inline elements
mikeabdullah authored
456 if ([tagName isEqualToString:@"strong"] ||
457 [tagName isEqualToString:@"select"] ||
458 [tagName isEqualToString:@"button"] ||
459 [tagName isEqualToString:@"object"] ||
460 [tagName isEqualToString:@"applet"] ||
461 [tagName isEqualToString:@"script"]) return YES;
462 break;
463
464 case 7:
465 if ([tagName isEqualToString:@"acronym"]) return YES;
466 break;
467
468 case 8:
469 if ([tagName isEqualToString:@"textarea"]) return YES;
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
470 break;
471 }
472
473 return [super canWriteElementInline:tagName];
474 }
475
05b69fd @mikeabdullah HTML Writer reports that lists may only contain list items.
mikeabdullah authored
476 - (BOOL)validateElement:(NSString *)element;
477 {
478 if (![super validateElement:element]) return NO;
479
480 // Lists can only contain list items
481 if ([self topElementIsList])
482 {
483 return [element isEqualToString:@"li"];
484 }
485 else
486 {
487 return YES;
488 }
489 }
490
a85616d @mikeabdullah Only ordered list items can have a value.
mikeabdullah authored
491 - (NSString *)validateAttribute:(NSString *)name value:(NSString *)value ofElement:(NSString *)element;
492 {
493 NSString *result = [super validateAttribute:name value:value ofElement:element];
494 if (!result) return nil;
495
496 // value is only allowed as a list item attribute when in an ordered list
497 if ([element isEqualToString:@"li"] && [name isEqualToString:@"value"])
498 {
499 if (![[self topElement] isEqualToString:@"ol"]) result = nil;
500 }
501
502 return result;
503 }
504
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
505 #pragma mark Element Primitives
506
c8bc317 @mikeabdullah Can now ditch -openTag:writeInline:
mikeabdullah authored
507 - (void)startElement:(NSString *)elementName writeInline:(BOOL)writeInline; // for more control
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
508 {
566d24c @mikeabdullah non-lowercase tags shouldn't be used for HTML.
mikeabdullah authored
509 NSAssert1([elementName isEqualToString:[elementName lowercaseString]], @"Attempt to start non-lowercase element: %@", elementName);
510
511
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
512 // Add in any pre-written classes
5df9cd7 @mikeabdullah Don't bother exposing -[KSHTMLWriter elementClassName]. Can use [[[write...
mikeabdullah authored
513 NSString *class = [self currentElementClassName];
ecfabe0 @mikeabdullah Expose -className.
mikeabdullah authored
514 if (class)
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
515 {
516 [_classNames removeAllObjects];
b12f4c9 Sorry to keep changing this, but -pushElementAttribute: really is too wo...
Mike authored
517 [super pushAttribute:@"class" value:class];
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
518 }
9beb73b @mikeabdullah Take a bunch of primitive element APIs private. Just need to use -addAtt...
mikeabdullah authored
519
c8bc317 @mikeabdullah Can now ditch -openTag:writeInline:
mikeabdullah authored
520 [super startElement:elementName writeInline:writeInline];
75c4ca6 @mikeabdullah Experimental support for building up CSS class names before writing an e...
mikeabdullah authored
521 }
522
994c91e @mikeabdullah And the real star of our show arrives: KSHTMLWriter!
mikeabdullah authored
523 - (void)closeEmptyElementTag; // /> OR > depending on -isXHTML
524 {
525 if ([self isXHTML])
526 {
527 [super closeEmptyElementTag];
528 }
529 else
530 {
531 [self writeString:@">"];
532 }
533 }
534
535 @end
Something went wrong with that request. Please try again.