This is Text.HTMLExtensions.m in view mode; [Download] [Up]
// Tue Oct 15 06:52:10 MET 1996
// toDo: · restore for form-objects after loadFromStream (esp. write formSession for every radioCell)
// · print- distinction for all the TFCells using e.g. the dingbats symbols
// · textarea
// · check-button
// · background-support: cell has to overrride DrawALine-func
// · replaceSelWithHTML:(char*)
// · </body> should finish all open attributes like bold et al.
// · matrices should draw in NXImages, not in the view-hierarchy (printing problems)
// · split matrices into individual lines (every line is a separate cell-> pagination of large tables)
// · whitespace problems
// · intra-word-bolding impossible w/out inserting spaces (solution: delete the added space)
// · problems with /daniel/tmp/html/msql/lite.htm
//
#import "Text.HTMLExtensions.h"
#import "MiscString.DExtensions.h"
// hidden NeXT-utility class uncovered (MiscClass-decoded)
@interface NXGraphicCell : Cell
{
}
+ initialize;
- replaceGraphic: arg;
- initFromImage: theImage name: (const char *) theName;
- readRichText: (NXStream *) theStrean forView: theView;
- writeRichText: (NXStream *) theStrean forView: theView;
- free;
- calcCellSize: (NXSize *) theSize;
- drawSelf: (NXRect *) aRect inView: theView;
- image;
- setImageNamed: (const char *) theName forView: theView;
-(BOOL) trackMouse: (NXEvent *) theEvnt inRect: (const NXRect *) drawRect ofView: theView;
- highlight: (NXRect *) aRect inView: theView lit: (BOOL) flag;
@end
// recognized HTML-directives¼
// Warning: every END-token must exactly be below its start token!
typedef enum
{ HTML_HTML,
HTML_ENDHTML,
HTML_TITLE,
HTML_ENDTITLE,
HTML_HEAD,
HTML_ENDHEAD,
HTML_BODY,
HTML_ENDBODY,
HTML_H1,
HTML_ENDH1,
HTML_H2,
HTML_ENDH2,
HTML_H3,
HTML_ENDH3,
HTML_H4,
HTML_ENDH4,
HTML_H5,
HTML_ENDH5,
HTML_H6,
HTML_ENDH6,
HTML_HR,
HTML_P,
HTML_ENDP,
HTML_SUB,
HTML_ENDSUB,
HTML_STRONG,
HTML_ENDSTRONG,
HTML_DL, // definitionlist
HTML_ENDDL,
HTML_DT, // word to be defined
HTML_DD, // definition
HTML_UL, // unordered list
HTML_ENDUL,
HTML_LI, // listitem
HTML_ENDLI,
HTML_OL, // ordered list
HTML_ENDOL,
HTML_SAMP, // contrast font
HTML_ENDSAMP,
HTML_FORMSESSION,
HTML_ENDFORMSESSION,
HTML_FORMINPUT,
HTML_IMG,
HTML_EM,
HTML_ENDEM,
HTML_HREF,
HTML_ENDHREF,
HTML_NAME,
HTML_SELECT,
HTML_ENDSELECT,
HTML_OPTION,
HTML_ENDOPTION,
HTML_CENTER,
HTML_ENDCENTER,
HTML_TABLE,
HTML_ENDTABLE,
HTML_TR, // new tablerow
HTML_ENDTR, // end of new tablerow
HTML_TH, // tableheader
HTML_TD, // new tablecell
HTML_ENDTD, // end of new tablecell
HTML_PRE, // preformatted text
HTML_ENDPRE, // preformatted text
HTML_BLOCKQUOTE,
HTML_ENDBLOCKQUOTE,
HTML_endOfHTMLList
} HTML_t;
@implementation Text(HTMLExtensions)
-(int) charAt:(int) pos
{ char text[2];
if([self getSubstring:text start:pos length:1] != 1) return 0;
return text[0];
}
#define MAX_TABS 50
- removeAllTabs
{/* int i;
NXTabStop tabs[MAX_TABS];
[self getTabs:&tabs num:MAX_TABS];
for(i=0; tabs[i].kind>= 0;i++)
{ [self setSelProp:NX_REMOVETAB to:tabs[i].x];
}
*/ return self;
}
#define LEFT_MARGIN 1
-(void) normalizeRulerAt:(int) pos
{ [self setSel:pos:pos+1];
[self setSelProp:NX_FIRSTINDENT to:LEFT_MARGIN];
[self setSelProp:NX_INDENT to:LEFT_MARGIN];
//[self pasteRuler:self];
}
// some lexical analysis¼
-(HTML_t) HTMLTokenForString:(MiscString *) str
{ if([str charAt:0] == '!') return HTML_endOfHTMLList; // sort of comment
if([str casestreq:"HTML"]) return HTML_HTML;
else if([str casestreq:"/HTML"]) return HTML_ENDHTML;
else if([str casestreq:"TITLE"]) return HTML_TITLE;
else if([str casestreq:"/TITLE"]) return HTML_ENDTITLE;
else if([str casestreq:"HEAD"]) return HTML_HEAD;
else if([str casestreq:"/HEAD"]) return HTML_ENDHEAD;
else if([str casestreq:"/BODY"]) return HTML_ENDBODY;
else if([str strstr:"BODY" caseSensitive:NO]) return HTML_BODY; // below!!!
else if([str casestreq:"H1"]) return HTML_H1;
else if([str casestreq:"/H1"]) return HTML_ENDH1;
else if([str casestreq:"H2"]) return HTML_H2;
else if([str casestreq:"/H2"]) return HTML_ENDH2;
else if([str casestreq:"H3"]) return HTML_H2;
else if([str casestreq:"/H3"]) return HTML_ENDH2;
else if([str casestreq:"H4"]) return HTML_H4;
else if([str casestreq:"/H4"]) return HTML_ENDH4;
else if([str casestreq:"H5"]) return HTML_H4;
else if([str casestreq:"/H5"]) return HTML_ENDH4;
else if([str casestreq:"H6"]) return HTML_H6;
else if([str casestreq:"/H6"]) return HTML_ENDH6;
else if([str casestreq:"HR"]) return HTML_HR;
else if([str casestreq:"P"]) return HTML_P;
else if([str casestreq:"/P"]) return HTML_ENDP;
else if([str casestreq:"STRONG"]) return HTML_STRONG;
else if([str casestreq:"/STRONG"]) return HTML_ENDSTRONG;
else if([str casestreq:"SUB"]) return HTML_SUB;
else if([str casestreq:"/SUB"]) return HTML_ENDSUB;
else if([str casestreq:"SAMP"]) return HTML_SAMP;
else if([str casestreq:"/SAMP"]) return HTML_ENDSAMP;
else if([str casestreq:"CODE"]) return HTML_SAMP;
else if([str casestreq:"/CODE"]) return HTML_ENDSAMP;
else if([str casestreq:"B"]) return HTML_STRONG;
else if([str casestreq:"/B"]) return HTML_ENDSTRONG;
else if([str casestreq:"EM"]) return HTML_EM;
else if([str casestreq:"/EM"]) return HTML_ENDEM;
else if([str casestreq:"I"]) return HTML_EM;
else if([str casestreq:"/I"]) return HTML_ENDEM;
else if([str casestreq:"CITE"]) return HTML_EM;
else if([str casestreq:"/CITE"]) return HTML_ENDEM;
else if([str casestreq:"VAR"]) return HTML_EM;
else if([str casestreq:"/VAR"]) return HTML_ENDEM;
else if([str casestreq:"UL"]) return HTML_UL;
else if([str casestreq:"/UL"]) return HTML_ENDUL;
else if([str casestreq:"/DL"]) return HTML_ENDDL; //above
else if([str strstr:"DL" caseSensitive:NO]) return HTML_DL;
else if([str casestreq:"LI"]) return HTML_LI;
else if([str casestreq:"/LI"]) return HTML_ENDLI;
else if([str casestreq:"DD"]) return HTML_DD;
else if([str casestreq:"/DD"]) return HTML_ENDLI;
else if([str casestreq:"DT"]) return HTML_DT;
else if([str casestreq:"OL"]) return HTML_OL;
else if([str casestreq:"/OL"]) return HTML_ENDOL;
else if([str casestreq:"BR"]) return HTML_P;
else if([str casestreq:"CENTER"]) return HTML_CENTER;
else if([str casestreq:"/CENTER"]) return HTML_ENDCENTER;
else if([str casestreq:"/TABLE"]) return HTML_ENDTABLE;
else if([str strstr:"TABLE" caseSensitive:NO]) return HTML_TABLE;
else if([str casestreq:"TR"]) return HTML_TR;
else if([str casestreq:"/TR"]) return HTML_ENDTR;
else if([str casestreq:"/TD"]) return HTML_ENDTD;
else if([str strstr:"TD" caseSensitive:NO]) return HTML_TD;
else if([str casestreq:"PRE"]) return HTML_PRE;
else if([str casestreq:"/PRE"]) return HTML_ENDPRE;
else if([str casestreq:"BLOCKQUOTE"]) return HTML_BLOCKQUOTE;
else if([str casestreq:"/BLOCKQUOTE"]) return HTML_ENDBLOCKQUOTE;
else if([str strstr:"IMG SRC" caseSensitive:NO]) return HTML_IMG;
else if([str strstr:"A HREF" caseSensitive:NO]) return HTML_HREF;
else if([str strstr:"A NAME" caseSensitive:NO]) return HTML_NAME;
else if([str casestreq:"/A"]) return HTML_ENDHREF;
// Forms-stuff
else if([str strstr:"FORM METHOD" caseSensitive:NO]) return HTML_FORMSESSION;
else if([str casestreq:"/FORM"]) return HTML_ENDFORMSESSION;
else if([str strstr:"INPUT TYPE" caseSensitive:NO]) return HTML_FORMINPUT;
else if([str strstr:"INPUT ID" caseSensitive:NO]) return HTML_FORMINPUT;
else if([str casestreq:"/OPTION"]) return HTML_ENDOPTION; // above select !! (SELECTED)
else if([str strstr:"OPTION" caseSensitive:NO]) return HTML_OPTION;
else if([str casestreq:"/SELECT"]) return HTML_ENDSELECT; // reihenfolge!
else if([str strstr:"SELECT" caseSensitive:NO]) return HTML_SELECT;
else if([str strstr:"TH" caseSensitive:NO]) return HTML_TH; //Lowest!
return HTML_endOfHTMLList;
}
-(MiscString*) contentFor:(HTML_t) theT inArr:(int*) modeArray in:(MiscString *)parseString right:(int)dirIndex
{ MiscString *contentString=[parseString midFrom:modeArray[theT] to:dirIndex];
modeArray[theT]=-1;
return contentString;
}
- insertBackground:(MiscString*)tmpString
{// NXRect newFrame;
id theCell;
const char *theFile;
List *keyVal=[tmpString tokenize:"=" into:nil];
MiscString *key=[keyVal objectAt:0],*val=[keyVal objectAt:1];
if([key strstr:"background" caseSensitive:NO])
{// MiscString *filename;
int end;
if((end=[val spotOfChars:"\"" occurrenceNum:1]) >=0) [val removeFrom:end to:[val length]];
[val trimChars:"\""];
theFile=[val stringValue];
theCell=[[TextBackgroundCell alloc] initFromImage:[[NXImage alloc] initFromFile:theFile]];
[[keyVal freeObjects] free];
#if 1
[self replaceSelWithCell:theCell];
#else
[self getBounds:&newFrame];
{ Button *background=[[Button alloc] initFrame:&newFrame];
[background setSelectable:NO];
[[background setCell:[[TextBackgroundCell alloc] init]] free];
[self addSubview:background];
}
#endif
return theCell;
} return nil;
}
- insertImage:(MiscString*)tmpString
{ Cell *theCell=nil;
NXImage *theImage=nil;
const char *theFile;
List *keyVal=[tmpString tokenize:"=" into:nil];
MiscString /**key=[keyVal objectAt:0],*/*val=[keyVal objectAt:1];
theFile=[val stringValue];
if(delegate && [delegate respondsTo:@selector(getImageForFile:)])
theImage=[delegate getImageForFile:theFile];
else theImage=[[NXImage alloc] initFromFile:theFile];
if(theImage)
{ theCell=[[NXGraphicCell alloc] initFromImage:theImage name:theFile];
[self replaceSelWithCell:theCell];
}
[[keyVal freeObjects] free];
return theCell;
}
- insertLink:(MiscString*)tmpString
{ id theCell=nil;
const char *theFile;
List *keyVal=[tmpString tokenize:"=" into:nil fieldsQuotatedBy:'\"'];
MiscString *key=[keyVal objectAt:0],*val=[keyVal objectAt:1];
[val trimChars:" \""];
theFile=[val stringValue];
if([key strstr:"HREF" caseSensitive:NO])
{ theCell=[[NXLinkCell alloc] initForView:self];
if(strchr([val stringValue],'#'))
{ List *fileMarker=[val tokenize:"#" into:nil fieldsQuotatedBy:'\"'];
if([fileMarker count]> 1)
{ [theCell setLinkMarkername:[[fileMarker objectAt:1] stringValue]];
[theCell setLinkFilename:[[fileMarker objectAt:0] stringValue]];
} else
{ [theCell setLinkFilename:"///SameFile///"];
[theCell setLinkMarkername:[[fileMarker objectAt:0] stringValue]];
}
[[fileMarker freeObjects] free];
} else [theCell setLinkFilename:theFile];
[theCell setOpenInNewWin:NO];
} else if([key strstr:"NAME" caseSensitive:NO])
{ theCell=[[NXMarkerCell alloc] initForView:self];
[theCell setMarkername:theFile];
[theCell setVisible:NO];
} [[keyVal freeObjects] free];
[self replaceSelWithCell:theCell];
return self;
}
static id sharedField;
- sharedField {return sharedField;}
static id sharedButton;
- setSharedButton:theButton
{ if(sharedButton)
{ [sharedButton removeFromSuperview];
[sharedButton free];
}
return sharedButton=theButton;
}
// cursor has to be set in advance
- insertFormElement:(MiscString*) tmpString forSession:(int)formSession radioList:currRadioList
{ List *attribs;
MiscString *currStr;
int i;
id gadget=nil;
[tmpString replaceEveryOccurrenceOf:"INPUT TYPE" with:"INPUT_TYPE" caseSensitive:NO];
[tmpString replaceEveryOccurrenceOf:"INPUT ID" with:"INPUT_ID" caseSensitive:NO];
attribs=[tmpString tokenize:" " into:nil fieldsQuotatedBy:'\"'];
for(i=0; currStr=[attribs objectAt:i];i++)
{ List *keyVal=[currStr tokenize:"=" into:nil];
MiscString *key=[keyVal objectAt:0],*val=[keyVal objectAt:1];
[val trimChars:"\""];[val collapseHTMLQuotedChars];
if([key casestreq:"INPUT_TYPE"] || [key casestreq:"INPUT_ID"])
{ if([val casestreq:"radio"])
{ gadget=[[MiscTFRadioCell alloc] initInText:self];
[currRadioList addObject:gadget];
} else if([val casestreq:"text"] || [key casestreq:"INPUT_ID"])
{ if (!sharedField)
{ sharedField=[[TextField alloc] init];
[sharedField setBezeled:YES];
[sharedField setBackgroundGray:NX_WHITE];
[sharedField setTag:2000];
[sharedField setTextDelegate:[self delegate]];
}
gadget=[[MiscTFTextFieldCell alloc] initTextCell:""];
[gadget setBezeled:YES];
[gadget setBackgroundGray:NX_WHITE];
[gadget setStringValue:""];
[gadget setSelectable:YES];
[gadget setEditable:YES];
} else if([val casestreq:"SUBMIT"] || [val casestreq:"RESET"])
{ gadget=[[MiscTFButtonCell alloc] initInText:self];
}
} else if([key casestreq:"NAME"])
{
} else if([key casestreq:"TYPE"])
{ if([val casestreq:"hidden"])
{ gadget=[gadget free];
}
} else if([key casestreq:"VALUE"])
{ if(gadget && [gadget isKindOf:[MiscTFButtonCell class]])
[gadget setTitle:[val stringValue]];
else [gadget setStringValue:[val stringValue]];
} else if([key casestreq:"SIZE"])
{ NXCoord newWidth=8*[val intValue];
if([gadget respondsTo:@selector(setWidth:)]) [gadget setWidth:newWidth];
else
{ NXRect lr;
[gadget getFrame:&lr];
[gadget sizeTo:8*[val intValue] :NX_HEIGHT(&lr)];
}
} [[keyVal freeObjects] free];
} [[attribs freeObjects] free];
if(gadget)
{ [self replaceSelWithCell:gadget];
// now register it with the delegate (including name, value etc.)
} return gadget;
}
#define LEFT_MARGIN 1
#define INDENT_WIDTH 30
#define MAX_NESTING 8
#define LIST_START_POS listStarts[liNest]
#define LIST_COUNT liCount[liNest]
#define LIST_MODE liMode[liNest]
//#define SIMPLE_CELL
- insertTableFromString:(MiscString *) parseString atPos:(int *)currPosPtr modeArray:(int *) modeArray textPos:(int*) textPos
{ int currRow=0,currCol=0,maxRows=0,maxCols=0,
currPos=*currPosPtr,dirIndex=-1,currColSpan=1;
BOOL cont=YES;
HTML_t currToken;
MiscMatrix *currMatrix=[[MiscMatrix alloc] init];
Cell *prototype=nil;
BOOL currParagraphCentered=NO;
if(!prototype)
{ prototype=[[HTMLTextCell alloc] initWithHTML:"" inView:self];
}// now setBordered et al¼
[currMatrix setPrototype:prototype];
[currMatrix addRow];[currMatrix addCol];
for(;cont && (currPos< [parseString length]-1);)
{ if([parseString charAt:currPos] !='<') // plain text?
{ currPos++;
} else // directive¼
{ MiscString *tmpString;
dirIndex=currPos+1;
if(tmpString=[parseString extractBracketsContentWithPrefix:""
positionInsideLeft:&dirIndex
positionRight:&currPos
leftBracket:'<'
rightBracket:'>'
deleteContent:NO]) currPos++;
else
{ // NXLogError("HTML error near %d",currPos);
break;
}
switch(currToken=[self HTMLTokenForString:tmpString])
{ case HTML_TD:
{ int i;
List *attribs=[tmpString tokenize:" " into:nil];
MiscString *currStr;
currColSpan=1;
for(i=0; currStr=[attribs objectAt:i];i++)
{ List *keyVal=[currStr tokenize:"=" into:nil];
MiscString *key=[keyVal objectAt:0],*val=[keyVal objectAt:1];
if([key casestreq:"COLSPAN"])
{ currColSpan=[val intValue];
} else if([key casestreq:"ALIGN"])
{
} [[keyVal freeObjects] free];
} [[attribs freeObjects] free];
if(modeArray) modeArray[currToken]=currPos; // catch begin of run
if(currCol++ > maxCols)
{ [currMatrix addCol];
maxCols=currCol;
}
} break;
case HTML_TH:
modeArray[currToken]=currPos;
break;
case HTML_CENTER: currParagraphCentered=YES;
break;
case HTML_ENDCENTER: currParagraphCentered=NO;
break;
case HTML_ENDTR:
if(modeArray && modeArray[HTML_TH]>= 0) // fake the tablehead via its own table
{ int tmpPos=0;
MiscString *contentString=[self contentFor:HTML_TH inArr:modeArray in:parseString
right:dirIndex-2],
*tableString=[[MiscString alloc] initFromFormat:"<table><tr><td>%s</td></tr></table>",
[contentString stringValue]];
[self insertTableFromString:tableString atPos:&tmpPos modeArray:modeArray
textPos:textPos];
[contentString free];[tableString free];
}
break;
case HTML_TR:
if(currRow > maxRows)
{ [currMatrix addRow];
maxRows=currRow;
} currRow++;currCol=0;
break;
case HTML_ENDTD:
{ id currCell=[currMatrix cellAt:currRow-1:currCol-1];
MiscString *contentString=[self contentFor:currToken-1 inArr:modeArray in:parseString
right:dirIndex-2];
if(![contentString indexOfChars:"<"])
{ [contentString replaceEveryOccurrenceOfChar:'\r' with:""];
[contentString replaceEveryOccurrenceOfChar:'\n' with:""];
[contentString collapseHTMLQuotedChars];[contentString trimSpaces];
} [currCell setStringValue:[contentString stringValue]];
[currCell setColumnsSpanning:currColSpan];
[currCell setAlignment:currParagraphCentered? NX_CENTERALIGN:NX_LEFTALIGN];
[contentString free];
} break;
case HTML_ENDTABLE:
cont=NO;
break;
default: break;
}
}
} (*currPosPtr)=currPos;
[currMatrix sizeToFit];
[self setSel:*textPos:*textPos];
[self replaceSelWithCell:[[MiscTFMatrixCell alloc] initWithMatrix:currMatrix inView:self]];
(*textPos)++;
return self;
}
-(int) leftCp{ return sp0.cp;}
// sorry for this much to large method, but categorys dot have ivars
- setFromHTML:(const char *)htmlString andDelete:(BOOL) doClear
{ MiscString *parseString=[[MiscString alloc] initString:htmlString];
int textPos=0,rightPos=0,currPos=0,dirIndex=-1;
int modeArray[HTML_endOfHTMLList],posArray[HTML_endOfHTMLList];
HTML_t currToken,
liMode[MAX_NESTING]={HTML_endOfHTMLList}; // stacking:(using liNest as index)
int liCount[MAX_NESTING], listStarts[MAX_NESTING],liNest=0,formSession=0;
List *currRadioList=nil;
PopUpList *currPopupList=nil;
id currPopupCell=nil;
BOOL currParagraphCentered=NO,hasBackground=NO,preMode=NO;
if(sharedField) [sharedField removeFromSuperview];
if(sharedButton) [sharedButton removeFromSuperview];
[self setGraphicsImportEnabled:YES];
[self setMonoFont:NO];
memset(modeArray,-1,(HTML_endOfHTMLList-1)*sizeof(int)); // init stateMachineArray
if(doClear)
{ //[self selectText:self];[self replaceSel:""]; // clear
[self setText:""];
[self setSel:0:0];
}
// here we have to clean the viewhierarchy from zombi-HTML-views (Tables, forms etc.¼ )
for(textPos=[self leftCp];currPos< [parseString length]-1;)
{ if([parseString charAt:currPos] !='<') // plain text?
{ MiscString *tmpString;
dirIndex=[parseString spotOfChar:'<' startingAt:currPos];
if(dirIndex>= 0) rightPos= dirIndex-1;
else rightPos=[parseString length];
tmpString=[parseString midFrom:currPos to:rightPos];
currPos=rightPos+1;
if(![tmpString length] || (!preMode && [tmpString isWhite]))
{ [tmpString free];
continue;
}
[tmpString replaceEveryOccurrenceOfChar:'\r' with:""];
[tmpString collapseHTMLQuotedChars];
if(!preMode)
{ BOOL hadLeftWhite= ([tmpString charAt:0] == ' '),
hadRightWhite=([tmpString charAt:[tmpString length]-1] == ' ');
[tmpString replaceEveryOccurrenceOfChar:'\n' with:" "];
[tmpString trimWhiteSpaces];
if(hadLeftWhite) [tmpString insertChar:' ' at:0];
if(hadRightWhite) [tmpString insertChar:' ' at:[tmpString length]];
[tmpString replaceEveryOccurrenceOf:" " with:" " overlap:NO];
}
if(modeArray[HTML_TITLE]< 0 && modeArray[HTML_OPTION]< 0) // muted?
{ [self setSel:textPos:textPos];[self replaceSel:[tmpString stringValue]];
textPos+=[tmpString length];
} [tmpString free];
} else // directive¼
{ MiscString *tmpString;
dirIndex=currPos+1;
if(tmpString=[parseString extractBracketsContentWithPrefix:""
positionInsideLeft:&dirIndex
positionRight:&currPos
leftBracket:'<'
rightBracket:'>'
deleteContent:NO]) currPos++;
else
{ NXLogError("HTML error near %d\n",currPos);
break;
}
switch(currToken=[self HTMLTokenForString:tmpString])
{ case HTML_BODY:
[self setSel:textPos:textPos];
if([self insertBackground:tmpString])
{ textPos++;
hasBackground=YES;
}
break;
case HTML_TABLE:
[self insertTableFromString:parseString atPos:&currPos modeArray:modeArray
textPos:&textPos];
break;
case HTML_ENDTABLE:
break;
case HTML_LI:case HTML_DD:case HTML_DT:
{ char buf[100]={0};
if(currToken != HTML_LI && (modeArray[HTML_DT] >=0 || modeArray[HTML_DD] >= 0))
{ [self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
}
if(modeArray[currToken] >=0)
{ [self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
switch(currToken)
{ case HTML_DD:
[self setSel:posArray[currToken]:textPos-1];
[self setSelProp:NX_FIRSTINDENT to:INDENT_WIDTH];
[self setSelProp:NX_INDENT to:INDENT_WIDTH];
[self setSel:textPos:textPos];[self replaceSel:"\n"];textPos++;
[self normalizeRulerAt:textPos];
break;
default: break;
}
} if(currToken != HTML_LI)
{ modeArray[HTML_DT]=modeArray[HTML_DD]=-1; // in some cases superseded below
}
modeArray[currToken]=currPos; // catch begin of run
switch(LIST_MODE) // calculate prefix
{ case HTML_UL:strcpy (buf+strlen(buf),"·\t"); break;
case HTML_OL:sprintf(buf+strlen(buf),"%d.\t", LIST_COUNT++); break;
case HTML_DL:if(currToken != HTML_DT) strcpy(buf+strlen(buf),"\t"); break;
default:break;
} [self setSel:textPos:textPos];[self replaceSel:buf];
textPos+=strlen(buf);
} // HTML_LI: fall thru to catch¼
// for these remember the beginning of the element
case HTML_TITLE: case HTML_H1: case HTML_H2: case HTML_H4: case HTML_H6: case HTML_SUB:
case HTML_STRONG: case HTML_EM: case HTML_OPTION: case HTML_BLOCKQUOTE: case HTML_SAMP:
switch(currToken)
{ case HTML_H1:case HTML_H2:case HTML_H3:case HTML_H4:case HTML_H5:case HTML_H6:
case HTML_BLOCKQUOTE:
if(!([self charAt:textPos-1] == '\n'))
{ [self setSel:textPos:textPos];[self replaceSel:"\n"];textPos++;
} [self setSel:textPos:textPos];[self replaceSel:"\n"];textPos++;
break;
case HTML_OPTION:
// if(modeArray[currToken] >=0) [currPopupList addItem:[contentString stringValue]];
break;
default: break;
}
modeArray[currToken]=currPos; // catch begin of run
posArray [currToken]=textPos;
break;
case HTML_ENDTITLE: case HTML_ENDH2: case HTML_ENDH4: case HTML_ENDH1:case HTML_ENDH6:
case HTML_ENDSUB:
case HTML_ENDSTRONG: case HTML_ENDEM: case HTML_ENDLI: case HTML_ENDOPTION: // apply emphasis¼
if(modeArray[currToken-1]>= 0)
{ MiscString *contentString=[self contentFor:currToken-1 inArr:modeArray in:parseString
right:dirIndex-2];
[contentString trimWhiteSpaces];[contentString collapseHTMLQuotedChars];
switch(currToken)
{ case HTML_ENDTITLE:
if(delegate && [delegate respondsTo:@selector(setTitle:)])
[delegate setTitle:[contentString stringValue]];
break;
case HTML_ENDOPTION:
[currPopupList addItem:[contentString stringValue]];
break;
// here go the headers¼
case HTML_ENDH1: case HTML_ENDH2: case HTML_ENDH4: case HTML_ENDH6:
{ float size=18.0;
switch(currToken)
{ case HTML_ENDH1: size=25.0; break;
case HTML_ENDH2: size=18.0; break;
case HTML_ENDH4: size=12.0; break;
case HTML_ENDH6: size= 8.0; break;
default: break;
}
[self setSel:textPos:textPos];[self replaceSel:"\n"];
[self setSel:posArray[currToken-1]:textPos];
[self setSelFontStyle:NX_BOLD];
[self setSelFontSize:size];
textPos++;[self setSel:textPos:textPos];
} break;
case HTML_ENDSTRONG:
[self setSel:textPos:textPos];[self replaceSel:" "];
[self setSel:posArray[currToken-1]:textPos];
[self setSelFontStyle:NX_BOLD];
[self setSel:textPos:textPos+1];[self setSelFontStyle:NX_UNBOLD];
textPos++;[self setSel:textPos:textPos];
break;
case HTML_ENDEM:
[self setSel:textPos:textPos];[self replaceSel:" "];
[self setSel:posArray[currToken-1]:textPos];
[self setSelFontStyle:NX_ITALIC];
[self setSel:textPos:textPos+1];[self setSelFontStyle:NX_UNITALIC];
textPos++;[self setSel:textPos:textPos];
break;
case HTML_ENDSUB:
[self setSel:textPos:textPos];[self replaceSel:" "];
[self setSel:posArray[currToken-1]:textPos];
[self subscript:self];
[self setSel:textPos:textPos+1];[self unscript:self];
textPos++;[self setSel:textPos:textPos];
break;
case HTML_ENDLI:
[self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
modeArray[currToken-1]=-1;
break;
default: break; // yeah, here goes html3.0 :-(
} [contentString free];
} else
{ // error
}
break;
case HTML_HR:
[self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
[self setSel:textPos:textPos];[self replaceSelWithCell:[[HRCell alloc] initForText:self]];textPos++;
[self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
break;
case HTML_OL:case HTML_UL:case HTML_DL: // lists
modeArray[currToken]=currPos; posArray[currToken]=textPos;
if(modeArray[HTML_DT]>= 0)
{
modeArray[HTML_DT]=-1;
}
if(modeArray[HTML_DD]>= 0 && [self charAt:textPos-1]== '\t')
{ [self setSel:textPos-1:textPos];[self replaceSel:""]; textPos--;
}
if(!liNest || modeArray[HTML_LI] >=0 || [self charAt:textPos-1]!= '\n')
{ [self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
modeArray[HTML_LI]=-1;
} if(liNest)
{ [self setSel:LIST_START_POS:textPos-1];
[self setSelProp:NX_FIRSTINDENT to:INDENT_WIDTH*liNest];
[self setSelProp:NX_INDENT to:INDENT_WIDTH*liNest+20];
[self setSelProp:NX_ADDTAB to:INDENT_WIDTH*liNest+20];
[self setSel:textPos:textPos];
}
liNest++;
LIST_MODE=currToken;
if(currToken == HTML_OL) LIST_COUNT=1;
LIST_START_POS=textPos;
break;
case HTML_ENDUL: case HTML_ENDOL: case HTML_ENDDL:
if(modeArray[HTML_LI] >=0)
{ [self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
modeArray[HTML_LI]=-1;
}
if(liNest > 0) listStarts[liNest-1]=textPos;
[self setSel:LIST_START_POS:textPos-1];
[self removeAllTabs];
[self setSelProp:NX_FIRSTINDENT to:INDENT_WIDTH*liNest];
[self setSelProp:NX_INDENT to:INDENT_WIDTH*liNest+20];
[self setSelProp:NX_ADDTAB to:INDENT_WIDTH*liNest+20];
[self setSel:textPos:textPos];
if(liNest< 2)
{ [self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
[self normalizeRulerAt:textPos];
}
modeArray[currToken]=-1;liNest--;
liNest=MAX(liNest,0);
break;
case HTML_CENTER: currParagraphCentered=YES;
break;
case HTML_ENDCENTER: currParagraphCentered=NO;
break;
case HTML_P:case HTML_ENDP: // div. pragraphs
modeArray[currToken]=-1;
if(liNest && (LIST_MODE== HTML_UL || LIST_MODE== HTML_OL)) {break;} // no cr's in lists
[self setSel:textPos:textPos];[self replaceSel:"\n"];textPos++;
posArray [currToken]=textPos;
if(currToken == HTML_ENDP)
{ if(currParagraphCentered)
{ [self setSel:posArray [currToken-1]:textPos-1];[self alignSelCenter:self];
[self setSel:textPos-1:textPos];[self alignSelLeft:self];
[self setSel:textPos:textPos];// [self pasteRuler:self];
currParagraphCentered=NO;
}
}
break;
case HTML_ENDBLOCKQUOTE:
[self setSel:posArray[currToken-1]:textPos-1];
[self setSelProp:NX_FIRSTINDENT to:INDENT_WIDTH];
[self setSelProp:NX_INDENT to:INDENT_WIDTH];
[self setSel:textPos:textPos];[self replaceSel:"\n"];textPos++;
[self normalizeRulerAt:textPos];
break;
case HTML_FORMSESSION:
formSession++;
if(!currRadioList) currRadioList=[[List alloc] init];
break;
case HTML_ENDFORMSESSION:
if(currRadioList && [currRadioList count])
{ [currRadioList makeObjectsPerform:@selector(setCollegues:) with:currRadioList];
[currRadioList makeObjectsPerform:@selector(setState:) with:(id)NO];
}
currRadioList=nil;
break;
case HTML_FORMINPUT:
if([self insertFormElement:tmpString forSession:formSession radioList:currRadioList])
textPos++;
break;
case HTML_SELECT:
currPopupList=[[PopUpList alloc] init];
currPopupCell=[[MiscTFPopupCell alloc] initInText:self];
if(!sharedButton)
{ sharedButton=[[Button alloc] init];
}
[self setSel:textPos:textPos];[self replaceSelWithCell:currPopupCell];
textPos++;
break;
case HTML_ENDSELECT:
if(currPopupList && [currPopupList count])
{ NXRect aFrame;
[currPopupCell setPopupList:currPopupList];
[currPopupList sizeToFit];
[currPopupList getFrame:&aFrame];
[currPopupCell setWidth:NX_WIDTH(&aFrame)];
[currPopupCell setTitle:[[[[currPopupList itemList] cellList] objectAt:0] title]];
[[[currPopupList itemList] cellList] makeObjectsPerform:@selector(setTarget:) with:currPopupCell];
[[[currPopupList itemList] cellList] makeObjectsPerform:@selector(setAction:)
with:(id)@selector(takeTitleFrom:)];
}
currPopupList=nil;
break;
case HTML_PRE:
[self setSel:textPos:textPos];[self replaceSel:"\n"]; textPos++;
posArray [currToken]=textPos;
preMode=YES;
break;
case HTML_ENDPRE:
preMode=NO; // fall thru
// case HTML_ENDSAMP:
[self setSel:posArray[currToken-1]:textPos-1];
[self setSelFont:[Font userFixedPitchFontOfSize:10 matrix:NX_FLIPPEDMATRIX]];
[self setSel:textPos:textPos];
if(currToken == HTML_ENDPRE)
{ [self replaceSel:"\n"]; textPos++;
}
break;
case HTML_IMG:
[self setSel:textPos:textPos];
if([self insertImage:tmpString])
textPos++;
break;
case HTML_HREF: case HTML_NAME:
[self setSel:textPos:textPos];
if([self insertLink:tmpString])
textPos++;
break;
default: break; // yeah, here goes html3.0 :-(
} [tmpString free];
}
} if(!hasBackground)
{ [self setBackgroundGray:NX_LTGRAY];
}
// sizeToFit bug- workaround
if([self textLength] == 1 && [self charAt:0] == '¬')
{ [self setSel:0:0];[self replaceSel:" "];
[self setSel:2:2];[self replaceSel:" "];
}
return self;
}
- setFromHTML:(const char *)htmlString
{ return [self setFromHTML:htmlString andDelete:YES];
}
@endThese are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.