Helios-Core.st 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. Smalltalk current createPackage: 'Helios-Core'!
  2. Object subclass: #HLModel
  3. instanceVariableNames: 'announcer environment'
  4. package: 'Helios-Core'!
  5. !HLModel methodsFor: 'accessing'!
  6. announcer
  7. ^ announcer ifNil: [ announcer := Announcer new ]
  8. !
  9. environment
  10. ^ environment ifNil: [ self manager environment ]
  11. !
  12. environment: anEnvironment
  13. environment := anEnvironment
  14. !
  15. manager
  16. ^ HLManager current
  17. !
  18. systemAnnouncer
  19. ^ self environment systemAnnouncer
  20. ! !
  21. !HLModel methodsFor: 'error handling'!
  22. withChangesDo: aBlock
  23. [
  24. self announcer announce: (HLAboutToChange new
  25. actionBlock: aBlock).
  26. aBlock value.
  27. ]
  28. on: HLChangeForbidden
  29. do: [ :ex | ]
  30. ! !
  31. !HLModel methodsFor: 'testing'!
  32. isBrowserModel
  33. ^ false
  34. !
  35. isReferencesModel
  36. ^ false
  37. !
  38. isToolModel
  39. ^ false
  40. ! !
  41. HLModel subclass: #HLToolModel
  42. instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
  43. package: 'Helios-Core'!
  44. !HLToolModel methodsFor: 'accessing'!
  45. allSelectors
  46. ^ self environment allSelectors
  47. !
  48. availableClassNames
  49. ^ self environment availableClassNames
  50. !
  51. availablePackageNames
  52. ^ self environment availablePackageNames
  53. !
  54. availablePackages
  55. ^ self environment availablePackageNames
  56. !
  57. availableProtocols
  58. ^ self environment availableProtocolsFor: self selectedClass
  59. !
  60. packages
  61. ^ self environment packages
  62. !
  63. selectedClass
  64. ^ selectedClass
  65. !
  66. selectedClass: aClass
  67. (self selectedClass = aClass and: [ aClass isNil ])
  68. ifTrue: [ ^ self ].
  69. self withChangesDo: [
  70. selectedClass = aClass ifTrue: [
  71. self selectedProtocol: nil ].
  72. aClass
  73. ifNil: [ selectedClass := nil ]
  74. ifNotNil: [
  75. self selectedPackage: aClass theNonMetaClass package.
  76. self showInstance
  77. ifTrue: [ selectedClass := aClass theNonMetaClass ]
  78. ifFalse: [ selectedClass := aClass theMetaClass ] ].
  79. self selectedProtocol: nil.
  80. self announcer announce: (HLClassSelected on: self selectedClass) ]
  81. !
  82. selectedMethod
  83. ^ self selectedClass ifNotNil: [
  84. self selectedClass methodDictionary
  85. at: selectedSelector
  86. ifAbsent: [ nil ] ]
  87. !
  88. selectedMethod: aCompiledMethod
  89. selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
  90. self withChangesDo: [
  91. aCompiledMethod
  92. ifNil: [ selectedSelector := nil ]
  93. ifNotNil: [
  94. selectedClass := aCompiledMethod methodClass.
  95. selectedSelector := aCompiledMethod selector ].
  96. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  97. !
  98. selectedPackage
  99. ^ selectedPackage
  100. !
  101. selectedPackage: aPackage
  102. selectedPackage = aPackage ifTrue: [ ^ self ].
  103. self withChangesDo: [
  104. selectedPackage := aPackage.
  105. self selectedClass: nil.
  106. self announcer announce: (HLPackageSelected on: aPackage) ]
  107. !
  108. selectedProtocol
  109. ^ selectedProtocol
  110. !
  111. selectedProtocol: aString
  112. selectedProtocol = aString ifTrue: [ ^ self ].
  113. self withChangesDo: [
  114. selectedProtocol := aString.
  115. self selectedMethod: nil.
  116. self announcer announce: (HLProtocolSelected on: aString) ]
  117. ! !
  118. !HLToolModel methodsFor: 'actions'!
  119. addInstVarNamed: aString
  120. self environment addInstVarNamed: aString to: self selectedClass.
  121. self announcer announce: (HLInstVarAdded new
  122. theClass: self selectedClass;
  123. variableName: aString;
  124. yourself)
  125. !
  126. save: aString
  127. self announcer announce: HLSourceCodeSaved new.
  128. (self shouldCompileClassDefinition: aString)
  129. ifTrue: [ self compileClassDefinition: aString ]
  130. ifFalse: [ self compileMethod: aString ]
  131. !
  132. saveSourceCode
  133. self announcer announce: HLSaveSourceCode new
  134. ! !
  135. !HLToolModel methodsFor: 'commands actions'!
  136. commitPackage
  137. self
  138. withHelperLabelled: 'Committing package ', self selectedPackage name, '...'
  139. do: [ self environment commitPackage: self selectedPackage ]
  140. !
  141. copyClassTo: aClassName
  142. self withChangesDo: [
  143. self environment
  144. copyClass: self selectedClass theNonMetaClass
  145. to: aClassName ]
  146. !
  147. moveClassToPackage: aPackageName
  148. self withChangesDo: [
  149. self environment
  150. moveClass: self selectedClass theNonMetaClass
  151. toPackage: aPackageName ]
  152. !
  153. moveMethodToClass: aClassName
  154. self withChangesDo: [
  155. self environment
  156. moveMethod: self selectedMethod
  157. toClass: aClassName ]
  158. !
  159. moveMethodToProtocol: aProtocol
  160. self withChangesDo: [
  161. self environment
  162. moveMethod: self selectedMethod
  163. toProtocol: aProtocol ]
  164. !
  165. openClassNamed: aString
  166. | class |
  167. self withChangesDo: [
  168. class := self environment classNamed: aString.
  169. self selectedPackage: class package.
  170. self selectedClass: class ]
  171. !
  172. removeClass
  173. self withChangesDo: [
  174. self manager
  175. confirm: 'Do you REALLY want to remove class ', self selectedClass name
  176. ifTrue: [ self environment removeClass: self selectedClass ] ]
  177. !
  178. removeMethod
  179. self withChangesDo: [
  180. self manager
  181. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  182. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  183. !
  184. removeProtocol
  185. self withChangesDo: [
  186. self manager
  187. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  188. ifTrue: [ self environment
  189. removeProtocol: self selectedProtocol
  190. from: self selectedClass ] ]
  191. !
  192. renameClassTo: aClassName
  193. self withChangesDo: [
  194. self environment
  195. renameClass: self selectedClass theNonMetaClass
  196. to: aClassName ]
  197. !
  198. renameProtocolTo: aString
  199. self withChangesDo: [
  200. self environment
  201. renameProtocol: self selectedProtocol
  202. to: aString
  203. in: self selectedClass ]
  204. ! !
  205. !HLToolModel methodsFor: 'compiling'!
  206. compileClassComment: aString
  207. self environment
  208. compileClassComment: aString
  209. for: self selectedClass
  210. !
  211. compileClassDefinition: aString
  212. self environment compileClassDefinition: aString
  213. !
  214. compileMethod: aString
  215. | method |
  216. self withCompileErrorHandling: [
  217. method := self environment
  218. compileMethod: aString
  219. for: self selectedClass
  220. protocol: self compilationProtocol.
  221. self selectedMethod: method ]
  222. ! !
  223. !HLToolModel methodsFor: 'defaults'!
  224. allProtocol
  225. ^ '-- all --'
  226. !
  227. unclassifiedProtocol
  228. ^ 'as yet unclassified'
  229. ! !
  230. !HLToolModel methodsFor: 'error handling'!
  231. handleCompileError: anError
  232. self announcer announce: (HLCompileErrorRaised new
  233. error: anError;
  234. yourself)
  235. !
  236. handleParseError: anError
  237. | split line column messageToInsert |
  238. split := anError messageText tokenize: ' : '.
  239. messageToInsert := split second.
  240. "21 = 'Parse error on line ' size + 1"
  241. split := split first copyFrom: 21 to: split first size.
  242. split := split tokenize: ' column '.
  243. line := split first.
  244. column := split second.
  245. self announcer announce: (HLParseErrorRaised new
  246. line: line asNumber;
  247. column: column asNumber;
  248. message: messageToInsert;
  249. error: anError;
  250. yourself)
  251. !
  252. handleUnkownVariableError: anError
  253. self announcer announce: (HLUnknownVariableErrorRaised new
  254. error: anError;
  255. yourself)
  256. !
  257. withCompileErrorHandling: aBlock
  258. [
  259. [
  260. aBlock
  261. on: ParseError
  262. do: [:ex | self handleParseError: ex ]
  263. ]
  264. on: UnknownVariableError
  265. do: [ :ex | self handleUnkownVariableError: ex ]
  266. ]
  267. on: CompilerError
  268. do: [ :ex | self handleCompileError: ex ]
  269. ! !
  270. !HLToolModel methodsFor: 'private'!
  271. compilationProtocol
  272. | currentProtocol |
  273. currentProtocol := self selectedProtocol.
  274. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  275. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  276. ^ currentProtocol = self allProtocol
  277. ifTrue: [ self unclassifiedProtocol ]
  278. ifFalse: [ currentProtocol ]
  279. !
  280. withHelperLabelled: aString do: aBlock
  281. "TODO: doesn't belong here"
  282. (window jQuery: '#helper') remove.
  283. [ :html |
  284. html div
  285. id: 'helper';
  286. with: aString ] appendToJQuery: 'body' asJQuery.
  287. [
  288. aBlock value.
  289. (window jQuery: '#helper') remove
  290. ]
  291. valueWithTimeout: 10
  292. ! !
  293. !HLToolModel methodsFor: 'testing'!
  294. isToolModel
  295. ^ true
  296. !
  297. shouldCompileClassDefinition: aString
  298. ^ self selectedClass isNil or: [
  299. aString first asUppercase = aString first ]
  300. ! !
  301. !HLToolModel class methodsFor: 'actions'!
  302. on: anEnvironment
  303. ^ self new
  304. environment: anEnvironment;
  305. yourself
  306. ! !
  307. Widget subclass: #HLTab
  308. instanceVariableNames: 'widget label root'
  309. package: 'Helios-Core'!
  310. !HLTab methodsFor: 'accessing'!
  311. activate
  312. self manager activate: self
  313. !
  314. add
  315. self manager addTab: self
  316. !
  317. displayLabel
  318. ^ self label size > 20
  319. ifTrue: [ (self label first: 20), '...' ]
  320. ifFalse: [ self label ]
  321. !
  322. focus
  323. self widget canHaveFocus ifTrue: [
  324. self widget focus ]
  325. !
  326. label
  327. ^ label ifNil: [ '' ]
  328. !
  329. label: aString
  330. label := aString
  331. !
  332. manager
  333. ^ HLManager current
  334. !
  335. widget
  336. ^ widget
  337. !
  338. widget: aWidget
  339. widget := aWidget
  340. ! !
  341. !HLTab methodsFor: 'actions'!
  342. hide
  343. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  344. !
  345. registerBindings
  346. self widget registerBindings
  347. !
  348. remove
  349. self widget unregister.
  350. root ifNotNil: [ root asJQuery remove ]
  351. !
  352. show
  353. root
  354. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  355. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  356. ! !
  357. !HLTab methodsFor: 'rendering'!
  358. renderOn: html
  359. root := html div
  360. class: 'tab';
  361. yourself.
  362. self renderTab
  363. !
  364. renderTab
  365. root contents: [ :html |
  366. html div
  367. class: 'amber_box';
  368. with: [ self widget renderOn: html ] ]
  369. ! !
  370. !HLTab methodsFor: 'testing'!
  371. isActive
  372. ^ self manager activeTab = self
  373. ! !
  374. !HLTab class methodsFor: 'instance creation'!
  375. on: aWidget labelled: aString
  376. ^ self new
  377. widget: aWidget;
  378. label: aString;
  379. yourself
  380. ! !
  381. Widget subclass: #HLWidget
  382. instanceVariableNames: 'wrapper'
  383. package: 'Helios-Core'!
  384. !HLWidget methodsFor: 'accessing'!
  385. manager
  386. ^ HLManager current
  387. !
  388. wrapper
  389. ^ wrapper
  390. ! !
  391. !HLWidget methodsFor: 'actions'!
  392. alert: aString
  393. window alert: aString
  394. !
  395. confirm: aString ifTrue: aBlock
  396. self manager confirm: aString ifTrue: aBlock
  397. !
  398. execute: aCommand
  399. HLManager current keyBinder
  400. activate;
  401. applyBinding: aCommand asBinding
  402. !
  403. request: aString do: aBlock
  404. self manager request: aString do: aBlock
  405. !
  406. request: aString value: valueString do: aBlock
  407. self manager
  408. request: aString
  409. value: valueString
  410. do: aBlock
  411. !
  412. unregister
  413. "This method is called whenever the receiver is closed (as a tab).
  414. Widgets subscribing to announcements should unregister there"
  415. ! !
  416. !HLWidget methodsFor: 'keybindings'!
  417. registerBindings
  418. self registerBindingsOn: self manager keyBinder bindings
  419. !
  420. registerBindingsOn: aBindingGroup
  421. ! !
  422. !HLWidget methodsFor: 'rendering'!
  423. renderContentOn: html
  424. !
  425. renderOn: html
  426. wrapper := html div.
  427. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  428. ! !
  429. !HLWidget methodsFor: 'testing'!
  430. canHaveFocus
  431. ^ false
  432. ! !
  433. !HLWidget methodsFor: 'updating'!
  434. refresh
  435. self wrapper ifNil: [ ^ self ].
  436. self wrapper asJQuery empty.
  437. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  438. ! !
  439. !HLWidget class methodsFor: 'accessing'!
  440. openAsTab
  441. self canBeOpenAsTab ifFalse: [ ^ self ].
  442. HLManager current addTab: (HLTab on: self new labelled: self tabLabel)
  443. !
  444. tabLabel
  445. ^ 'Tab'
  446. !
  447. tabPriority
  448. ^ 500
  449. ! !
  450. !HLWidget class methodsFor: 'testing'!
  451. canBeOpenAsTab
  452. ^ false
  453. ! !
  454. HLWidget subclass: #HLConfirmation
  455. instanceVariableNames: 'confirmationString actionBlock cancelBlock'
  456. package: 'Helios-Core'!
  457. !HLConfirmation methodsFor: 'accessing'!
  458. actionBlock
  459. ^ actionBlock ifNil: [ [] ]
  460. !
  461. actionBlock: aBlock
  462. actionBlock := aBlock
  463. !
  464. cancelBlock
  465. ^ cancelBlock ifNil: [ [] ]
  466. !
  467. cancelBlock: aBlock
  468. cancelBlock := aBlock
  469. !
  470. confirmationString
  471. ^ confirmationString ifNil: [ 'Confirm' ]
  472. !
  473. confirmationString: aString
  474. confirmationString := aString
  475. !
  476. cssClass
  477. ^ ''
  478. ! !
  479. !HLConfirmation methodsFor: 'actions'!
  480. cancel
  481. self cancelBlock value.
  482. self remove
  483. !
  484. confirm
  485. self actionBlock value.
  486. self remove
  487. !
  488. remove
  489. (window jQuery: '.dialog') removeClass: 'active'.
  490. [
  491. (window jQuery: '#overlay') remove.
  492. (window jQuery: '.dialog') remove
  493. ] valueWithTimeout: 300
  494. ! !
  495. !HLConfirmation methodsFor: 'rendering'!
  496. renderButtonsOn: html
  497. | confirmButton |
  498. html div
  499. class: 'buttons';
  500. with: [
  501. html button
  502. class: 'button';
  503. with: 'Cancel';
  504. onClick: [ self cancel ].
  505. confirmButton := html button
  506. class: 'button default';
  507. with: 'Confirm';
  508. onClick: [ self confirm ] ].
  509. confirmButton asJQuery focus
  510. !
  511. renderContentOn: html
  512. | confirmButton |
  513. html div id: 'overlay'.
  514. html div
  515. class: 'dialog ', self cssClass;
  516. with: [
  517. self
  518. renderMainOn: html;
  519. renderButtonsOn: html ].
  520. (window jQuery: '.dialog') addClass: 'active'.
  521. self setupKeyBindings
  522. !
  523. renderMainOn: html
  524. html span with: self confirmationString
  525. !
  526. setupKeyBindings
  527. (window jQuery: '.dialog') keyup: [ :e |
  528. e keyCode = 27 ifTrue: [ self cancel ] ]
  529. ! !
  530. HLConfirmation subclass: #HLRequest
  531. instanceVariableNames: 'input value'
  532. package: 'Helios-Core'!
  533. !HLRequest methodsFor: 'accessing'!
  534. cssClass
  535. ^ 'large'
  536. !
  537. value
  538. ^ value ifNil: [ '' ]
  539. !
  540. value: aString
  541. value := aString
  542. ! !
  543. !HLRequest methodsFor: 'actions'!
  544. confirm
  545. self actionBlock value: input asJQuery val.
  546. self remove
  547. ! !
  548. !HLRequest methodsFor: 'rendering'!
  549. renderMainOn: html
  550. super renderMainOn: html.
  551. input := html textarea.
  552. input asJQuery val: self value
  553. ! !
  554. HLWidget subclass: #HLDebugger
  555. instanceVariableNames: ''
  556. package: 'Helios-Core'!
  557. HLWidget subclass: #HLFocusableWidget
  558. instanceVariableNames: ''
  559. package: 'Helios-Core'!
  560. !HLFocusableWidget methodsFor: 'accessing'!
  561. focusClass
  562. ^ 'focused'
  563. ! !
  564. !HLFocusableWidget methodsFor: 'events'!
  565. blur
  566. self wrapper asJQuery blur
  567. !
  568. focus
  569. self wrapper asJQuery focus
  570. !
  571. hasFocus
  572. ^ self wrapper notNil and: [ self wrapper asJQuery is: ':focus' ]
  573. ! !
  574. !HLFocusableWidget methodsFor: 'rendering'!
  575. renderContentOn: html
  576. !
  577. renderOn: html
  578. self registerBindings.
  579. wrapper := html div
  580. class: 'hl_widget';
  581. yourself.
  582. wrapper with: [ self renderContentOn: html ].
  583. wrapper
  584. at: 'tabindex' put: '0';
  585. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  586. onFocus: [ self wrapper asJQuery addClass: self focusClass ]
  587. ! !
  588. !HLFocusableWidget methodsFor: 'testing'!
  589. canHaveFocus
  590. ^ true
  591. ! !
  592. HLFocusableWidget subclass: #HLListWidget
  593. instanceVariableNames: 'items selectedItem mapping'
  594. package: 'Helios-Core'!
  595. !HLListWidget methodsFor: 'accessing'!
  596. cssClassForItem: anObject
  597. ^ self selectedItem = anObject
  598. ifTrue: [ 'active' ]
  599. ifFalse: [ 'inactive' ]
  600. !
  601. iconForItem: anObject
  602. ^ ''
  603. !
  604. items
  605. ^ items ifNil: [ items := self defaultItems ]
  606. !
  607. items: aCollection
  608. items := aCollection
  609. !
  610. positionOf: aListItem
  611. <
  612. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  613. >
  614. !
  615. selectedItem
  616. ^ selectedItem
  617. !
  618. selectedItem: anObject
  619. selectedItem := anObject
  620. ! !
  621. !HLListWidget methodsFor: 'actions'!
  622. activateFirstListItem
  623. self activateListItem: (window jQuery: ((wrapper asJQuery find: 'li.inactive') get: 0))
  624. !
  625. activateItem: anObject
  626. self activateListItem: (mapping
  627. at: anObject
  628. ifAbsent: [ ^ self ]) asJQuery
  629. !
  630. activateListItem: aListItem
  631. | item |
  632. (aListItem get: 0) ifNil: [ ^self ].
  633. aListItem parent children removeClass: 'active'.
  634. aListItem addClass: 'active'.
  635. self ensureVisible: aListItem.
  636. "Activate the corresponding item"
  637. item := (self items at: (aListItem attr: 'list-data') asNumber).
  638. self selectedItem == item ifFalse: [
  639. self selectItem: item ]
  640. !
  641. activateNextListItem
  642. self activateListItem: (window jQuery: '.focused .nav-pills .active') next.
  643. "select the first item if none is selected"
  644. (window jQuery: '.focused .nav-pills .active') get ifEmpty: [
  645. self activateFirstListItem ]
  646. !
  647. activatePreviousListItem
  648. self activateListItem: (window jQuery: '.focused .nav-pills .active') prev
  649. !
  650. ensureVisible: aListItem
  651. "Move the scrollbar to show the active element"
  652. | perent position |
  653. position := self positionOf: aListItem.
  654. parent := aListItem parent.
  655. aListItem position top < 0 ifTrue: [
  656. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  657. aListItem position top + aListItem height > parent height ifTrue: [
  658. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
  659. !
  660. focus
  661. super focus.
  662. self items isEmpty ifFalse: [
  663. self selectedItem ifNil: [ self activateFirstListItem ] ]
  664. !
  665. refresh
  666. super refresh.
  667. self ensureVisible: (mapping
  668. at: self selectedItem
  669. ifAbsent: [ ^ self ]) asJQuery
  670. !
  671. selectItem: anObject
  672. self selectedItem: anObject
  673. ! !
  674. !HLListWidget methodsFor: 'defaults'!
  675. defaultItems
  676. ^ #()
  677. ! !
  678. !HLListWidget methodsFor: 'events'!
  679. setupKeyBindings
  680. "TODO: refactor this!!"
  681. | active interval delay repeatInterval |
  682. active := false.
  683. repeatInterval := 70.
  684. self wrapper asJQuery unbind: 'keydown'.
  685. self wrapper asJQuery keydown: [ :e |
  686. (e which = 38 and: [ active = false ]) ifTrue: [
  687. active := true.
  688. self activatePreviousListItem.
  689. delay := [
  690. interval := [
  691. (self wrapper asJQuery hasClass: self focusClass)
  692. ifTrue: [
  693. self activatePreviousListItem ]
  694. ifFalse: [
  695. active := false.
  696. interval ifNotNil: [ interval clearInterval ].
  697. delay ifNotNil: [ delay clearTimeout] ] ]
  698. valueWithInterval: repeatInterval ]
  699. valueWithTimeout: 300 ].
  700. (e which = 40 and: [ active = false ]) ifTrue: [
  701. active := true.
  702. self activateNextListItem.
  703. delay := [
  704. interval := [
  705. (self wrapper asJQuery hasClass: self focusClass)
  706. ifTrue: [
  707. self activateNextListItem ]
  708. ifFalse: [
  709. active := false.
  710. interval ifNotNil: [ interval clearInterval ].
  711. delay ifNotNil: [ delay clearTimeout] ] ]
  712. valueWithInterval: repeatInterval ]
  713. valueWithTimeout: 300 ] ].
  714. self wrapper asJQuery keyup: [ :e |
  715. active ifTrue: [
  716. active := false.
  717. interval ifNotNil: [ interval clearInterval ].
  718. delay ifNotNil: [ delay clearTimeout] ] ]
  719. ! !
  720. !HLListWidget methodsFor: 'initialization'!
  721. initialize
  722. super initialize.
  723. mapping := Dictionary new.
  724. ! !
  725. !HLListWidget methodsFor: 'private'!
  726. registerMappingFrom: anObject to: aTag
  727. mapping at: anObject put: aTag
  728. ! !
  729. !HLListWidget methodsFor: 'rendering'!
  730. renderButtonsOn: html
  731. !
  732. renderContentOn: html
  733. html ul
  734. class: 'nav nav-pills nav-stacked';
  735. with: [ self renderListOn: html ].
  736. html div class: 'pane_actions form-actions'; with: [
  737. self renderButtonsOn: html ].
  738. self setupKeyBindings
  739. !
  740. renderItem: anObject on: html
  741. | li |
  742. li := html li.
  743. self registerMappingFrom: anObject to: li.
  744. li
  745. class: (self cssClassForItem: anObject);
  746. at: 'list-data' put: (self items indexOf: anObject) asString;
  747. with: [
  748. html a
  749. with: [
  750. (html tag: 'i') class: (self iconForItem: anObject).
  751. self renderItemLabel: anObject on: html ];
  752. onClick: [
  753. self activateListItem: li asJQuery ] ]
  754. !
  755. renderItemLabel: anObject on: html
  756. html with: anObject asString
  757. !
  758. renderListOn: html
  759. mapping := Dictionary new.
  760. self items do: [ :each |
  761. self renderItem: each on: html ]
  762. ! !
  763. HLListWidget subclass: #HLNavigationListWidget
  764. instanceVariableNames: 'previous next'
  765. package: 'Helios-Core'!
  766. !HLNavigationListWidget methodsFor: 'accessing'!
  767. next
  768. ^ next
  769. !
  770. next: aWidget
  771. next := aWidget.
  772. aWidget previous = self ifFalse: [ aWidget previous: self ]
  773. !
  774. previous
  775. ^ previous
  776. !
  777. previous: aWidget
  778. previous := aWidget.
  779. aWidget next = self ifFalse: [ aWidget next: self ]
  780. ! !
  781. !HLNavigationListWidget methodsFor: 'actions'!
  782. nextFocus
  783. self next ifNotNil: [ self next focus ]
  784. !
  785. previousFocus
  786. self previous ifNotNil: [ self previous focus ]
  787. ! !
  788. !HLNavigationListWidget methodsFor: 'events'!
  789. setupKeyBindings
  790. super setupKeyBindings.
  791. self wrapper asJQuery keydown: [ :e |
  792. e which = 39 ifTrue: [
  793. self nextFocus ].
  794. e which = 37 ifTrue: [
  795. self previousFocus ] ]
  796. ! !
  797. HLNavigationListWidget subclass: #HLToolListWidget
  798. instanceVariableNames: 'model'
  799. package: 'Helios-Core'!
  800. !HLToolListWidget methodsFor: 'accessing'!
  801. commandCategory
  802. ^ self label
  803. !
  804. label
  805. ^ 'List'
  806. !
  807. menuCommands
  808. "Answer a collection of commands to be put in the cog menu"
  809. ^ ((HLToolCommand concreteClasses
  810. select: [ :each | each isValidFor: self model ])
  811. collect: [ :each | each for: self model ])
  812. select: [ :each |
  813. each category = self commandCategory and: [
  814. each isAction and: [ each isActive ] ] ]
  815. !
  816. model
  817. ^ model
  818. !
  819. model: aBrowserModel
  820. model := aBrowserModel.
  821. self
  822. observeSystem;
  823. observeModel
  824. !
  825. selectedItem: anItem
  826. "Selection changed, update the cog menu"
  827. super selectedItem: anItem.
  828. self updateMenu
  829. ! !
  830. !HLToolListWidget methodsFor: 'actions'!
  831. activateListItem: anItem
  832. self model withChangesDo: [ super activateListItem: anItem ]
  833. !
  834. activateNextListItem
  835. self model withChangesDo: [ super activateNextListItem ]
  836. !
  837. activatePreviousListItem
  838. self model withChangesDo: [ super activatePreviousListItem ]
  839. !
  840. observeModel
  841. !
  842. observeSystem
  843. !
  844. unregister
  845. super unregister.
  846. self model announcer unsubscribe: self.
  847. self model systemAnnouncer unsubscribe: self
  848. ! !
  849. !HLToolListWidget methodsFor: 'rendering'!
  850. renderContentOn: html
  851. self renderHeadOn: html.
  852. super renderContentOn: html
  853. !
  854. renderHeadOn: html
  855. html div
  856. class: 'list-label';
  857. with: [
  858. html with: self label.
  859. self renderMenuOn: html ]
  860. !
  861. renderMenuOn: html
  862. | commands |
  863. commands := self menuCommands.
  864. commands isEmpty ifTrue: [ ^ self ].
  865. html div
  866. class: 'btn-group cog';
  867. with: [
  868. html a
  869. class: 'btn dropdown-toggle';
  870. at: 'data-toggle' put: 'dropdown';
  871. with: [ (html tag: 'i') class: 'icon-cog' ].
  872. html ul
  873. class: 'dropdown-menu pull-right';
  874. with: [
  875. self menuCommands do: [ :each |
  876. html li with: [ html a
  877. with: each menuLabel;
  878. onClick: [ self execute: each ] ] ] ] ]
  879. ! !
  880. !HLToolListWidget methodsFor: 'updating'!
  881. updateMenu
  882. (self wrapper asJQuery find: '.cog') remove.
  883. [ :html | self renderMenuOn: html ]
  884. appendToJQuery: (self wrapper asJQuery find: '.list-label')
  885. ! !
  886. !HLToolListWidget class methodsFor: 'instance creation'!
  887. on: aModel
  888. ^ self new
  889. model: aModel;
  890. yourself
  891. ! !
  892. HLWidget subclass: #HLManager
  893. instanceVariableNames: 'tabs activeTab keyBinder environment history'
  894. package: 'Helios-Core'!
  895. !HLManager methodsFor: 'accessing'!
  896. activeTab
  897. ^ activeTab
  898. !
  899. environment
  900. "The default environment used by all Helios objects"
  901. ^ environment ifNil: [ environment := self defaultEnvironment ]
  902. !
  903. environment: anEnvironment
  904. environment := anEnvironment
  905. !
  906. history
  907. ^ history ifNil: [ history := OrderedCollection new ]
  908. !
  909. history: aCollection
  910. history := aCollection
  911. !
  912. keyBinder
  913. ^ keyBinder ifNil: [ keyBinder := HLKeyBinder new ]
  914. !
  915. tabs
  916. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  917. ! !
  918. !HLManager methodsFor: 'actions'!
  919. activate: aTab
  920. self keyBinder flushBindings.
  921. aTab registerBindings.
  922. activeTab := aTab.
  923. self
  924. refresh;
  925. addToHistory: aTab;
  926. show: aTab
  927. !
  928. addTab: aTab
  929. self tabs add: aTab.
  930. self activate: aTab
  931. !
  932. addToHistory: aTab
  933. self removeFromHistory: aTab.
  934. self history add: aTab
  935. !
  936. confirm: aString ifFalse: aBlock
  937. (HLConfirmation new
  938. confirmationString: aString;
  939. cancelBlock: aBlock;
  940. yourself)
  941. appendToJQuery: 'body' asJQuery
  942. !
  943. confirm: aString ifTrue: aBlock
  944. (HLConfirmation new
  945. confirmationString: aString;
  946. actionBlock: aBlock;
  947. yourself)
  948. appendToJQuery: 'body' asJQuery
  949. !
  950. removeActiveTab
  951. self removeTab: self activeTab
  952. !
  953. removeFromHistory: aTab
  954. self history: (self history reject: [ :each | each == aTab ])
  955. !
  956. removeTab: aTab
  957. (self tabs includes: aTab) ifFalse: [ ^ self ].
  958. self removeFromHistory: aTab.
  959. self tabs remove: aTab.
  960. self keyBinder flushBindings.
  961. aTab remove.
  962. self refresh.
  963. self history ifNotEmpty: [
  964. self history last activate ]
  965. !
  966. request: aString do: aBlock
  967. self
  968. request: aString
  969. value: ''
  970. do: aBlock
  971. !
  972. request: aString value: valueString do: aBlock
  973. (HLRequest new
  974. confirmationString: aString;
  975. actionBlock: aBlock;
  976. value: valueString;
  977. yourself)
  978. appendToJQuery: 'body' asJQuery
  979. ! !
  980. !HLManager methodsFor: 'defaults'!
  981. defaultEnvironment
  982. "If helios is loaded from within a frame, answer the parent window environment"
  983. window parent ifNil: [ ^ Environment new ].
  984. ^ ((window parent at: 'smalltalk')
  985. at: 'Environment') new
  986. ! !
  987. !HLManager methodsFor: 'initialization'!
  988. initialize
  989. super initialize.
  990. self keyBinder setupEvents
  991. ! !
  992. !HLManager methodsFor: 'rendering'!
  993. refresh
  994. (window jQuery: '.navbar') remove.
  995. self appendToJQuery: 'body' asJQuery
  996. !
  997. renderAddOn: html
  998. html li
  999. class: 'dropdown';
  1000. with: [
  1001. html a
  1002. class: 'dropdown-toggle';
  1003. at: 'data-toggle' put: 'dropdown';
  1004. with: [
  1005. html with: 'Open...'.
  1006. (html tag: 'b') class: 'caret' ].
  1007. html ul
  1008. class: 'dropdown-menu';
  1009. with: [
  1010. ((HLWidget withAllSubclasses
  1011. select: [ :each | each canBeOpenAsTab ])
  1012. sorted: [ :a :b | a tabPriority < b tabPriority ])
  1013. do: [ :each |
  1014. html li with: [
  1015. html a
  1016. with: each tabLabel;
  1017. onClick: [ each openAsTab ] ] ] ] ]
  1018. !
  1019. renderContentOn: html
  1020. html div
  1021. class: 'navbar navbar-fixed-top';
  1022. with: [ html div
  1023. class: 'navbar-inner';
  1024. with: [ self renderTabsOn: html ] ]
  1025. !
  1026. renderTabsOn: html
  1027. html ul
  1028. class: 'nav';
  1029. with: [
  1030. self tabs do: [ :each |
  1031. html li
  1032. class: (each isActive ifTrue: [ 'active' ] ifFalse: [ 'inactive' ]);
  1033. with: [
  1034. html a
  1035. with: [
  1036. ((html tag: 'i') class: 'icon-remove')
  1037. onClick: [ self removeTab: each ].
  1038. html with: each displayLabel ];
  1039. onClick: [ each activate ] ] ].
  1040. self renderAddOn: html ]
  1041. !
  1042. show: aTab
  1043. self tabs do: [ :each | each hide ].
  1044. aTab show; focus
  1045. ! !
  1046. HLManager class instanceVariableNames: 'current'!
  1047. !HLManager class methodsFor: 'accessing'!
  1048. current
  1049. ^ current ifNil: [ current := self basicNew initialize ]
  1050. ! !
  1051. !HLManager class methodsFor: 'initialization'!
  1052. initialize
  1053. self current appendToJQuery: 'body' asJQuery
  1054. ! !
  1055. !HLManager class methodsFor: 'instance creation'!
  1056. new
  1057. "Use current instead"
  1058. self shouldNotImplement
  1059. ! !
  1060. HLWidget subclass: #HLSUnit
  1061. instanceVariableNames: ''
  1062. package: 'Helios-Core'!
  1063. !HLSUnit class methodsFor: 'accessing'!
  1064. tabLabel
  1065. ^ 'SUnit'
  1066. !
  1067. tabPriority
  1068. ^ 1000
  1069. ! !
  1070. !HLSUnit class methodsFor: 'testing'!
  1071. canBeOpenAsTab
  1072. ^ true
  1073. ! !
  1074. HLWidget subclass: #HLTranscript
  1075. instanceVariableNames: ''
  1076. package: 'Helios-Core'!
  1077. !HLTranscript class methodsFor: 'accessing'!
  1078. tabLabel
  1079. ^ 'Transcript'
  1080. !
  1081. tabPriority
  1082. ^ 600
  1083. ! !
  1084. !HLTranscript class methodsFor: 'testing'!
  1085. canBeOpenAsTab
  1086. ^ true
  1087. ! !