ide.st 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. Widget subclass: #TabManager
  2. instanceVariableNames: 'selectedTab tabs opened'
  3. category: 'IDE'!
  4. TabManager class instanceVariableNames: 'current'!
  5. !TabManager class methodsFor: 'instance creation'!
  6. current
  7. ^current ifNil: [current := super new]
  8. !
  9. new
  10. self shouldNotImplement
  11. ! !
  12. !TabManager methodsFor: 'initialization'!
  13. initialize
  14. super initialize.
  15. opened := true.
  16. 'body' asJQuery
  17. append: self;
  18. append: [:html | html div id: 'jtalk'];
  19. addClass: 'jtalkBody'.
  20. self
  21. addTab: Transcript current;
  22. addTab: Workspace new.
  23. self selectTab: self tabs last.
  24. self
  25. onResize: [self updateBodyMargin; updatePosition];
  26. onWindowResize: [self updatePosition]
  27. ! !
  28. !TabManager methodsFor: 'accessing'!
  29. tabs
  30. ^tabs ifNil: [tabs := Array new]
  31. ! !
  32. !TabManager methodsFor: 'adding/Removing'!
  33. addTab: aWidget
  34. self tabs add: aWidget.
  35. '#jtalk' asJQuery append: aWidget.
  36. aWidget root asJQuery hide
  37. !
  38. removeTab: aWidget
  39. self tabs remove: aWidget.
  40. self update
  41. ! !
  42. !TabManager methodsFor: 'actions'!
  43. updateBodyMargin
  44. self setBodyMargin: '#jtalk' asJQuery height + 27
  45. !
  46. updatePosition
  47. {'jQuery(''#jtalk'').css(''top'', '''''').css(''bottom'', ''27px'');'}
  48. !
  49. removeBodyMargin
  50. self setBodyMargin: 0
  51. !
  52. setBodyMargin: anInteger
  53. '.jtalkBody' asJQuery cssAt: 'margin-bottom' put: anInteger asString, 'px'
  54. !
  55. onResize: aBlock
  56. {'jQuery(''#jtalk'').resizable({
  57. handles: ''n'',
  58. resize: aBlock,
  59. minHeight: 230
  60. });'}
  61. !
  62. onWindowResize: aBlock
  63. {'jQuery(window).resize(aBlock)'}
  64. !
  65. open
  66. opened ifFalse: [
  67. self root asJQuery show.
  68. 'body' asJQuery addClass: 'jtalkBody'.
  69. '#jtalk' asJQuery show.
  70. self updateBodyMargin.
  71. selectedTab root asJQuery show.
  72. opened := true]
  73. !
  74. close
  75. opened ifTrue: [
  76. self root asJQuery hide.
  77. '#jtalk' asJQuery hide.
  78. self removeBodyMargin.
  79. 'body' asJQuery removeClass: 'jtalkBody'.
  80. opened := false]
  81. !
  82. newBrowserTab
  83. Browser open
  84. !
  85. selectTab: aWidget
  86. self open.
  87. selectedTab := aWidget.
  88. self tabs do: [:each |
  89. each root asJQuery hide].
  90. aWidget root asJQuery show.
  91. self update
  92. !
  93. closeTab: aWidget
  94. self removeTab: aWidget.
  95. self selectTab: self tabs last.
  96. aWidget root asJQuery remove.
  97. self update
  98. ! !
  99. !TabManager methodsFor: 'rendering'!
  100. renderOn: html
  101. html ul
  102. id: 'jtalkTabs';
  103. with: [
  104. html li
  105. class: 'closeAll';
  106. with: 'x';
  107. onClick: [self close].
  108. self tabs do: [:each |
  109. self renderTabFor: each on: html].
  110. html li
  111. class: 'newtab';
  112. with: ' + ';
  113. onClick: [self newBrowserTab]]
  114. !
  115. renderTabFor: aWidget on: html
  116. | li |
  117. li := html li.
  118. selectedTab = aWidget ifTrue: [
  119. li class: 'selected'].
  120. li with: [
  121. html span
  122. with: aWidget label;
  123. onClick: [self selectTab: aWidget].
  124. aWidget canBeClosed ifTrue: [
  125. html span
  126. class: 'close';
  127. with: 'x';
  128. onClick: [self closeTab: aWidget]]]
  129. ! !
  130. Widget subclass: #TabWidget
  131. instanceVariableNames: ''
  132. category: 'IDE'!
  133. !TabWidget class methodsFor: 'instance creation'!
  134. open
  135. ^self new open
  136. ! !
  137. !TabWidget methodsFor: 'accessing'!
  138. label
  139. self subclassResponsibility
  140. ! !
  141. !TabWidget methodsFor: 'actions'!
  142. open
  143. TabManager current
  144. addTab: self;
  145. selectTab: self
  146. ! !
  147. !TabWidget methodsFor: 'testing'!
  148. canBeClosed
  149. ^false
  150. ! !
  151. !TabWidget methodsFor: 'rendering'!
  152. renderOn: html
  153. html root
  154. class: 'jtalkTool';
  155. with: [
  156. html div
  157. class: 'jt_box';
  158. with: [self renderBoxOn: html].
  159. html div
  160. class: 'jt_buttons';
  161. with: [self renderButtonsOn: html]]
  162. !
  163. renderBoxOn: html
  164. !
  165. renderButtonsOn: html
  166. ! !
  167. TabWidget subclass: #Workspace
  168. instanceVariableNames: 'textarea'
  169. category: 'IDE'!
  170. !Workspace methodsFor: 'accessing'!
  171. label
  172. ^'[Workspace]'
  173. !
  174. selection
  175. ^{'return document.selection'}
  176. !
  177. selectionStart
  178. ^{'return jQuery(''.jt_workspace'')[0].selectionStart'}
  179. !
  180. selectionEnd
  181. ^{'return jQuery(''.jt_workspace'')[0].selectionEnd'}
  182. !
  183. selectionStart: anInteger
  184. {'jQuery(''.jt_workspace'')[0].selectionStart = anInteger'}
  185. !
  186. selectionEnd: anInteger
  187. {'jQuery(''.jt_workspace'')[0].selectionEnd = anInteger'}
  188. !
  189. currentLine
  190. | lines startLine endLine|
  191. lines := textarea asJQuery val tokenize: String cr.
  192. startLine := endLine := 0.
  193. lines do: [:each |
  194. endLine := startLine + each size.
  195. startLine := endLine + 1.
  196. endLine >= self selectionStart ifTrue: [
  197. self selectionEnd: endLine.
  198. ^each]]
  199. ! !
  200. !Workspace methodsFor: 'actions'!
  201. handleKeyDown: anEvent
  202. ^{'if(anEvent.ctrlKey) {
  203. if(anEvent.keyCode === 68) { //ctrl+p
  204. self._printIt();
  205. return false;
  206. }
  207. if(anEvent.keyCode === 80) { //ctrl+d
  208. self._doIt();
  209. return false;
  210. }
  211. }'}
  212. !
  213. clearWorkspace
  214. textarea asJQuery val: ''
  215. !
  216. doIt
  217. self printIt
  218. !
  219. printIt
  220. | selection |
  221. textarea asJQuery focus.
  222. self selectionStart = self selectionEnd
  223. ifTrue: [selection := self currentLine]
  224. ifFalse: [
  225. selection := textarea asJQuery val copyFrom: self selectionStart + 1 to: self selectionEnd + 1].
  226. self print: (self eval: selection) printString
  227. !
  228. print: aString
  229. | start |
  230. start := self selectionEnd.
  231. textarea asJQuery val: (
  232. (textarea asJQuery val copyFrom: 1 to: start),
  233. ' ', aString, ' ',
  234. (textarea asJQuery val copyFrom: start + 1 to: textarea asJQuery val size)).
  235. self selectionStart: start.
  236. self selectionEnd: start + aString size + 2
  237. !
  238. eval: aString
  239. | compiler node |
  240. compiler := Compiler new.
  241. node := compiler parseExpression: aString.
  242. node isParseFailure ifTrue: [
  243. ^self alert: node reason, ', position: ', node position].
  244. ^compiler loadExpression: aString
  245. ! !
  246. !Workspace methodsFor: 'rendering'!
  247. renderBoxOn: html
  248. textarea := html textarea.
  249. textarea asJQuery call: 'tabby'.
  250. textarea onKeyDown: [:e | self handleKeyDown: e].
  251. textarea
  252. class: 'jt_workspace';
  253. at: 'spellcheck' put: 'false'
  254. !
  255. renderButtonsOn: html
  256. html button
  257. with: 'DoIt';
  258. title: 'ctrl+d';
  259. onClick: [self doIt].
  260. html button
  261. with: 'PrintIt';
  262. title: 'ctrl+p';
  263. onClick: [self printIt].
  264. html button
  265. with: 'Clear workspace';
  266. onClick: [self clearWorkspace]
  267. ! !
  268. TabWidget subclass: #Transcript
  269. instanceVariableNames: 'textarea'
  270. category: 'IDE'!
  271. Transcript class instanceVariableNames: 'current'!
  272. !Transcript class methodsFor: 'instance creation'!
  273. open
  274. self current open
  275. !
  276. new
  277. self shouldNotImplement
  278. !
  279. current
  280. ^current ifNil: [current := super new]
  281. ! !
  282. !Transcript class methodsFor: 'printing'!
  283. show: anObject
  284. self current show: anObject
  285. !
  286. cr
  287. self current show: String cr
  288. !
  289. clear
  290. self current clear
  291. ! !
  292. !Transcript methodsFor: 'accessing'!
  293. label
  294. ^'[Transcript]'
  295. ! !
  296. !Transcript methodsFor: 'actions'!
  297. show: anObject
  298. textarea asJQuery val: textarea asJQuery val, anObject asString.
  299. !
  300. cr
  301. textarea asJQuery val: textarea asJQuery val, String cr.
  302. !
  303. clear
  304. textarea asJQuery val: ''
  305. ! !
  306. !Transcript methodsFor: 'rendering'!
  307. renderBoxOn: html
  308. textarea := html textarea.
  309. textarea asJQuery call: 'tabby'.
  310. textarea
  311. class: 'jt_transcript';
  312. at: 'spellcheck' put: 'false'
  313. !
  314. renderButtonsOn: html
  315. html button
  316. with: 'Clear transcript';
  317. onClick: [self clear]
  318. ! !
  319. TabWidget subclass: #Browser
  320. instanceVariableNames: 'selectedCategory selectedClass selectedProtocol selectedMethod commitButton categoriesList classesList protocolsList methodsList sourceTextarea tabsList selectedTab saveButton classButtons methodButtons unsavedChanges'
  321. category: 'IDE'!
  322. !Browser class methodsFor: 'convenience'!
  323. openOn: aClass
  324. self new
  325. open;
  326. selectCategory: aClass category;
  327. selectClass: aClass
  328. !
  329. open
  330. self new open
  331. ! !
  332. !Browser methodsFor: 'initialization'!
  333. initialize
  334. super initialize.
  335. selectedTab := #instance.
  336. unsavedChanges := false
  337. ! !
  338. !Browser methodsFor: 'accessing'!
  339. label
  340. ^selectedClass
  341. ifNil: ['Browser (nil)']
  342. ifNotNil: [selectedClass name]
  343. !
  344. categories
  345. | categories |
  346. categories := Array new.
  347. Smalltalk current classes do: [:each |
  348. (categories includes: each category) ifFalse: [
  349. categories add: each category]].
  350. ^categories sort
  351. !
  352. classes
  353. ^(Smalltalk current classes
  354. select: [:each | each category = selectedCategory])
  355. sort: [:a :b | a name > b name]
  356. !
  357. protocols
  358. | klass protocols |
  359. protocols := Array new.
  360. selectedClass ifNotNil: [
  361. selectedTab = #comment ifTrue: [^#()].
  362. klass := selectedTab = #instance
  363. ifTrue: [selectedClass]
  364. ifFalse: [selectedClass class].
  365. klass methodDictionary isEmpty ifTrue: [
  366. protocols add: 'not yet classified'].
  367. klass methodDictionary do: [:each |
  368. (protocols includes: each category) ifFalse: [
  369. protocols add: each category]]].
  370. ^protocols sort
  371. !
  372. methods
  373. | klass |
  374. selectedTab = #comment ifTrue: [^#()].
  375. selectedClass ifNotNil: [
  376. klass := selectedTab = #instance
  377. ifTrue: [selectedClass]
  378. ifFalse: [selectedClass class]].
  379. ^(selectedProtocol
  380. ifNil: [
  381. klass
  382. ifNil: [#()]
  383. ifNotNil: [klass methodDictionary values]]
  384. ifNotNil: [
  385. klass methodDictionary values select: [:each |
  386. each category = selectedProtocol]]) sort: [:a :b | a selector > b selector]
  387. !
  388. source
  389. selectedTab = #comment ifFalse: [
  390. ^(selectedProtocol notNil or: [selectedMethod notNil])
  391. ifFalse: [self declarationSource]
  392. ifTrue: [self methodSource]].
  393. ^selectedClass
  394. ifNil: ['']
  395. ifNotNil: [self classCommentSource]
  396. !
  397. methodSource
  398. ^selectedMethod
  399. ifNil: [self dummyMethodSource]
  400. ifNotNil: [selectedMethod source]
  401. !
  402. dummyMethodSource
  403. ^'messageSelectorAndArgumentNames
  404. "comment stating purpose of message"
  405. | temporary variable names |
  406. statements'
  407. !
  408. declarationSource
  409. ^selectedTab = #instance
  410. ifTrue: [self classDeclarationSource]
  411. ifFalse: [self metaclassDeclarationSource]
  412. !
  413. classDeclarationSource
  414. | stream |
  415. stream := '' writeStream.
  416. selectedClass ifNotNil: [
  417. stream
  418. nextPutAll: selectedClass superclass asString;
  419. nextPutAll: ' subclass: #';
  420. nextPutAll: selectedClass name;
  421. nextPutAll: String cr, String tab;
  422. nextPutAll: 'instanceVariableNames: '''.
  423. selectedClass instanceVariableNames
  424. do: [:each | stream nextPutAll: each]
  425. separatedBy: [stream nextPutAll: ' '].
  426. stream
  427. nextPutAll: '''', String cr, String tab;
  428. nextPutAll: 'category: ''';
  429. nextPutAll: selectedClass category;
  430. nextPutAll: ''''].
  431. ^stream contents
  432. !
  433. metaclassDeclarationSource
  434. | stream |
  435. stream := '' writeStream.
  436. selectedClass ifNotNil: [
  437. stream
  438. nextPutAll: selectedClass asString;
  439. nextPutAll: ' class ';
  440. nextPutAll: 'instanceVariableNames: '''.
  441. selectedClass class instanceVariableNames
  442. do: [:each | stream nextPutAll: each]
  443. separatedBy: [stream nextPutAll: ' '].
  444. stream nextPutAll: ''''].
  445. ^stream contents
  446. !
  447. classCommentSource
  448. ^selectedClass comment
  449. ! !
  450. !Browser methodsFor: 'actions'!
  451. enableSaveButton
  452. saveButton removeAt: 'disabled'.
  453. unsavedChanges := true
  454. !
  455. disableSaveButton
  456. saveButton ifNotNil: [
  457. saveButton at: 'disabled' put: true].
  458. unsavedChanges := false
  459. !
  460. hideClassButtons
  461. classButtons asJQuery hide
  462. !
  463. showClassButtons
  464. classButtons asJQuery show
  465. !
  466. hideMethodButtons
  467. methodButtons asJQuery hide
  468. !
  469. showMethodButtons
  470. methodButtons asJQuery show
  471. !
  472. compile
  473. self disableSaveButton.
  474. selectedTab = #comment ifTrue: [
  475. selectedClass ifNotNil: [
  476. self compileClassComment]].
  477. (selectedProtocol notNil or: [selectedMethod notNil])
  478. ifFalse: [self compileDefinition]
  479. ifTrue: [self compileMethodDefinition]
  480. !
  481. compileClassComment
  482. selectedClass comment: sourceTextarea asJQuery val
  483. !
  484. compileMethodDefinition
  485. selectedTab = #instance
  486. ifTrue: [self compileMethodDefinitionFor: selectedClass]
  487. ifFalse: [self compileMethodDefinitionFor: selectedClass class]
  488. !
  489. compileMethodDefinitionFor: aClass
  490. | compiler method source node |
  491. source := sourceTextarea asJQuery val.
  492. selectedProtocol ifNil: [selectedProtocol := selectedMethod category].
  493. compiler := Compiler new.
  494. node := compiler parse: source.
  495. node isParseFailure ifTrue: [
  496. ^self alert: 'PARSE ERROR: ', node reason, ', position: ', node position asString].
  497. compiler currentClass: selectedClass.
  498. method := compiler eval: (compiler compileNode: node).
  499. method category: selectedProtocol.
  500. aClass addCompiledMethod: method.
  501. self updateMethodsList.
  502. self selectMethod: method
  503. !
  504. compileDefinition
  505. | newClass |
  506. newClass := Compiler new loadExpression: sourceTextarea asJQuery val.
  507. self
  508. updateCategoriesList;
  509. updateClassesList
  510. !
  511. commitCategory
  512. selectedCategory ifNotNil: [
  513. (Ajax url: 'js/', selectedCategory, '.js')
  514. at: 'type' put: 'PUT';
  515. at: 'data' put: (Exporter new exportCategory: selectedCategory);
  516. at: 'error' put: [self alert: 'Commit failed!!'];
  517. send]
  518. !
  519. cancelChanges
  520. ^unsavedChanges
  521. ifTrue: [self confirm: 'Cancel changes?']
  522. ifFalse: [true]
  523. !
  524. removeClass
  525. (self confirm: 'Do you really want to remove ', selectedClass name, '?')
  526. ifTrue: [
  527. Smalltalk current basicDelete: selectedClass name.
  528. self selectClass: nil]
  529. !
  530. removeMethod
  531. self cancelChanges ifTrue: [
  532. (self confirm: 'Do you really want to remove #', selectedMethod selector, '?')
  533. ifTrue: [
  534. selectedClass removeCompiledMethod: selectedMethod.
  535. self selectMethod: nil]]
  536. !
  537. setMethodProtocol: aString
  538. self cancelChanges ifTrue: [
  539. (self protocols includes: aString)
  540. ifFalse: [self addNewProtocol]
  541. ifTrue: [
  542. selectedMethod category: aString.
  543. selectedProtocol := aString.
  544. selectedMethod := selectedMethod.
  545. self
  546. updateProtocolsList;
  547. updateMethodsList;
  548. updateSourceAndButtons]]
  549. !
  550. addNewProtocol
  551. | newProtocol |
  552. newProtocol := self prompt: 'New method protocol'.
  553. newProtocol notEmpty ifTrue: [
  554. selectedMethod category: newProtocol.
  555. self setMethodProtocol: newProtocol]
  556. !
  557. selectCategory: aCategory
  558. self cancelChanges ifTrue: [
  559. selectedCategory := aCategory.
  560. selectedClass := selectedProtocol := selectedMethod := nil.
  561. self
  562. updateCategoriesList;
  563. updateClassesList;
  564. updateProtocolsList;
  565. updateMethodsList;
  566. updateSourceAndButtons]
  567. !
  568. selectClass: aClass
  569. self cancelChanges ifTrue: [
  570. selectedClass := aClass.
  571. selectedProtocol := selectedMethod := nil.
  572. self
  573. updateClassesList;
  574. updateProtocolsList;
  575. updateMethodsList;
  576. updateSourceAndButtons]
  577. !
  578. selectProtocol: aString
  579. self cancelChanges ifTrue: [
  580. selectedProtocol := aString.
  581. selectedMethod := nil.
  582. self
  583. updateProtocolsList;
  584. updateMethodsList;
  585. updateSourceAndButtons]
  586. !
  587. selectMethod: aMethod
  588. self cancelChanges ifTrue: [
  589. selectedMethod := aMethod.
  590. self
  591. updateProtocolsList;
  592. updateMethodsList;
  593. updateSourceAndButtons]
  594. !
  595. selectTab: aString
  596. self cancelChanges ifTrue: [
  597. selectedTab := aString.
  598. self selectProtocol: nil.
  599. self updateTabsList]
  600. ! !
  601. !Browser methodsFor: 'rendering'!
  602. renderBoxOn: html
  603. self
  604. renderTopPanelOn: html;
  605. renderTabsOn: html;
  606. renderBottomPanelOn: html
  607. !
  608. renderTopPanelOn: html
  609. html div
  610. class: 'top';
  611. with: [
  612. categoriesList := html ul class: 'jt_column categories'.
  613. commitButton := html button
  614. class: 'jt_commit';
  615. title: 'Commit classes in this category to disk';
  616. onClick: [self commitCategory];
  617. with: 'Commit category'.
  618. classesList := html ul class: 'jt_column classes'.
  619. protocolsList := html ul class: 'jt_column protocols'.
  620. methodsList := html ul class: 'jt_column methods'.
  621. self
  622. updateCategoriesList;
  623. updateClassesList;
  624. updateProtocolsList;
  625. updateMethodsList.
  626. html div class: 'jt_clear']
  627. !
  628. renderTabsOn: html
  629. tabsList := html ul class: 'jt_tabs'.
  630. self updateTabsList.
  631. !
  632. renderBottomPanelOn: html
  633. html div
  634. class: 'jt_sourceCode';
  635. with: [
  636. sourceTextarea := html textarea
  637. onKeyPress: [self enableSaveButton];
  638. class: 'source';
  639. at: 'spellcheck' put: 'false'.
  640. sourceTextarea asJQuery call: 'tabby']
  641. !
  642. renderButtonsOn: html
  643. saveButton := html button.
  644. saveButton
  645. with: 'Save';
  646. onClick: [self compile].
  647. methodButtons := html span.
  648. classButtons := html span.
  649. self updateSourceAndButtons
  650. ! !
  651. !Browser methodsFor: 'updating'!
  652. updateCategoriesList
  653. categoriesList contents: [:html |
  654. self categories do: [:each || li |
  655. li := html li.
  656. selectedCategory = each ifTrue: [
  657. li class: 'selected'].
  658. li
  659. with: each;
  660. onClick: [self selectCategory: each]]]
  661. !
  662. updateClassesList
  663. TabManager current update.
  664. classesList contents: [:html |
  665. self classes do: [:each || li |
  666. li := html li.
  667. selectedClass = each ifTrue: [
  668. li class: 'selected'].
  669. li
  670. with: each name;
  671. onClick: [self selectClass: each]]]
  672. !
  673. updateProtocolsList
  674. protocolsList contents: [:html |
  675. self protocols do: [:each || li |
  676. li := html li.
  677. selectedProtocol = each ifTrue: [
  678. li class: 'selected'].
  679. li
  680. with: each;
  681. onClick: [self selectProtocol: each]]]
  682. !
  683. updateMethodsList
  684. methodsList contents: [:html |
  685. self methods do: [:each || li |
  686. li := html li.
  687. selectedMethod = each ifTrue: [
  688. li class: 'selected'].
  689. li
  690. with: each selector;
  691. onClick: [self selectMethod: each]]]
  692. !
  693. updateTabsList
  694. tabsList contents: [:html || li |
  695. li := html li.
  696. selectedTab = #instance ifTrue: [li class: 'selected'].
  697. li
  698. with: 'Instance';
  699. onClick: [self selectTab: #instance].
  700. li := html li.
  701. selectedTab = #class ifTrue: [li class: 'selected'].
  702. li
  703. with: 'Class';
  704. onClick: [self selectTab: #class].
  705. li := html li.
  706. selectedTab = #comment ifTrue: [li class: 'selected'].
  707. li
  708. with: 'Comment';
  709. onClick: [self selectTab: #comment]]
  710. !
  711. updateSourceAndButtons
  712. self disableSaveButton.
  713. classButtons contents: [:html |
  714. html button
  715. with: 'Remove class';
  716. onClick: [self removeClass]].
  717. methodButtons contents: [:html |
  718. html button
  719. with: 'Remove method';
  720. onClick: [self removeMethod].
  721. html select
  722. onChange: [:s | self setMethodProtocol: s val];
  723. with: [
  724. html option
  725. with: 'Method protocol';
  726. at: 'disabled' put: 'disabled'.
  727. html option
  728. class: 'important';
  729. with: 'New...'.
  730. self protocols do: [:each |
  731. html option with: each]]].
  732. selectedMethod
  733. ifNil: [
  734. self hideMethodButtons.
  735. selectedClass
  736. ifNil: [self hideClassButtons]
  737. ifNotNil: [self showClassButtons]]
  738. ifNotNil: [
  739. self hideClassButtons.
  740. self showMethodButtons].
  741. sourceTextarea asJQuery val: self source
  742. ! !
  743. !Browser methodsFor: 'testing'!
  744. canBeClosed
  745. ^true
  746. ! !