SystemOrganization addCategory: #'TextLint-Seaside'! !TLSyntacticElement methodsFor: '*textlint-seaside' stamp: 'lr 11/3/2010 19:54'! renderStart: aFailure on: html html anchor name: aFailure element start printString; with: [ ]. html document openTag: 'a' attributes: (WAHtmlAttributes new at: 'class' put: 'problem'; at: 'href' put: '#' , (aFailure rule class name allButFirst: 2); at: 'title' put: aFailure rule name , ': ' , aFailure rule rationale; yourself) closed: false! ! !TLSyntacticElement methodsFor: '*textlint-seaside' stamp: 'lr 10/26/2010 13:24'! renderStarts: starts stops: stops on: html [ starts notEmpty and: [ starts first element start <= self start ] ] whileTrue: [ self renderStart: starts removeFirst on: html ]. self renderTextOn: html. [ stops notEmpty and: [ stops first element stop <= self stop ] ] whileTrue: [ self renderStop: stops removeFirst on: html ]! ! !TLSyntacticElement methodsFor: '*textlint-seaside' stamp: 'lr 11/3/2010 15:24'! renderStop: aFailure on: html html document closeTag: 'a'! ! !TLSyntacticElement methodsFor: '*textlint-seaside' stamp: 'lr 10/26/2010 13:24'! renderTextOn: html html text: self text! ! !TLElement methodsFor: '*textlint-seaside' stamp: 'lr 10/25/2010 20:51'! renderStarts: starts stops: stops on: html self children do: [ :each | each renderStarts: starts stops: stops on: html ]! ! WAComponent subclass: #TLCustomComponent instanceVariableNames: 'query checker' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Seaside'! !TLCustomComponent class methodsFor: 'instance creation' stamp: 'lr 5/11/2011 20:36'! on: aString ^ self new initializeOn: aString! ! !TLCustomComponent methodsFor: 'initialization' stamp: 'lr 5/11/2011 21:20'! initializeOn: aString query := 'the {adjective} {noun}'. checker := TLTextLintChecker new. checker parse: aString. self search! ! !TLCustomComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 21:17'! renderButtonsOn: html. html paragraph class: 'buttons'; with: [ html submitButton callback: [ self answer ]; with: 'Go Back' ]! ! !TLCustomComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 21:17'! renderContentOn: html self renderQueryOn: html. self renderResultsOn: html. self renderButtonsOn: html! ! !TLCustomComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:45'! renderQueryOn: html html textInput text: query; callback: [ :value | query := value ]! ! !TLCustomComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 21:16'! renderResultsOn: html | starts stops | starts := checker results sortBy: [ :a :b | a element start < b element start ]. stops := checker results sortBy: [ :a :b | a element stop < b element stop ]. html div class: 'result'; with: [ checker document renderStarts: starts stops: stops on: html ]! ! !TLCustomComponent methodsFor: 'actions' stamp: 'lr 5/11/2011 21:19'! search! ! WAComponent subclass: #TLInputComponent instanceVariableNames: 'input' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Seaside'! !TLInputComponent methodsFor: 'actions' stamp: 'lr 5/11/2011 20:30'! analyze self show: (TLResultComponent on: (TLRootComponent analyze: input))! ! !TLInputComponent methodsFor: 'actions' stamp: 'lr 5/11/2011 20:59'! customize self show: (TLCustomComponent on: input)! ! !TLInputComponent methodsFor: 'initialization' stamp: 'lr 5/11/2011 20:19'! initialize super initialize. input := 'Please replace with the text you wish to analyze ...'! ! !TLInputComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:33'! renderButtonsOn: html html paragraph class: 'buttons'; with: [ html submitButton onClick: (html jQuery this attributeAt: 'enabled' put: false; text: 'Please Wait'; return: true); callback: [ self analyze ]; with: 'Analyze Text'. html submitButton callback: [ self customize ]; with: 'Custom Search' ]! ! !TLInputComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 19:56'! renderContentOn: html self renderIntroOn: html. self renderTextOn: html. self renderButtonsOn: html! ! !TLInputComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 19:57'! renderIntroOn: html html paragraph: 'TextLint is a tool to check your scientific writing for common style errors. To give it a try paste your plain text, HTML or LaTeX source into the input field below and click on "analyze text".'! ! !TLInputComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:33'! renderTextOn: html html div: [ html textArea value: input; script: (html jQuery this triggerFocus; triggerSelect); callback: [ :value | input := value ] ]! ! WAComponent subclass: #TLResultComponent instanceVariableNames: 'checker' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Seaside'! !TLResultComponent class methodsFor: 'instance creation' stamp: 'lr 5/11/2011 20:15'! on: aChecker ^ self new initializeOn: aChecker! ! !TLResultComponent methodsFor: 'initialization' stamp: 'lr 5/11/2011 20:16'! initializeOn: aChecker checker := aChecker! ! !TLResultComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:18'! renderButtonsOn: html. html paragraph class: 'buttons'; with: [ html submitButton callback: [ self answer ]; with: 'Go Back' ]! ! !TLResultComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:18'! renderContentOn: html self renderIntroOn: html. self renderResultOn: html. self renderButtonsOn: html! ! !TLResultComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:16'! renderIntroOn: html html paragraph: (checker results isEmpty ifTrue: [ 'Congratulations!! TextLint could not discover any issues in your text.' ] ifFalse: [ 'TextLint discovered ' , (checker results size printString) , ' possible issue' , (checker results size > 1 ifTrue: [ 's' ] ifFalse: [ '' ]) , ' in your text. Click an issue in the list to navigate to your text; click an issue in the text to navigate to an explanation of the issue.' ]) ! ! !TLResultComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 21:09'! renderListOn: html | groups | html unorderedList: [ groups := checker results groupedBy: [ :each | each rule class ]. groups := groups values sorted: [ :a :b | a first rule name < b first rule name ]. groups do: [ :failures | | rule | rule := failures first rule. html listItem: [ html heading level: 3; with: [ html anchor name: (rule class name allButFirst: 2). html text: rule name ]. html paragraph: [ html withLineBreaks: rule rationale ]. html orderedList: [ failures do: [ :failure | html listItem: [ html anchor url: '#' , failure element start printString; with: (failure element text truncate: 100) ] ] ] ] ] ]! ! !TLResultComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 20:18'! renderResultOn: html | starts stops | starts := checker results sortBy: [ :a :b | a element start < b element start ]. stops := checker results sortBy: [ :a :b | a element stop < b element stop ]. html div class: 'list'; with: [ self renderListOn: html ]. html div class: 'result'; with: [ checker document renderStarts: starts stops: stops on: html ]! ! WAComponent subclass: #TLRootComponent instanceVariableNames: 'content' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Seaside'! !TLRootComponent class methodsFor: 'utilities' stamp: 'lr 5/11/2011 20:10'! analyze: aString ^ self analyze: aString with: TLWritingStyle scientificPaperStyle rules! ! !TLRootComponent class methodsFor: 'utilities' stamp: 'lr 5/11/2011 21:07'! analyze: aString with: aCollectionOfRules | checker normalized | checker := TLTextLintChecker new. aCollectionOfRules do: [ :each | checker addRule: each ]. normalized := aString first: (aString size min: self maximumSize). self log: 'analyze' data: normalized. [ checker parse: normalized; results ] valueWithin: self maximumTime onTimeout: [ #() ]. self log: 'results' data: (String streamContents: [ :s | (checker results inject: Bag new into: [ :bag :each | bag add: each rule; yourself ]) valuesAndCounts keysAndValuesDo: [ :rule :count | s print: count; nextPut: $ ; nextPutAll: rule name; cr ] ]). ^ checker! ! !TLRootComponent class methodsFor: 'initialization' stamp: 'lr 5/11/2011 19:56'! initialize | application | application := WAAdmin register: self asApplicationAt: 'textlint'. application preferenceAt: #serverPath put: '/'. application addLibrary: JQGoogleLibrary. WAAdmin defaultDispatcher defaultName: 'textlint'. WAAdmin applicationDefaults removeParent: WADevelopmentConfiguration instance! ! !TLRootComponent class methodsFor: 'utilities' stamp: 'lr 5/11/2011 19:40'! log: aLabelString data: aDataString | directory context | directory := (FileDirectory default directoryNamed: 'logs') directoryNamed: (Date today printFormat: #(3 2 1 $- 1 1 2)). directory assureExistence. context := WACurrentRequestContext signal. directory fileNamed: context session key , '.log' do: [ :stream | stream setToEnd. stream nextPutAll: ' === '; print: TimeStamp now. stream nextPutAll: ' === '; nextPutAll: aLabelString. stream nextPutAll: ' === '; cr. stream nextPutAll: aDataString; cr; cr ]! ! !TLRootComponent class methodsFor: 'configuration' stamp: 'lr 5/11/2011 20:06'! maximumSize "200k should be enough for most papers." ^ 1024 * 1024 // 4! ! !TLRootComponent class methodsFor: 'configuration' stamp: 'lr 5/11/2011 20:08'! maximumTime "If this takes more than 10 seconds there is something wrong." ^ 10 seconds! ! !TLRootComponent methodsFor: 'initialization' stamp: 'lr 5/11/2011 19:50'! initialize super initialize. content := TLInputComponent new! ! !TLRootComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 19:51'! renderBodyOn: html html form: content! ! !TLRootComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 19:50'! renderContentOn: html html div class: 'head'; with: [ self renderHeadOn: html ]. html div class: 'body'; with: [ self renderBodyOn: html ]. html div class: 'foot'; with: [ self renderFootOn: html ]! ! !TLRootComponent methodsFor: 'rendering' stamp: 'lr 10/26/2010 21:40'! renderFootOn: html html paragraph: [ html anchor url: 'http://scg.unibe.ch/research/textlint'; with: 'TextLint'. html text: ' is a '. html anchor url: 'http://scg.unibe.ch/staff/fabrizioperin/'; with: 'Fabrizio Perin'. html text: ', '. html anchor url: 'http://www.lukas-renggli.ch/'; with: 'Lukas Renggli'. html text: ', and '. html anchor url: 'http://www.jorgeressia.com/'; with: 'Jorge Ressia'. html text: ' production.'. html break. html text: 'Powered by '. html anchor url: 'http://www.pharo-project.org/'; with: 'Pharo Smalltalk'. html text: ', '. html anchor url: 'http://www.seaside.st/'; with: 'Seaside'. html text: ', and '. html anchor url: 'http://www.mirandabanda.org/'; with: 'Cog'. html text: '.' ]! ! !TLRootComponent methodsFor: 'rendering' stamp: 'lr 5/11/2011 19:51'! renderHeadOn: html html heading level: 1; with: [ html span: self title ]! ! !TLRootComponent methodsFor: 'accessing' stamp: 'lr 5/11/2011 20:35'! style ^ '.head, .body, .foot { width: 800px; margin: 0 auto; } .head h1 { width: 263px; height: 100px; background-image: url("http://textlint.lukas-renggli.ch/images/logo.png"); } .head h1 span { display: none; } .body textarea, .body div.result { padding: 0; resize: none; width: 800px; height: 600px; line-height: 1.5; border: 1px solid #bbb; font: 1em "andale mono", "lucida console", monospace; } .body div.list { resize: none; overflow: auto; width: 810px; height: 200px; line-height: 1.5; border: 1px solid #bbb; border-bottom: none; } .body div.list ul { padding: 0; margin: 0; } .body div.list ul li { list-style-type: none; } .body div.list ul li h3 { margin: 0; padding: 5px; background: #eee; } .body div.list ul li p { margin: 0; padding: 5px; } .body div.list ol { margin: 0; padding: 0 0 10px 5px; } .body div.list ol li { margin: 0; padding: 0 0 0 10px; list-style-type: none; } .body div.result { overflow: auto; height: 400px; padding: 5px; white-space: pre-wrap; white-space: -moz-pre-wrap !!important; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; } .body div.result .markup { color: gray; } .body div.result .problem { border-bottom: 1px dotted red; color: red; text-decoration: none; } .body div.result .problem:hover { background: #fbe3e4; } .body p.buttons { text-align: center; padding-top: 10px; } .body p.buttons input { margin: 0 10px; } .foot p { font-size: 0.8em; text-align: center; }'! ! !TLRootComponent methodsFor: 'accessing' stamp: 'lr 10/25/2010 19:23'! title ^ 'TextLint'! ! !TLRootComponent methodsFor: 'updating' stamp: 'lr 11/3/2010 15:43'! updateRoot: aHtmlRoot super updateRoot: aHtmlRoot. aHtmlRoot beHtml5. aHtmlRoot title: self title. aHtmlRoot stylesheet url: 'http://textlint.lukas-renggli.ch/blueprint/screen.css'! ! !TLMarkup methodsFor: '*textlint-seaside' stamp: 'lr 10/26/2010 13:25'! renderTextOn: html html span class: 'markup'; with: [ super renderTextOn: html ]! ! TLRootComponent initialize!