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]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.