1
0

ide.st 18 KB

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