Helios-Core.st 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. Smalltalk current createPackage: 'Helios-Core'!
  2. Object subclass: #HLTab
  3. instanceVariableNames: 'widget label'
  4. package: 'Helios-Core'!
  5. !HLTab methodsFor: 'accessing'!
  6. activate
  7. self manager activate: self
  8. !
  9. add
  10. self manager addTab: self
  11. !
  12. label
  13. ^ label ifNil: [ '' ]
  14. !
  15. label: aString
  16. label := aString
  17. !
  18. manager
  19. ^ HLManager current
  20. !
  21. widget
  22. ^ widget
  23. !
  24. widget: aWidget
  25. widget := aWidget
  26. ! !
  27. !HLTab methodsFor: 'testing'!
  28. isActive
  29. ^ self manager activeTab = self
  30. ! !
  31. !HLTab class methodsFor: 'instance creation'!
  32. on: aWidget labelled: aString
  33. ^ self new
  34. widget: aWidget;
  35. label: aString;
  36. yourself
  37. ! !
  38. Widget subclass: #HLWidget
  39. instanceVariableNames: 'wrapper'
  40. package: 'Helios-Core'!
  41. !HLWidget methodsFor: 'accessing'!
  42. manager
  43. ^ HLManager current
  44. !
  45. wrapper
  46. ^ wrapper
  47. ! !
  48. !HLWidget methodsFor: 'actions'!
  49. alert: aString
  50. window alert: aString
  51. !
  52. confirm: aString
  53. ^ window confirm: aString
  54. ! !
  55. !HLWidget methodsFor: 'keybindings'!
  56. registerBindings
  57. self registerBindingsOn: self manager keyBinder bindings
  58. !
  59. registerBindingsOn: aBindingGroup
  60. ! !
  61. !HLWidget methodsFor: 'rendering'!
  62. renderContentOn: html
  63. !
  64. renderOn: html
  65. self registerBindings.
  66. wrapper := html div.
  67. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  68. ! !
  69. !HLWidget methodsFor: 'updating'!
  70. refresh
  71. self wrapper ifNil: [ ^ self ].
  72. self wrapper asJQuery empty.
  73. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  74. ! !
  75. !HLWidget class methodsFor: 'accessing'!
  76. openAsTab
  77. self canBeOpenAsTab ifFalse: [ ^ self ].
  78. HLManager current addTab: (HLTab on: self new labelled: self tabLabel)
  79. !
  80. tabLabel
  81. ^ 'Tab'
  82. !
  83. tabPriority
  84. ^ 500
  85. ! !
  86. !HLWidget class methodsFor: 'testing'!
  87. canBeOpenAsTab
  88. ^ false
  89. ! !
  90. HLWidget subclass: #HLDebugger
  91. instanceVariableNames: ''
  92. package: 'Helios-Core'!
  93. HLWidget subclass: #HLFocusableWidget
  94. instanceVariableNames: 'hiddenInput'
  95. package: 'Helios-Core'!
  96. !HLFocusableWidget methodsFor: 'accessing'!
  97. focusClass
  98. ^ 'focused'
  99. ! !
  100. !HLFocusableWidget methodsFor: 'events'!
  101. blur
  102. hiddenInput asJQuery blur
  103. !
  104. focus
  105. hiddenInput asJQuery focus
  106. !
  107. hasFocus
  108. ^ self wrapper notNil and: [ self wrapper asJQuery hasClass: self focusClass ]
  109. ! !
  110. !HLFocusableWidget methodsFor: 'rendering'!
  111. renderContentOn: html
  112. !
  113. renderHiddenInputOn: html
  114. hiddenInput := html input
  115. style: 'position: absolute; left: -100000px;';
  116. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  117. onFocus: [ self wrapper asJQuery addClass: self focusClass ]
  118. !
  119. renderOn: html
  120. self registerBindings.
  121. self renderHiddenInputOn: html.
  122. wrapper := html div
  123. class: 'hl_widget';
  124. onClick: [ hiddenInput asJQuery focus ];
  125. with: [
  126. self renderContentOn: html ]
  127. ! !
  128. HLFocusableWidget subclass: #HLListWidget
  129. instanceVariableNames: 'items selectedItem'
  130. package: 'Helios-Core'!
  131. !HLListWidget methodsFor: 'accessing'!
  132. cssClassForItem: anObject
  133. ^ self selectedItem = anObject
  134. ifTrue: [ 'active' ]
  135. ifFalse: [ 'inactive' ]
  136. !
  137. iconForItem: anObject
  138. ^ ''
  139. !
  140. items
  141. ^ items ifNil: [ items := self defaultItems ]
  142. !
  143. items: aCollection
  144. items := aCollection
  145. !
  146. positionOf: aListItem
  147. <
  148. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  149. >
  150. !
  151. selectedItem
  152. ^ selectedItem
  153. !
  154. selectedItem: anObject
  155. selectedItem := anObject
  156. ! !
  157. !HLListWidget methodsFor: 'actions'!
  158. activateFirstListItem
  159. self activateListItem: (window jQuery: ((wrapper asJQuery find: 'li') get: 0))
  160. !
  161. activateListItem: aListItem
  162. | parent position |
  163. (aListItem get: 0) ifNil: [ ^self ].
  164. position := self positionOf: aListItem.
  165. parent := aListItem parent.
  166. parent children removeClass: 'active'.
  167. aListItem addClass: 'active'.
  168. "Move the scrollbar to show the active element"
  169. aListItem position top < 0 ifTrue: [
  170. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  171. aListItem position top + aListItem height > parent height ifTrue: [
  172. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ].
  173. "Activate the corresponding item"
  174. self selectItem: (self items at: (aListItem attr: 'list-data') asNumber)
  175. !
  176. focus
  177. super focus.
  178. self items isEmpty ifFalse: [
  179. self selectedItem ifNil: [ self activateFirstListItem ] ]
  180. !
  181. selectItem: anObject
  182. self selectedItem: anObject
  183. ! !
  184. !HLListWidget methodsFor: 'defaults'!
  185. defaultItems
  186. ^ #()
  187. ! !
  188. !HLListWidget methodsFor: 'events'!
  189. setupKeyBindings
  190. | next |
  191. hiddenInput asJQuery unbind: 'keydown'.
  192. hiddenInput asJQuery keydown: [ :e | | selected |
  193. selected := window jQuery: '.focused .nav-pills .active'.
  194. e which = 38 ifTrue: [
  195. self activateListItem: selected prev ].
  196. e which = 40 ifTrue: [
  197. next := selected next.
  198. (next get: 0) ifNil: [ next := window jQuery: '.focused .nav-pills li:first-child' ].
  199. self activateListItem: next ] ]
  200. ! !
  201. !HLListWidget methodsFor: 'rendering'!
  202. renderButtonsOn: html
  203. !
  204. renderContentOn: html
  205. html ul
  206. class: 'nav nav-pills nav-stacked';
  207. with: [ self renderListOn: html ].
  208. html div class: 'pane_actions form-actions'; with: [
  209. self renderButtonsOn: html ].
  210. self setupKeyBindings
  211. !
  212. renderItem: anObject on: html
  213. | li |
  214. li := html li.
  215. li
  216. class: (self cssClassForItem: anObject);
  217. at: 'list-data' put: (self items indexOf: anObject) asString;
  218. with: [
  219. html a
  220. with: [
  221. (html tag: 'i') class: (self iconForItem: anObject).
  222. self renderItemLabel: anObject on: html ];
  223. onClick: [
  224. self activateListItem: li asJQuery ] ]
  225. !
  226. renderItemLabel: anObject on: html
  227. html with: anObject asString
  228. !
  229. renderListOn: html
  230. self items do: [ :each |
  231. self renderItem: each on: html ]
  232. ! !
  233. HLListWidget subclass: #HLNavigationListWidget
  234. instanceVariableNames: 'previous next'
  235. package: 'Helios-Core'!
  236. !HLNavigationListWidget methodsFor: 'accessing'!
  237. next
  238. ^ next
  239. !
  240. next: aWidget
  241. next := aWidget.
  242. aWidget previous = self ifFalse: [ aWidget previous: self ]
  243. !
  244. previous
  245. ^ previous
  246. !
  247. previous: aWidget
  248. previous := aWidget.
  249. aWidget next = self ifFalse: [ aWidget next: self ]
  250. ! !
  251. !HLNavigationListWidget methodsFor: 'actions'!
  252. nextFocus
  253. self next ifNotNil: [ self next focus ]
  254. !
  255. previousFocus
  256. self previous ifNotNil: [ self previous focus ]
  257. ! !
  258. !HLNavigationListWidget methodsFor: 'events'!
  259. setupKeyBindings
  260. super setupKeyBindings.
  261. hiddenInput asJQuery keydown: [ :e |
  262. e which = 39 ifTrue: [
  263. self nextFocus ].
  264. e which = 37 ifTrue: [
  265. self previousFocus ] ]
  266. ! !
  267. HLWidget subclass: #HLManager
  268. instanceVariableNames: 'tabs activeTab keyBinder environment history'
  269. package: 'Helios-Core'!
  270. !HLManager methodsFor: 'accessing'!
  271. activeTab
  272. ^ activeTab
  273. !
  274. environment
  275. "The default environment used by all Helios objects"
  276. ^ environment ifNil: [ environment := self defaultEnvironment ]
  277. !
  278. environment: anEnvironment
  279. environment := anEnvironment
  280. !
  281. history
  282. ^ history ifNil: [ history := OrderedCollection new ]
  283. !
  284. history: aCollection
  285. history := aCollection
  286. !
  287. keyBinder
  288. ^ keyBinder ifNil: [ keyBinder := HLKeyBinder new ]
  289. !
  290. tabs
  291. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  292. ! !
  293. !HLManager methodsFor: 'actions'!
  294. activate: aTab
  295. self keyBinder flushBindings.
  296. activeTab := aTab.
  297. self
  298. refresh;
  299. addToHistory: aTab;
  300. show: aTab
  301. !
  302. addTab: aTab
  303. self tabs add: aTab.
  304. self activate: aTab
  305. !
  306. addToHistory: aTab
  307. self removeFromHistory: aTab.
  308. self history add: aTab
  309. !
  310. removeActiveTab
  311. self removeTab: self activeTab
  312. !
  313. removeFromHistory: aTab
  314. self history: (self history reject: [ :each | each == aTab ])
  315. !
  316. removeTab: aTab
  317. (self tabs includes: aTab) ifFalse: [ ^ self ].
  318. self removeFromHistory: aTab.
  319. self tabs remove: aTab.
  320. self refresh.
  321. self history ifNotEmpty: [
  322. self history last activate ]
  323. ! !
  324. !HLManager methodsFor: 'defaults'!
  325. defaultEnvironment
  326. ^ HLLocalEnvironment new
  327. ! !
  328. !HLManager methodsFor: 'initialization'!
  329. initialize
  330. super initialize.
  331. self keyBinder setupEvents
  332. ! !
  333. !HLManager methodsFor: 'rendering'!
  334. refresh
  335. (window jQuery: '.navbar') remove.
  336. (window jQuery: '#container') remove.
  337. self appendToJQuery: 'body' asJQuery
  338. !
  339. renderAddOn: html
  340. html li
  341. class: 'dropdown';
  342. with: [
  343. html a
  344. class: 'dropdown-toggle';
  345. at: 'data-toggle' put: 'dropdown';
  346. with: [
  347. html with: 'Open...'.
  348. (html tag: 'b') class: 'caret' ].
  349. html ul
  350. class: 'dropdown-menu';
  351. with: [
  352. ((HLWidget withAllSubclasses
  353. select: [ :each | each canBeOpenAsTab ])
  354. sorted: [ :a :b | a tabPriority < b tabPriority ])
  355. do: [ :each |
  356. html li with: [
  357. html a
  358. with: each tabLabel;
  359. onClick: [ each openAsTab ] ] ] ] ]
  360. !
  361. renderContentOn: html
  362. html div
  363. class: 'navbar navbar-fixed-top';
  364. with: [ html div
  365. class: 'navbar-inner';
  366. with: [ self renderTabsOn: html ] ].
  367. html div id: 'container'
  368. !
  369. renderTabsOn: html
  370. html ul
  371. class: 'nav';
  372. with: [
  373. self tabs do: [ :each |
  374. html li
  375. class: (each isActive ifTrue: [ 'active' ] ifFalse: [ 'inactive' ]);
  376. with: [
  377. html a
  378. with: [
  379. ((html tag: 'i') class: 'icon-remove-circle')
  380. onClick: [ self removeTab: each ].
  381. html with: each label ];
  382. onClick: [ each activate ] ] ].
  383. self renderAddOn: html ]
  384. !
  385. show: aTab
  386. (window jQuery: '#container') empty.
  387. aTab widget appendToJQuery: '#container' asJQuery
  388. ! !
  389. HLManager class instanceVariableNames: 'current'!
  390. !HLManager class methodsFor: 'accessing'!
  391. current
  392. ^ current ifNil: [ current := self basicNew initialize ]
  393. ! !
  394. !HLManager class methodsFor: 'initialization'!
  395. initialize
  396. self current appendToJQuery: 'body' asJQuery
  397. ! !
  398. !HLManager class methodsFor: 'instance creation'!
  399. new
  400. "Use current instead"
  401. self shouldNotImplement
  402. ! !
  403. HLWidget subclass: #HLSUnit
  404. instanceVariableNames: ''
  405. package: 'Helios-Core'!
  406. !HLSUnit class methodsFor: 'accessing'!
  407. tabLabel
  408. ^ 'SUnit'
  409. !
  410. tabPriority
  411. ^ 1000
  412. ! !
  413. !HLSUnit class methodsFor: 'testing'!
  414. canBeOpenAsTab
  415. ^ true
  416. ! !
  417. HLWidget subclass: #HLTranscript
  418. instanceVariableNames: ''
  419. package: 'Helios-Core'!
  420. !HLTranscript class methodsFor: 'accessing'!
  421. tabLabel
  422. ^ 'Transcript'
  423. !
  424. tabPriority
  425. ^ 600
  426. ! !
  427. !HLTranscript class methodsFor: 'testing'!
  428. canBeOpenAsTab
  429. ^ true
  430. ! !