1
0

Helios-Core.st 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541
  1. Smalltalk createPackage: 'Helios-Core'!
  2. Object subclass: #HLModel
  3. instanceVariableNames: 'announcer environment'
  4. package: 'Helios-Core'!
  5. !HLModel commentStamp!
  6. I am the abstract superclass of all models of Helios.
  7. I am the "Model" part of the MVC pattern implementation in Helios.
  8. I provide access to an `Environment` object and both a local (model-specific) and global (system-specific) announcer.
  9. The `#withChangesDo:` method is handy for performing model changes ensuring that all widgets are aware of the change and can prevent it from happening.
  10. Modifications of the system should be done via commands (see `HLCommand` and subclasses).!
  11. !HLModel methodsFor: 'accessing'!
  12. announcer
  13. ^ announcer ifNil: [ announcer := Announcer new ]
  14. !
  15. environment
  16. ^ environment ifNil: [ self manager environment ]
  17. !
  18. environment: anEnvironment
  19. environment := anEnvironment
  20. !
  21. manager
  22. ^ HLManager current
  23. !
  24. systemAnnouncer
  25. ^ self environment systemAnnouncer
  26. ! !
  27. !HLModel methodsFor: 'error handling'!
  28. withChangesDo: aBlock
  29. [
  30. self announcer announce: (HLAboutToChange new
  31. actionBlock: aBlock;
  32. yourself).
  33. aBlock value.
  34. ]
  35. on: HLChangeForbidden
  36. do: [ :ex | ]
  37. ! !
  38. !HLModel methodsFor: 'testing'!
  39. isBrowserModel
  40. ^ false
  41. !
  42. isReferencesModel
  43. ^ false
  44. !
  45. isToolModel
  46. ^ false
  47. ! !
  48. HLModel subclass: #HLFinder
  49. instanceVariableNames: ''
  50. package: 'Helios-Core'!
  51. !HLFinder commentStamp!
  52. I am the `Finder` service handler of Helios.
  53. Finding a class will open a new class browser, while finding a method will open a references browser.!
  54. !HLFinder methodsFor: 'finding'!
  55. findClass: aClass
  56. HLBrowser openAsTab openClassNamed: aClass name
  57. !
  58. findMethod: aCompiledMethod
  59. HLBrowser openAsTab openMethod: aCompiledMethod
  60. !
  61. findString: aString
  62. | foundClass |
  63. foundClass := self environment classes
  64. detect: [ :each | each name = aString ]
  65. ifNone: [ nil ].
  66. foundClass
  67. ifNil: [ HLReferences openAsTab search: aString ]
  68. ifNotNil: [ self findClass: foundClass ]
  69. ! !
  70. HLModel subclass: #HLToolModel
  71. instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
  72. package: 'Helios-Core'!
  73. !HLToolModel commentStamp!
  74. I am a model specific to package and class manipulation. All browsers should either use me or a subclass as their model.
  75. I provide methods for package, class, protocol and method manipulation and access, forwarding to my environment.
  76. I also handle compilation of classes and methods as well as compilation and parsing errors.!
  77. !HLToolModel methodsFor: 'accessing'!
  78. allSelectors
  79. ^ self environment allSelectors
  80. !
  81. availableClassNames
  82. ^ self environment availableClassNames
  83. !
  84. availablePackageNames
  85. ^ self environment availablePackageNames
  86. !
  87. availablePackages
  88. ^ self environment availablePackageNames
  89. !
  90. availableProtocols
  91. ^ self environment availableProtocolsFor: self selectedClass
  92. !
  93. forceSelectedClass: aClass
  94. self withChangesDo: [
  95. self
  96. selectedClass: nil;
  97. selectedClass: aClass ]
  98. !
  99. forceSelectedMethod: aMethod
  100. self withChangesDo: [
  101. self
  102. selectedMethod: nil;
  103. selectedMethod: aMethod ]
  104. !
  105. forceSelectedPackage: aPackage
  106. self withChangesDo: [
  107. self
  108. selectedPackage: nil;
  109. selectedPackage: aPackage ]
  110. !
  111. forceSelectedProtocol: aProtocol
  112. self withChangesDo: [
  113. self
  114. selectedProtocol: nil;
  115. selectedProtocol: aProtocol ]
  116. !
  117. packageToCommit
  118. "Answer the package to commit depending on the context:
  119. - if a Method is selected, answer its package
  120. - else answer the `selectedPackage`"
  121. ^ self selectedMethod
  122. ifNil: [ self selectedPackage ]
  123. ifNotNil: [ :method | method package ]
  124. !
  125. packages
  126. ^ self environment packages
  127. !
  128. selectedClass
  129. ^ selectedClass
  130. !
  131. selectedClass: aClass
  132. (self selectedClass = aClass and: [ aClass isNil ])
  133. ifTrue: [ ^ self ].
  134. self withChangesDo: [
  135. aClass
  136. ifNil: [ selectedClass := nil ]
  137. ifNotNil: [
  138. self selectedPackage: aClass theNonMetaClass package.
  139. self showInstance
  140. ifTrue: [ selectedClass := aClass theNonMetaClass ]
  141. ifFalse: [ selectedClass := aClass theMetaClass ] ].
  142. selectedProtocol := nil.
  143. self selectedProtocol: self allProtocol.
  144. self announcer announce: (HLClassSelected on: self selectedClass) ]
  145. !
  146. selectedMethod
  147. ^ self selectedClass ifNotNil: [
  148. self selectedClass methodDictionary
  149. at: selectedSelector
  150. ifAbsent: [ nil ] ]
  151. !
  152. selectedMethod: aCompiledMethod
  153. selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
  154. self withChangesDo: [
  155. aCompiledMethod
  156. ifNil: [ selectedSelector := nil ]
  157. ifNotNil: [
  158. selectedSelector := aCompiledMethod selector.
  159. (selectedClass notNil and: [ selectedClass methodDictionary includesKey: selectedSelector ]) ifFalse: [
  160. selectedClass := aCompiledMethod methodClass.
  161. selectedPackage := selectedClass theNonMetaClass package ] ].
  162. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  163. !
  164. selectedPackage
  165. ^ selectedPackage
  166. !
  167. selectedPackage: aPackage
  168. selectedPackage = aPackage ifTrue: [ ^ self ].
  169. self withChangesDo: [
  170. selectedPackage := aPackage.
  171. self selectedClass: nil.
  172. self announcer announce: (HLPackageSelected on: aPackage) ]
  173. !
  174. selectedProtocol
  175. ^ selectedProtocol
  176. !
  177. selectedProtocol: aString
  178. selectedProtocol = aString ifTrue: [ ^ self ].
  179. self withChangesDo: [
  180. selectedProtocol := aString.
  181. self selectedMethod: nil.
  182. self announcer announce: (HLProtocolSelected on: aString) ]
  183. ! !
  184. !HLToolModel methodsFor: 'actions'!
  185. addInstVarNamed: aString
  186. self environment addInstVarNamed: aString to: self selectedClass.
  187. self announcer announce: (HLInstVarAdded new
  188. theClass: self selectedClass;
  189. variableName: aString;
  190. yourself)
  191. !
  192. save: aString
  193. self announcer announce: HLSourceCodeSaved new.
  194. (self shouldCompileDefinition: aString)
  195. ifTrue: [ self compileClassDefinition: aString ]
  196. ifFalse: [ self compileMethod: aString ]
  197. !
  198. saveSourceCode
  199. self announcer announce: HLSaveSourceCode new
  200. ! !
  201. !HLToolModel methodsFor: 'commands actions'!
  202. commitPackageOnSuccess: aBlock onError: anotherBlock
  203. self environment
  204. commitPackage: self packageToCommit
  205. onSuccess: aBlock
  206. onError: anotherBlock
  207. !
  208. copyClassTo: aClassName
  209. self withChangesDo: [
  210. self environment
  211. copyClass: self selectedClass theNonMetaClass
  212. to: aClassName.
  213. self selectedClass: (self environment classNamed: aClassName) ]
  214. !
  215. moveClassToPackage: aPackageName
  216. self withChangesDo: [
  217. self environment
  218. moveClass: self selectedClass theNonMetaClass
  219. toPackage: aPackageName ]
  220. !
  221. moveMethodToClass: aClassName
  222. self withChangesDo: [
  223. self environment
  224. moveMethod: self selectedMethod
  225. toClass: aClassName ]
  226. !
  227. moveMethodToProtocol: aProtocol
  228. self withChangesDo: [
  229. self environment
  230. moveMethod: self selectedMethod
  231. toProtocol: aProtocol ]
  232. !
  233. openClassNamed: aString
  234. | class |
  235. self withChangesDo: [
  236. class := self environment classNamed: aString.
  237. self selectedPackage: class package.
  238. self selectedClass: class ]
  239. !
  240. removeClass
  241. self withChangesDo: [
  242. self manager
  243. confirm: 'Do you REALLY want to remove class ', self selectedClass theNonMetaClass name
  244. ifTrue: [ self environment removeClass: self selectedClass theNonMetaClass ] ]
  245. !
  246. removeMethod
  247. self withChangesDo: [
  248. self manager
  249. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  250. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  251. !
  252. removeProtocol
  253. self withChangesDo: [
  254. self manager
  255. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  256. ifTrue: [ self environment
  257. removeProtocol: self selectedProtocol
  258. from: self selectedClass ] ]
  259. !
  260. renameClassTo: aClassName
  261. self withChangesDo: [
  262. self environment
  263. renameClass: self selectedClass theNonMetaClass
  264. to: aClassName ]
  265. !
  266. renamePackageTo: aPackageName
  267. self withChangesDo: [
  268. self environment
  269. renamePackage: self selectedPackage name
  270. to: aPackageName ]
  271. !
  272. renameProtocolTo: aString
  273. self withChangesDo: [
  274. self environment
  275. renameProtocol: self selectedProtocol
  276. to: aString
  277. in: self selectedClass ]
  278. ! !
  279. !HLToolModel methodsFor: 'compiling'!
  280. compileClassComment: aString
  281. self environment
  282. compileClassComment: aString
  283. for: self selectedClass
  284. !
  285. compileClassDefinition: aString
  286. self environment compileClassDefinition: aString
  287. !
  288. compileMethod: aString
  289. | method |
  290. self withCompileErrorHandling: [
  291. method := self environment
  292. compileMethod: aString
  293. for: self selectedClass
  294. protocol: self compilationProtocol.
  295. self selectedMethod: method ]
  296. ! !
  297. !HLToolModel methodsFor: 'defaults'!
  298. allProtocol
  299. ^ '-- all --'
  300. !
  301. unclassifiedProtocol
  302. ^ 'as yet unclassified'
  303. ! !
  304. !HLToolModel methodsFor: 'error handling'!
  305. handleCompileError: anError
  306. self announcer announce: (HLCompileErrorRaised new
  307. error: anError;
  308. yourself)
  309. !
  310. handleParseError: anError
  311. | split line column messageToInsert |
  312. split := anError messageText tokenize: ' : '.
  313. messageToInsert := split second.
  314. "21 = 'Parse error on line ' size + 1"
  315. split := split first copyFrom: 21 to: split first size.
  316. split := split tokenize: ' column '.
  317. line := split first.
  318. column := split second.
  319. self announcer announce: (HLParseErrorRaised new
  320. line: line asNumber;
  321. column: column asNumber;
  322. message: messageToInsert;
  323. error: anError;
  324. yourself)
  325. !
  326. handleUnkownVariableError: anError
  327. self announcer announce: (HLUnknownVariableErrorRaised new
  328. error: anError;
  329. yourself)
  330. !
  331. withCompileErrorHandling: aBlock
  332. self environment
  333. evaluate: [
  334. self environment
  335. evaluate: [
  336. self environment
  337. evaluate: aBlock
  338. on: ParseError
  339. do: [ :ex | self handleParseError: ex ] ]
  340. on: UnknownVariableError
  341. do: [ :ex | self handleUnkownVariableError: ex ] ]
  342. on: CompilerError
  343. do: [ :ex | self handleCompileError: ex ]
  344. ! !
  345. !HLToolModel methodsFor: 'private'!
  346. compilationProtocol
  347. | currentProtocol |
  348. currentProtocol := self selectedProtocol.
  349. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  350. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  351. ^ currentProtocol = self allProtocol
  352. ifTrue: [ self unclassifiedProtocol ]
  353. ifFalse: [ currentProtocol ]
  354. !
  355. withHelperLabelled: aString do: aBlock
  356. "TODO: doesn't belong here"
  357. '#helper' asJQuery remove.
  358. [ :html |
  359. html div
  360. id: 'helper';
  361. with: aString ] appendToJQuery: 'body' asJQuery.
  362. [
  363. aBlock value.
  364. '#helper' asJQuery remove ] fork
  365. ! !
  366. !HLToolModel methodsFor: 'testing'!
  367. isToolModel
  368. ^ true
  369. !
  370. shouldCompileDefinition: aString
  371. ^ self selectedClass isNil or: [
  372. aString match: '^\s*[A-Z]' ]
  373. ! !
  374. !HLToolModel class methodsFor: 'actions'!
  375. on: anEnvironment
  376. ^ self new
  377. environment: anEnvironment;
  378. yourself
  379. ! !
  380. Object subclass: #HLProgressHandler
  381. instanceVariableNames: ''
  382. package: 'Helios-Core'!
  383. !HLProgressHandler commentStamp!
  384. I am a specific progress handler for Helios, displaying progresses in a modal window.!
  385. !HLProgressHandler methodsFor: 'progress handling'!
  386. do: aBlock on: aCollection displaying: aString
  387. HLProgressWidget default
  388. do: aBlock
  389. on: aCollection
  390. displaying: aString
  391. ! !
  392. Widget subclass: #HLWidget
  393. instanceVariableNames: 'wrapper'
  394. package: 'Helios-Core'!
  395. !HLWidget commentStamp!
  396. I am the abstract superclass of all Helios widgets.
  397. I provide common methods, additional behavior to widgets useful for Helios, like dialog creation, command execution and tab creation.
  398. ## API
  399. 1. Rendering
  400. Instead of overriding `#renderOn:` as with other Widget subclasses, my subclasses should override `#renderContentOn:`.
  401. 2. Refreshing
  402. To re-render a widget, use `#refresh`.
  403. 3. Key bindings registration and tabs
  404. When displayed as a tab, the widget has a chance to register keybindings with the `#registerBindingsOn:` hook method.
  405. 4. Unregistration
  406. When a widget has subscribed to announcements or other actions that need to be cleared when closing the tab, the hook method `#unregister` will be called by helios.
  407. 5. Tabs
  408. To enable a widget class to be open as a tab, override the class-side `#canBeOpenAsTab` method to answer `true`. `#tabClass` and `#tabPriority` can be overridden too to respectively change the css class of the tab and the order of tabs in the main menu.
  409. 6. Command execution
  410. An helios command (instance of `HLCommand` or one of its subclass) can be executed with `#execute:`.!
  411. !HLWidget methodsFor: 'accessing'!
  412. cssClass
  413. ^ 'hl_widget'
  414. !
  415. manager
  416. ^ HLManager current
  417. !
  418. removeTab
  419. self manager removeTabForWidget: self
  420. !
  421. setTabLabel: aString
  422. self manager announcer announce: (HLTabLabelChanged new
  423. widget: self;
  424. label: aString;
  425. yourself)
  426. !
  427. tabClass
  428. ^ self class tabClass
  429. !
  430. wrapper
  431. ^ wrapper
  432. ! !
  433. !HLWidget methodsFor: 'actions'!
  434. confirm: aString ifTrue: aBlock
  435. self manager confirm: aString ifTrue: aBlock
  436. !
  437. confirm: aString ifTrue: aBlock ifFalse: anotherBlock
  438. self manager
  439. confirm: aString
  440. ifTrue: aBlock
  441. ifFalse: anotherBlock
  442. !
  443. execute: aCommand
  444. HLManager current keyBinder
  445. activate;
  446. applyBinding: aCommand asBinding.
  447. (HLShortcutSuggestionWidget new)
  448. command: aCommand;
  449. show.
  450. !
  451. inform: aString
  452. self manager inform: aString
  453. !
  454. openAsTab
  455. (HLTabWidget on: self labelled: self defaultTabLabel)
  456. add
  457. !
  458. request: aString do: aBlock
  459. self manager request: aString do: aBlock
  460. !
  461. request: aString value: valueString do: aBlock
  462. self manager
  463. request: aString
  464. value: valueString
  465. do: aBlock
  466. !
  467. unregister
  468. "This method is called whenever the receiver is closed (as a tab).
  469. Widgets subscribing to announcements should unregister there"
  470. ! !
  471. !HLWidget methodsFor: 'defaults'!
  472. defaultTabLabel
  473. ^ self class tabLabel
  474. ! !
  475. !HLWidget methodsFor: 'keybindings'!
  476. bindKeyDown: keyDownBlock keyUp: keyUpBlock
  477. self wrapper ifNotNil: [ wrapper
  478. onKeyDown: keyDownBlock;
  479. onKeyUp: keyUpBlock ]
  480. !
  481. registerBindings
  482. self registerBindingsOn: self manager keyBinder bindings
  483. !
  484. registerBindingsOn: aBindingGroup
  485. !
  486. unbindKeyDownKeyUp
  487. self wrapper asJQuery
  488. unbind: 'keydown';
  489. unbind: 'keyup'
  490. ! !
  491. !HLWidget methodsFor: 'rendering'!
  492. renderContentOn: html
  493. !
  494. renderOn: html
  495. wrapper := html div
  496. class: self cssClass;
  497. yourself.
  498. "must do this later, as renderContentOn may want to use self wrapper"
  499. wrapper with: [ self renderContentOn: html ]
  500. ! !
  501. !HLWidget methodsFor: 'testing'!
  502. canHaveFocus
  503. ^ false
  504. ! !
  505. !HLWidget methodsFor: 'updating'!
  506. refresh
  507. self wrapper
  508. ifNotNil: [ :wrap | wrap contents: [ :html | self renderContentOn: html ] ]
  509. ! !
  510. !HLWidget class methodsFor: 'accessing'!
  511. openAsTab
  512. | instance |
  513. instance := self new.
  514. (HLTabWidget
  515. on: instance
  516. labelled: instance defaultTabLabel) add.
  517. ^ instance
  518. !
  519. tabClass
  520. ^ ''
  521. !
  522. tabLabel
  523. ^ 'Tab'
  524. !
  525. tabPriority
  526. ^ 500
  527. ! !
  528. !HLWidget class methodsFor: 'testing'!
  529. canBeOpenAsTab
  530. ^ false
  531. ! !
  532. HLWidget subclass: #HLContextMenuWidget
  533. instanceVariableNames: 'commands'
  534. package: 'Helios-Core'!
  535. !HLContextMenuWidget methodsFor: 'as yet unclassified'!
  536. bindToElement: anElement
  537. anElement asDomNode
  538. setAttribute: 'data-toggle' put: 'dropdown';
  539. addEventListener: 'contextmenu' do: [ :evt |
  540. evt preventDefault.
  541. self openForEvent: evt
  542. ]
  543. !
  544. openForEvent: anEvent
  545. | rect x y |
  546. x := anEvent clientX.
  547. y := anEvent clientY.
  548. (self wrapper asDomNode querySelector: '.dropdown-menu') style
  549. left: x, 'px';
  550. top: y, 'px'.
  551. self wrapper asJQuery dropdown toggle
  552. !
  553. renderContentOn: html
  554. html ul
  555. class: 'dropdown-menu';
  556. style: 'position: fixed';
  557. width: [
  558. html li
  559. with: [
  560. html a
  561. with: 'Test';
  562. onClick: [ window alert: 'Clicked Test' ]
  563. ]
  564. ]
  565. ! !
  566. HLWidget subclass: #HLFocusableWidget
  567. instanceVariableNames: ''
  568. package: 'Helios-Core'!
  569. !HLFocusableWidget commentStamp!
  570. I am a widget that can be focused.
  571. ## API
  572. Instead of overriding `#renderOn:` as with other `Widget` subclasses, my subclasses should override `#renderContentOn:`.
  573. To bring the focus to the widget, use the `#focus` method.!
  574. !HLFocusableWidget methodsFor: 'accessing'!
  575. focusClass
  576. ^ 'focused'
  577. ! !
  578. !HLFocusableWidget methodsFor: 'events'!
  579. blur
  580. self wrapper asJQuery blur
  581. !
  582. focus
  583. self wrapper asJQuery focus
  584. ! !
  585. !HLFocusableWidget methodsFor: 'rendering'!
  586. renderContentOn: html
  587. !
  588. renderOn: html
  589. wrapper := html div
  590. class: self cssClass;
  591. at: 'tabindex' put: '0';
  592. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  593. onFocus: [ self wrapper asJQuery addClass: self focusClass ];
  594. yourself.
  595. "must do this later, as renderContentOn may want to use self wrapper"
  596. wrapper with: [ self renderContentOn: html ]
  597. ! !
  598. !HLFocusableWidget methodsFor: 'testing'!
  599. canHaveFocus
  600. ^ true
  601. !
  602. hasFocus
  603. ^ self wrapper notNil and: [ self wrapper asJQuery hasClass: self focusClass ]
  604. ! !
  605. HLFocusableWidget subclass: #HLListWidget
  606. instanceVariableNames: 'items selectedItem'
  607. package: 'Helios-Core'!
  608. !HLListWidget methodsFor: 'accessing'!
  609. activeItemCssClass
  610. ^'active'
  611. !
  612. buttonsDivCssClass
  613. ^ 'pane_actions form-group'
  614. !
  615. cssClassForItem: anObject
  616. ^ ''
  617. !
  618. findListItemFor: anObject
  619. ^ (((wrapper asJQuery find: 'li')
  620. filter: [ :thisArg :otherArg | (thisArg asJQuery data: 'item') = anObject ] currySelf) eq: 0)
  621. !
  622. items
  623. ^ items ifNil: [ items := self defaultItems ]
  624. !
  625. items: aCollection
  626. items := aCollection
  627. !
  628. listCssClass
  629. ^'nav nav-pills nav-stacked'
  630. !
  631. listCssClassForItem: anObject
  632. ^ self selectedItem = anObject
  633. ifTrue: [ self activeItemCssClass ]
  634. ifFalse: [ 'inactive' ]
  635. !
  636. positionOf: aListItem
  637. <inlineJS: '
  638. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  639. '>
  640. !
  641. selectedItem
  642. ^ selectedItem
  643. !
  644. selectedItem: anObject
  645. selectedItem := anObject
  646. ! !
  647. !HLListWidget methodsFor: 'actions'!
  648. activateFirstListItem
  649. self activateListItem: ((wrapper asJQuery find: 'li.inactive') eq: 0)
  650. !
  651. activateItem: anObject
  652. self activateListItem: (self findListItemFor: anObject)
  653. !
  654. activateListItem: aListItem
  655. | item |
  656. (aListItem get: 0) ifNil: [ ^ self ].
  657. aListItem parent children removeClass: self activeItemCssClass.
  658. aListItem addClass: self activeItemCssClass.
  659. self ensureVisible: aListItem.
  660. "Activate the corresponding item"
  661. item := aListItem data: 'item'.
  662. self selectedItem == item ifFalse: [
  663. self selectItem: item ]
  664. !
  665. activateNextListItem
  666. self activateListItem: (self wrapper asJQuery find: ('li.', self activeItemCssClass)) next.
  667. "select the first item if none is selected"
  668. (self wrapper asJQuery find: (' .', self activeItemCssClass)) get ifEmpty: [
  669. self activateFirstListItem ]
  670. !
  671. activatePreviousListItem
  672. self activateListItem: (self wrapper asJQuery find: ('li.', self activeItemCssClass)) prev
  673. !
  674. ensureVisible: aListItem
  675. "Move the scrollbar to show the active element"
  676. | parent position |
  677. (aListItem get: 0) ifNil: [ ^ self ].
  678. position := self positionOf: aListItem.
  679. parent := aListItem parent.
  680. aListItem position top < 0 ifTrue: [
  681. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  682. aListItem position top + aListItem height > parent height ifTrue: [
  683. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
  684. !
  685. focus
  686. super focus.
  687. self items ifNotEmpty: [
  688. self selectedItem ifNil: [ self activateFirstListItem ] ]
  689. !
  690. reactivateListItem: aListItem
  691. self activateListItem: aListItem.
  692. self reselectItem: self selectedItem
  693. !
  694. refresh
  695. super refresh.
  696. self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
  697. !
  698. reselectItem: anObject
  699. !
  700. selectItem: anObject
  701. self selectedItem: anObject
  702. ! !
  703. !HLListWidget methodsFor: 'defaults'!
  704. defaultItems
  705. ^ #()
  706. ! !
  707. !HLListWidget methodsFor: 'events'!
  708. setupKeyBindings
  709. (HLRepeatedKeyDownHandler on: self)
  710. whileKeyDown: 38 do: [ self activatePreviousListItem ];
  711. whileKeyDown: 40 do: [ self activateNextListItem ];
  712. rebindKeys.
  713. self wrapper asJQuery keydown: [ :e |
  714. e which = 13 ifTrue: [
  715. self reselectItem: self selectedItem ] ]
  716. ! !
  717. !HLListWidget methodsFor: 'rendering'!
  718. renderButtonsOn: html
  719. !
  720. renderContentOn: html
  721. | ul contextMenu |
  722. contextMenu := HLContextMenuWidget new.
  723. ul := html ul
  724. class: self listCssClass;
  725. with: [ self renderListOn: html ];
  726. onClick: [ :evt | console log: evt. self focus ].
  727. contextMenu bindToElement: ul.
  728. html div class: self buttonsDivCssClass; with: [
  729. self renderButtonsOn: html ].
  730. html with: contextMenu.
  731. self setupKeyBindings
  732. !
  733. renderItem: anObject on: html
  734. | li |
  735. li := html li.
  736. li asJQuery data: 'item' put: anObject.
  737. li
  738. class: (self listCssClassForItem: anObject);
  739. with: [
  740. html a
  741. with: [
  742. (html tag: 'i') class: (self cssClassForItem: anObject).
  743. self renderItemLabel: anObject on: html ];
  744. onClick: [
  745. self reactivateListItem: li asJQuery ] ]
  746. !
  747. renderItemLabel: anObject on: html
  748. html with: anObject asString
  749. !
  750. renderListOn: html
  751. self items do: [ :each |
  752. self renderItem: each on: html ]
  753. ! !
  754. HLListWidget subclass: #HLNavigationListWidget
  755. instanceVariableNames: 'previous next'
  756. package: 'Helios-Core'!
  757. !HLNavigationListWidget methodsFor: 'accessing'!
  758. next
  759. ^ next
  760. !
  761. next: aWidget
  762. next := aWidget.
  763. aWidget previous = self ifFalse: [ aWidget previous: self ]
  764. !
  765. previous
  766. ^ previous
  767. !
  768. previous: aWidget
  769. previous := aWidget.
  770. aWidget next = self ifFalse: [ aWidget next: self ]
  771. ! !
  772. !HLNavigationListWidget methodsFor: 'actions'!
  773. nextFocus
  774. self next ifNotNil: [ self next focus ]
  775. !
  776. previousFocus
  777. self previous ifNotNil: [ self previous focus ]
  778. ! !
  779. !HLNavigationListWidget methodsFor: 'events'!
  780. setupKeyBindings
  781. super setupKeyBindings.
  782. self wrapper ifNotNil: [ wrapper onKeyDown: [ :e |
  783. e which = 39 ifTrue: [
  784. self nextFocus ].
  785. e which = 37 ifTrue: [
  786. self previousFocus ] ] ]
  787. ! !
  788. HLNavigationListWidget subclass: #HLToolListWidget
  789. instanceVariableNames: 'model'
  790. package: 'Helios-Core'!
  791. !HLToolListWidget methodsFor: 'accessing'!
  792. commandCategory
  793. ^ self label
  794. !
  795. label
  796. ^ 'List'
  797. !
  798. menuCommands
  799. "Answer a collection of commands to be put in the cog menu"
  800. ^ ((HLToolCommand concreteClasses
  801. select: [ :each | each isValidFor: self model ])
  802. collect: [ :each | each for: self model ])
  803. select: [ :each |
  804. each category = self commandCategory and: [
  805. each isAction and: [ each isActive ] ] ]
  806. !
  807. model
  808. ^ model
  809. !
  810. model: aBrowserModel
  811. model := aBrowserModel.
  812. self
  813. observeSystem;
  814. observeModel
  815. !
  816. selectedItem: anItem
  817. "Selection changed, update the cog menu"
  818. super selectedItem: anItem.
  819. self updateMenu
  820. ! !
  821. !HLToolListWidget methodsFor: 'actions'!
  822. activateListItem: anItem
  823. self model withChangesDo: [ super activateListItem: anItem ]
  824. !
  825. activateNextListItem
  826. self model withChangesDo: [ super activateNextListItem ]
  827. !
  828. activatePreviousListItem
  829. self model withChangesDo: [ super activatePreviousListItem ]
  830. !
  831. observeModel
  832. !
  833. observeSystem
  834. !
  835. reactivateListItem: anItem
  836. self model withChangesDo: [ super reactivateListItem: anItem ]
  837. !
  838. unregister
  839. super unregister.
  840. self model announcer unsubscribe: self.
  841. self model systemAnnouncer unsubscribe: self
  842. ! !
  843. !HLToolListWidget methodsFor: 'rendering'!
  844. renderContentOn: html
  845. self renderHeadOn: html.
  846. super renderContentOn: html
  847. !
  848. renderHeadOn: html
  849. html div
  850. class: 'list-label';
  851. with: [
  852. html with: self label.
  853. self renderMenuOn: html ]
  854. !
  855. renderMenuOn: html
  856. | commands |
  857. commands := self menuCommands.
  858. commands ifEmpty: [ ^ self ].
  859. html div
  860. class: 'btn-group cog';
  861. with: [
  862. html a
  863. class: 'btn btn-default dropdown-toggle';
  864. at: 'data-toggle' put: 'dropdown';
  865. with: [ (html tag: 'i') class: 'glyphicon glyphicon-chevron-down' ].
  866. html ul
  867. class: 'dropdown-menu pull-right';
  868. with: [
  869. commands do: [ :each |
  870. html li with: [ html a
  871. with: each menuLabel;
  872. onClick: [ self execute: each ] ] ] ] ]
  873. ! !
  874. !HLToolListWidget methodsFor: 'updating'!
  875. updateMenu
  876. (self wrapper asJQuery find: '.cog') remove.
  877. [ :html | self renderMenuOn: html ]
  878. appendToJQuery: (self wrapper asJQuery find: '.list-label')
  879. ! !
  880. !HLToolListWidget class methodsFor: 'instance creation'!
  881. on: aModel
  882. ^ self new
  883. model: aModel;
  884. yourself
  885. ! !
  886. HLListWidget subclass: #HLTabListWidget
  887. instanceVariableNames: 'callback'
  888. package: 'Helios-Core'!
  889. !HLTabListWidget commentStamp!
  890. I am a widget used to display a list of helios tabs.
  891. When a tab is selected, `callback` is evaluated with the selected tab as argument.!
  892. !HLTabListWidget methodsFor: 'accessing'!
  893. callback
  894. ^ callback ifNil: [ [] ]
  895. !
  896. callback: aBlock
  897. callback := aBlock
  898. ! !
  899. !HLTabListWidget methodsFor: 'actions'!
  900. selectItem: aTab
  901. super selectItem: aTab.
  902. self callback value: aTab
  903. ! !
  904. !HLTabListWidget methodsFor: 'rendering'!
  905. renderItemLabel: aTab on: html
  906. html span
  907. class: aTab cssClass;
  908. with: aTab label
  909. ! !
  910. HLWidget subclass: #HLInformationWidget
  911. instanceVariableNames: 'informationString'
  912. package: 'Helios-Core'!
  913. !HLInformationWidget commentStamp!
  914. I display an information dialog.
  915. ## API
  916. `HLWidget >> #inform:` is a convenience method for creating information dialogs.!
  917. !HLInformationWidget methodsFor: 'accessing'!
  918. informationString
  919. ^ informationString ifNil: [ '' ]
  920. !
  921. informationString: anObject
  922. informationString := anObject
  923. ! !
  924. !HLInformationWidget methodsFor: 'actions'!
  925. remove
  926. [
  927. self wrapper asJQuery fadeOut: 100.
  928. [ self wrapper asJQuery remove ]
  929. valueWithTimeout: 400.
  930. ]
  931. valueWithTimeout: 1500
  932. !
  933. show
  934. self appendToJQuery: 'body' asJQuery
  935. ! !
  936. !HLInformationWidget methodsFor: 'rendering'!
  937. renderContentOn: html
  938. html div
  939. class: 'growl';
  940. with: self informationString.
  941. self remove
  942. ! !
  943. HLWidget subclass: #HLManager
  944. instanceVariableNames: 'tabsWidget environment history announcer rendered'
  945. package: 'Helios-Core'!
  946. !HLManager commentStamp!
  947. HLManager is the entry point Class of Helios.
  948. Its `singleton` instance is created on startup, and rendered on body.!
  949. !HLManager methodsFor: 'accessing'!
  950. activeTab
  951. ^ self tabsWidget activeTab
  952. !
  953. announcer
  954. ^ announcer ifNil: [ announcer := Announcer new ]
  955. !
  956. environment
  957. "The default environment used by all Helios objects"
  958. ^ environment ifNil: [ environment := self defaultEnvironment ]
  959. !
  960. environment: anEnvironment
  961. environment := anEnvironment
  962. !
  963. history
  964. ^ history ifNil: [ history := OrderedCollection new ]
  965. !
  966. history: aCollection
  967. history := aCollection
  968. !
  969. keyBinder
  970. ^ HLKeyBinder current
  971. !
  972. setEditorTheme: aTheme
  973. 'helios.editorTheme' asSetting value: aTheme
  974. !
  975. setTheme: aTheme
  976. | currentTheme |
  977. currentTheme := 'helios.theme' asSettingIfAbsent: 'default'.
  978. 'body' asJQuery
  979. removeClass: currentTheme value;
  980. addClass: aTheme.
  981. 'helios.theme' asSetting value: aTheme
  982. !
  983. tabWidth
  984. ^ (window asJQuery width - 90) / self tabs size
  985. !
  986. tabs
  987. ^ self tabsWidget tabs
  988. !
  989. tabsWidget
  990. ^ tabsWidget ifNil: [ tabsWidget := HLTabsWidget new ]
  991. ! !
  992. !HLManager methodsFor: 'actions'!
  993. activate: aTab
  994. self tabsWidget activate: aTab
  995. !
  996. addTab: aTab
  997. self tabsWidget addTab: aTab
  998. !
  999. confirm: aString ifFalse: aBlock
  1000. self
  1001. confirm: aString
  1002. ifTrue: []
  1003. ifFalse: aBlock
  1004. !
  1005. confirm: aString ifTrue: aBlock
  1006. self
  1007. confirm: aString
  1008. ifTrue: aBlock
  1009. ifFalse: []
  1010. !
  1011. confirm: aString ifTrue: aBlock ifFalse: anotherBlock
  1012. HLConfirmationWidget new
  1013. confirmationString: aString;
  1014. actionBlock: aBlock;
  1015. cancelBlock: anotherBlock;
  1016. show
  1017. !
  1018. handleLossOfEnvironmentWithParent: parent
  1019. parent at: 'onunload' put: [
  1020. self removeBeforeUnloadMessage.
  1021. window close ]
  1022. !
  1023. inform: aString
  1024. HLInformationWidget new
  1025. informationString: aString;
  1026. show
  1027. !
  1028. removeActiveTab
  1029. self tabsWidget removeActiveTab
  1030. !
  1031. removeBeforeUnloadMessage
  1032. <inlineJS: 'window.onbeforeunload = null'>
  1033. !
  1034. removeTabForWidget: aWidget
  1035. self tabsWidget removeTabForWidget: aWidget
  1036. !
  1037. request: aString do: aBlock
  1038. self
  1039. request: aString
  1040. value: ''
  1041. do: aBlock
  1042. !
  1043. request: aString value: valueString do: aBlock
  1044. HLRequestWidget new
  1045. confirmationString: aString;
  1046. actionBlock: aBlock;
  1047. value: valueString;
  1048. show
  1049. ! !
  1050. !HLManager methodsFor: 'defaults'!
  1051. defaultEnvironment
  1052. "If helios is loaded from within a frame, answer the parent window environment"
  1053. | parent parentSmalltalkGlobals |
  1054. parent := window opener ifNil: [ window parent ].
  1055. parent ifNil: [ ^ Environment new ].
  1056. [ parentSmalltalkGlobals := ((parent at: 'requirejs') value: 'amber/boot') at: 'globals' ]
  1057. on: Error do: [ parentSmalltalkGlobals := (parent at: 'requirejs') value: 'amber_vm/globals' ].
  1058. parentSmalltalkGlobals ifNil: [ ^ Environment new ].
  1059. self handleLossOfEnvironmentWithParent: parent.
  1060. ^ (parentSmalltalkGlobals at: 'Environment') new
  1061. ! !
  1062. !HLManager methodsFor: 'initialization'!
  1063. initialize
  1064. super initialize.
  1065. rendered := false
  1066. !
  1067. setup
  1068. self
  1069. registerServices;
  1070. setupEvents.
  1071. self keyBinder setupEvents.
  1072. self tabsWidget setupEvents.
  1073. self setupTheme.
  1074. '#helper' asJQuery fadeOut
  1075. ! !
  1076. !HLManager methodsFor: 'private'!
  1077. registerServices
  1078. self
  1079. registerInspector;
  1080. registerErrorHandler;
  1081. registerProgressHandler;
  1082. registerTranscript;
  1083. registerFinder
  1084. !
  1085. setupEvents
  1086. 'body' asJQuery keydown: [ :event |
  1087. "On ctrl keydown, adds a 'navigation' css class to <body>
  1088. for the CodeMirror navigation links. See `HLCodeWidget`."
  1089. event ctrlKey ifTrue: [
  1090. 'body' asJQuery addClass: 'navigation' ] ].
  1091. 'body' asJQuery keyup: [ :event |
  1092. 'body' asJQuery removeClass: 'navigation' ].
  1093. window asJQuery resize: [ :event |
  1094. self refresh ]
  1095. !
  1096. setupTheme
  1097. "self
  1098. setTheme: 'niflheim';
  1099. setEditorTheme: 'niflheim'."
  1100. self
  1101. setTheme: 'default';
  1102. setEditorTheme: 'default'.
  1103. ! !
  1104. !HLManager methodsFor: 'rendering'!
  1105. renderContentOn: html
  1106. html with: self tabsWidget.
  1107. html with: HLWelcomeWidget new.
  1108. self renderDefaultTabs.
  1109. rendered := true
  1110. !
  1111. renderDefaultTabs
  1112. rendered ifFalse: [
  1113. HLWorkspace openAsTab.
  1114. HLBrowser openAsTab ]
  1115. ! !
  1116. !HLManager methodsFor: 'services'!
  1117. registerErrorHandler
  1118. self environment registerErrorHandler: HLErrorHandler new.
  1119. ErrorHandler register: HLErrorHandler new
  1120. !
  1121. registerFinder
  1122. self environment registerFinder: HLFinder new.
  1123. Finder register: HLFinder new
  1124. !
  1125. registerInspector
  1126. self environment registerInspector: HLInspector.
  1127. Inspector register: HLInspector
  1128. !
  1129. registerProgressHandler
  1130. self environment registerProgressHandler: HLProgressHandler new.
  1131. ProgressHandler register: HLProgressHandler new
  1132. !
  1133. registerTranscript
  1134. self environment registerTranscript: HLTranscriptHandler
  1135. ! !
  1136. HLManager class instanceVariableNames: 'current'!
  1137. !HLManager class methodsFor: 'accessing'!
  1138. current
  1139. ^ current ifNil: [ current := self basicNew initialize ]
  1140. ! !
  1141. !HLManager class methodsFor: 'initialization'!
  1142. setup
  1143. self current
  1144. setup;
  1145. appendToJQuery: 'body' asJQuery.
  1146. ('helios.confirmOnExit' settingValueIfAbsent: true) ifTrue: [
  1147. window onbeforeunload: [ 'Do you want to close Amber? All uncommitted changes will be lost.' ] ]
  1148. ! !
  1149. !HLManager class methodsFor: 'instance creation'!
  1150. new
  1151. "Use current instead"
  1152. self shouldNotImplement
  1153. ! !
  1154. HLWidget subclass: #HLModalWidget
  1155. instanceVariableNames: ''
  1156. package: 'Helios-Core'!
  1157. !HLModalWidget commentStamp!
  1158. I implement an abstract modal widget.!
  1159. !HLModalWidget methodsFor: 'actions'!
  1160. remove
  1161. '.dialog' asJQuery removeClass: 'active'.
  1162. [
  1163. '#overlay' asJQuery remove.
  1164. wrapper asJQuery remove
  1165. ] valueWithTimeout: 300
  1166. !
  1167. show
  1168. self appendToJQuery: 'body' asJQuery
  1169. ! !
  1170. !HLModalWidget methodsFor: 'private'!
  1171. giveFocusToButton: aButton
  1172. aButton asJQuery focus
  1173. ! !
  1174. !HLModalWidget methodsFor: 'rendering'!
  1175. hasButtons
  1176. ^ true
  1177. !
  1178. renderButtonsOn: html
  1179. !
  1180. renderContentOn: html
  1181. html div id: 'overlay'.
  1182. html div
  1183. class: 'dialog ', self cssClass;
  1184. with: [
  1185. self renderMainOn: html.
  1186. self hasButtons ifTrue: [
  1187. self renderButtonsOn: html ] ].
  1188. '.dialog' asJQuery addClass: 'active'.
  1189. self setupKeyBindings
  1190. !
  1191. renderMainOn: html
  1192. !
  1193. setupKeyBindings
  1194. '.dialog' asJQuery keyup: [ :e |
  1195. e keyCode = String esc asciiValue ifTrue: [ self cancel ] ]
  1196. ! !
  1197. HLModalWidget subclass: #HLConfirmationWidget
  1198. instanceVariableNames: 'cancelButtonLabel confirmButtonLabel confirmationString actionBlock cancelBlock'
  1199. package: 'Helios-Core'!
  1200. !HLConfirmationWidget commentStamp!
  1201. I display confirmation dialog.
  1202. ## API
  1203. HLWidget contains convenience methods like `HLWidget >> #confirm:ifTrue:` for creating confirmation dialogs.!
  1204. !HLConfirmationWidget methodsFor: 'accessing'!
  1205. actionBlock
  1206. ^ actionBlock ifNil: [ [] ]
  1207. !
  1208. actionBlock: aBlock
  1209. actionBlock := aBlock
  1210. !
  1211. cancelBlock
  1212. ^ cancelBlock ifNil: [ [] ]
  1213. !
  1214. cancelBlock: aBlock
  1215. cancelBlock := aBlock
  1216. !
  1217. cancelButtonLabel
  1218. ^ cancelButtonLabel ifNil: [ 'Cancel' ]
  1219. !
  1220. cancelButtonLabel: aString
  1221. ^ cancelButtonLabel := aString
  1222. !
  1223. confirmButtonLabel
  1224. ^ confirmButtonLabel ifNil: [ 'Confirm' ]
  1225. !
  1226. confirmButtonLabel: aString
  1227. ^ confirmButtonLabel := aString
  1228. !
  1229. confirmationString
  1230. ^ confirmationString ifNil: [ 'Confirm' ]
  1231. !
  1232. confirmationString: aString
  1233. confirmationString := aString
  1234. ! !
  1235. !HLConfirmationWidget methodsFor: 'actions'!
  1236. cancel
  1237. self cancelBlock value.
  1238. self remove
  1239. !
  1240. confirm
  1241. self remove.
  1242. self actionBlock value
  1243. ! !
  1244. !HLConfirmationWidget methodsFor: 'rendering'!
  1245. renderButtonsOn: html
  1246. | confirmButton |
  1247. html div
  1248. class: 'buttons';
  1249. with: [
  1250. html button
  1251. class: 'button';
  1252. with: self cancelButtonLabel;
  1253. onClick: [ self cancel ].
  1254. confirmButton := html button
  1255. class: 'button default';
  1256. with: self confirmButtonLabel;
  1257. onClick: [ self confirm ] ].
  1258. self giveFocusToButton:confirmButton
  1259. !
  1260. renderMainOn: html
  1261. html span
  1262. class: 'head';
  1263. with: self confirmationString
  1264. ! !
  1265. HLConfirmationWidget subclass: #HLRequestWidget
  1266. instanceVariableNames: 'input multiline value'
  1267. package: 'Helios-Core'!
  1268. !HLRequestWidget commentStamp!
  1269. I display a modal window requesting user input.
  1270. ## API
  1271. `HLWidget >> #request:do:` and `#request:value:do:` are convenience methods for creating modal request dialogs.!
  1272. !HLRequestWidget methodsFor: 'accessing'!
  1273. beMultiline
  1274. multiline := true
  1275. !
  1276. beSingleline
  1277. multiline := false
  1278. !
  1279. cssClass
  1280. ^ 'large'
  1281. !
  1282. value
  1283. ^ value ifNil: [ '' ]
  1284. !
  1285. value: aString
  1286. value := aString
  1287. ! !
  1288. !HLRequestWidget methodsFor: 'actions'!
  1289. confirm
  1290. | val |
  1291. val := input asJQuery val.
  1292. self remove.
  1293. self actionBlock value: val
  1294. ! !
  1295. !HLRequestWidget methodsFor: 'private'!
  1296. giveFocusToButton: aButton
  1297. ! !
  1298. !HLRequestWidget methodsFor: 'rendering'!
  1299. renderMainOn: html
  1300. super renderMainOn: html.
  1301. self isMultiline
  1302. ifTrue: [ input := html textarea ]
  1303. ifFalse: [ input := html input
  1304. type: 'text';
  1305. onKeyDown: [ :event |
  1306. event keyCode = 13 ifTrue: [
  1307. self confirm ] ];
  1308. yourself ].
  1309. input asJQuery
  1310. val: self value;
  1311. focus
  1312. ! !
  1313. !HLRequestWidget methodsFor: 'testing'!
  1314. isMultiline
  1315. ^ multiline ifNil: [ true ]
  1316. ! !
  1317. HLModalWidget subclass: #HLProgressWidget
  1318. instanceVariableNames: 'progressBars visible'
  1319. package: 'Helios-Core'!
  1320. !HLProgressWidget commentStamp!
  1321. I am a widget used to display progress modal dialogs.
  1322. My default instance is accessed with `HLProgressWidget class >> #default`.
  1323. See `HLProgressHandler` for usage.!
  1324. !HLProgressWidget methodsFor: 'accessing'!
  1325. progressBars
  1326. ^ progressBars ifNil: [ progressBars := OrderedCollection new ]
  1327. ! !
  1328. !HLProgressWidget methodsFor: 'actions'!
  1329. addProgressBar: aProgressBar
  1330. self show.
  1331. self progressBars add: aProgressBar.
  1332. aProgressBar appendToJQuery: (self wrapper asJQuery find: '.dialog')
  1333. !
  1334. do: aBlock on: aCollection displaying: aString
  1335. | progressBar |
  1336. progressBar := HLProgressBarWidget new
  1337. parent: self;
  1338. label: aString;
  1339. workBlock: aBlock;
  1340. collection: aCollection;
  1341. yourself.
  1342. self addProgressBar: progressBar.
  1343. progressBar start
  1344. !
  1345. flush
  1346. self progressBars do: [ :each |
  1347. self removeProgressBar: each ]
  1348. !
  1349. remove
  1350. self isVisible ifTrue: [
  1351. visible := false.
  1352. super remove ]
  1353. !
  1354. removeProgressBar: aProgressBar
  1355. self progressBars remove: aProgressBar ifAbsent: [].
  1356. aProgressBar wrapper asJQuery remove.
  1357. self progressBars ifEmpty: [ self remove ]
  1358. !
  1359. show
  1360. self isVisible ifFalse: [
  1361. visible := true.
  1362. super show ]
  1363. ! !
  1364. !HLProgressWidget methodsFor: 'rendering'!
  1365. renderMainOn: html
  1366. self progressBars do: [ :each |
  1367. html with: each ]
  1368. ! !
  1369. !HLProgressWidget methodsFor: 'testing'!
  1370. hasButtons
  1371. ^ false
  1372. !
  1373. isVisible
  1374. ^ visible ifNil: [ false ]
  1375. ! !
  1376. HLProgressWidget class instanceVariableNames: 'default'!
  1377. !HLProgressWidget class methodsFor: 'accessing'!
  1378. default
  1379. ^ default ifNil: [ default := self new ]
  1380. ! !
  1381. HLModalWidget subclass: #HLShortcutSuggestionWidget
  1382. instanceVariableNames: 'command'
  1383. package: 'Helios-Core'!
  1384. !HLShortcutSuggestionWidget commentStamp!
  1385. I am a modal that displays the keyboard shortcut associated to a specific command.!
  1386. !HLShortcutSuggestionWidget methodsFor: 'accessing'!
  1387. command
  1388. ^ command
  1389. !
  1390. command: aCommand
  1391. command := aCommand
  1392. ! !
  1393. !HLShortcutSuggestionWidget methodsFor: 'actions'!
  1394. show
  1395. super show.
  1396. [ self remove ] valueWithTimeout: self visibleDelay.
  1397. ! !
  1398. !HLShortcutSuggestionWidget methodsFor: 'constants'!
  1399. visibleDelay
  1400. ^ 2000
  1401. ! !
  1402. !HLShortcutSuggestionWidget methodsFor: 'rendering'!
  1403. hasButtons
  1404. ^ false
  1405. !
  1406. renderMainOn: html
  1407. html div
  1408. class: 'title';
  1409. with: command label.
  1410. html p
  1411. with: 'Ctrl-space + ', (command keySequence join: ' + ')
  1412. ! !
  1413. !HLShortcutSuggestionWidget class methodsFor: 'instance creation'!
  1414. command: aCommand
  1415. ^ self new command: aCommand
  1416. ! !
  1417. HLModalWidget subclass: #HLTabSelectionWidget
  1418. instanceVariableNames: 'tabs tabList selectedTab selectCallback cancelCallback confirmCallback'
  1419. package: 'Helios-Core'!
  1420. !HLTabSelectionWidget commentStamp!
  1421. I am a modal window used to select or create tabs.!
  1422. !HLTabSelectionWidget methodsFor: 'accessing'!
  1423. cancelCallback
  1424. ^ cancelCallback ifNil: [ [] ]
  1425. !
  1426. cancelCallback: aBlock
  1427. cancelCallback := aBlock
  1428. !
  1429. confirmCallback
  1430. ^ confirmCallback ifNil: [ [] ]
  1431. !
  1432. confirmCallback: aBlock
  1433. confirmCallback := aBlock
  1434. !
  1435. selectCallback
  1436. ^ selectCallback ifNil: [ [] ]
  1437. !
  1438. selectCallback: aBlock
  1439. selectCallback := aBlock
  1440. !
  1441. selectedTab
  1442. ^ selectedTab
  1443. !
  1444. selectedTab: aTab
  1445. selectedTab := aTab
  1446. !
  1447. tabs
  1448. ^ tabs ifNil: [ #() ]
  1449. !
  1450. tabs: aCollection
  1451. tabs := aCollection
  1452. ! !
  1453. !HLTabSelectionWidget methodsFor: 'actions'!
  1454. cancel
  1455. self remove.
  1456. self cancelCallback value
  1457. !
  1458. confirm
  1459. self remove.
  1460. self confirmCallback value: self selectedTab
  1461. !
  1462. selectTab: aTab
  1463. self selectedTab: aTab.
  1464. self selectCallback value: aTab
  1465. !
  1466. setupKeyBindings
  1467. super setupKeyBindings.
  1468. '.dialog' asJQuery keyup: [ :e |
  1469. e keyCode = String cr asciiValue ifTrue: [ self confirm ] ]
  1470. ! !
  1471. !HLTabSelectionWidget methodsFor: 'rendering'!
  1472. renderButtonsOn: html
  1473. | confirmButton |
  1474. html div
  1475. class: 'buttons';
  1476. with: [
  1477. html button
  1478. class: 'button';
  1479. with: 'Cancel';
  1480. onClick: [ self cancel ].
  1481. confirmButton := html button
  1482. class: 'button default';
  1483. with: 'Select tab';
  1484. onClick: [ self confirm ] ].
  1485. self giveFocusToButton:confirmButton
  1486. !
  1487. renderContentOn: html
  1488. super renderContentOn: html.
  1489. self tabList focus
  1490. !
  1491. renderMainOn: html
  1492. html div
  1493. class: 'title';
  1494. with: 'Tab selection'.
  1495. html with: self tabList
  1496. !
  1497. renderTab: aTab on: html
  1498. html
  1499. span
  1500. class: aTab cssClass;
  1501. with: aTab label
  1502. !
  1503. renderTabsOn: html
  1504. self tabs do: [ :each |
  1505. html li with: [
  1506. html a
  1507. with: [
  1508. self renderTab: each on: html ];
  1509. onClick: [ self selectTab: each ] ] ]
  1510. !
  1511. tabList
  1512. tabList ifNil: [
  1513. tabList := HLTabListWidget new.
  1514. tabList
  1515. callback: [ :tab | self selectTab: tab. tabList focus ];
  1516. selectedItem: self selectedTab;
  1517. items: self tabs ].
  1518. ^ tabList
  1519. ! !
  1520. HLWidget subclass: #HLProgressBarWidget
  1521. instanceVariableNames: 'label parent workBlock collection bar'
  1522. package: 'Helios-Core'!
  1523. !HLProgressBarWidget commentStamp!
  1524. I am a widget used to display a progress bar while iterating over a collection.!
  1525. !HLProgressBarWidget methodsFor: 'accessing'!
  1526. collection
  1527. ^ collection
  1528. !
  1529. collection: aCollection
  1530. collection := aCollection
  1531. !
  1532. label
  1533. ^ label
  1534. !
  1535. label: aString
  1536. label := aString
  1537. !
  1538. parent
  1539. ^ parent
  1540. !
  1541. parent: aProgress
  1542. parent := aProgress
  1543. !
  1544. workBlock
  1545. ^ workBlock
  1546. !
  1547. workBlock: aBlock
  1548. workBlock := aBlock
  1549. ! !
  1550. !HLProgressBarWidget methodsFor: 'actions'!
  1551. evaluateAt: anInteger
  1552. self updateProgress: (anInteger / self collection size) * 100.
  1553. anInteger <= self collection size
  1554. ifTrue: [
  1555. [
  1556. self workBlock value: (self collection at: anInteger).
  1557. self evaluateAt: anInteger + 1 ] fork ]
  1558. ifFalse: [ [ self remove ] valueWithTimeout: 500 ]
  1559. !
  1560. remove
  1561. self parent removeProgressBar: self
  1562. !
  1563. start
  1564. "Make sure the UI has some time to update itself between each iteration"
  1565. self evaluateAt: 1
  1566. !
  1567. updateProgress: anInteger
  1568. bar asJQuery css: 'width' put: anInteger asString, '%'
  1569. ! !
  1570. !HLProgressBarWidget methodsFor: 'rendering'!
  1571. renderContentOn: html
  1572. html span with: self label.
  1573. console log: 'progress bar: '; log: self label.
  1574. html div
  1575. class: 'progress';
  1576. with: [
  1577. bar := html div
  1578. class: 'progress-bar';
  1579. style: 'width: 0%' ]
  1580. ! !
  1581. HLProgressBarWidget class instanceVariableNames: 'default'!
  1582. !HLProgressBarWidget class methodsFor: 'accessing'!
  1583. default
  1584. ^ default ifNil: [ default := self new ]
  1585. ! !
  1586. HLWidget subclass: #HLSpotlightWidget
  1587. instanceVariableNames: 'input'
  1588. package: 'Helios-Core'!
  1589. !HLSpotlightWidget methodsFor: 'accessing'!
  1590. ghostText
  1591. ^ 'Search... (Ctrl+F)'
  1592. !
  1593. inputCompletion
  1594. ^ self manager environment availableClassNames, self manager environment allSelectors
  1595. ! !
  1596. !HLSpotlightWidget methodsFor: 'actions'!
  1597. findMatches: aQueryString andRender: aRenderCallback
  1598. | matches |
  1599. matches := self inputCompletion select: [ :each | each match: aQueryString ].
  1600. aRenderCallback value: matches
  1601. !
  1602. search: aString
  1603. "open a new Browser pointing to aString"
  1604. aString ifNotEmpty: [
  1605. Finder findString: aString ]
  1606. ! !
  1607. !HLSpotlightWidget methodsFor: 'rendering'!
  1608. renderContentOn: html
  1609. input := html input
  1610. class: 'spotlight typeahead';
  1611. placeholder: self ghostText;
  1612. onKeyDown: [ :event |
  1613. event which = 13 ifTrue: [
  1614. self search: input asJQuery val ] ]
  1615. yourself.
  1616. input asJQuery
  1617. typeahead: #{ 'hint' -> true }
  1618. value: #{ 'name' -> 'classesAndSelectors'.
  1619. 'displayKey' -> [ :suggestion | suggestion asString ].
  1620. 'source' -> [ :query :callback | self findMatches: query andRender: callback ]}.
  1621. "use additional datasets for grouping into classes and selectors"
  1622. ! !
  1623. HLWidget subclass: #HLTabWidget
  1624. instanceVariableNames: 'widget label root'
  1625. package: 'Helios-Core'!
  1626. !HLTabWidget commentStamp!
  1627. I am a widget specialized into building another widget as an Helios tab.
  1628. I should not be used directly, `HLWidget class >> #openAsTab` should be used instead.
  1629. ## Example
  1630. HLWorkspace openAsTab!
  1631. !HLTabWidget methodsFor: 'accessing'!
  1632. activate
  1633. self manager activate: self
  1634. !
  1635. cssClass
  1636. ^ self widget tabClass
  1637. !
  1638. focus
  1639. self widget canHaveFocus ifTrue: [
  1640. self widget focus ]
  1641. !
  1642. label
  1643. ^ label ifNil: [ '' ]
  1644. !
  1645. label: aString
  1646. label := aString
  1647. !
  1648. manager
  1649. ^ HLManager current
  1650. !
  1651. widget
  1652. ^ widget
  1653. !
  1654. widget: aWidget
  1655. widget := aWidget
  1656. ! !
  1657. !HLTabWidget methodsFor: 'actions'!
  1658. add
  1659. self manager addTab: self.
  1660. self observeManager
  1661. !
  1662. hide
  1663. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  1664. !
  1665. observeManager
  1666. self manager announcer
  1667. on: HLTabLabelChanged
  1668. send: #onTabLabelChanged:
  1669. to: self
  1670. !
  1671. registerBindings
  1672. self widget registerBindings
  1673. !
  1674. remove
  1675. self unregister.
  1676. self widget unregister.
  1677. root ifNotNil: [ root asJQuery remove ]
  1678. !
  1679. show
  1680. root
  1681. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  1682. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  1683. !
  1684. unregister
  1685. self manager announcer unsubscribe: self
  1686. ! !
  1687. !HLTabWidget methodsFor: 'reactions'!
  1688. onTabLabelChanged: anAnnouncement
  1689. anAnnouncement widget = self widget ifTrue: [
  1690. self label = anAnnouncement label ifFalse: [
  1691. self label: anAnnouncement label.
  1692. self manager refresh ] ]
  1693. ! !
  1694. !HLTabWidget methodsFor: 'rendering'!
  1695. renderOn: html
  1696. root := html div
  1697. class: 'tab';
  1698. yourself.
  1699. self renderTab
  1700. !
  1701. renderTab
  1702. root contents: [ :html |
  1703. html div
  1704. class: 'amber_box';
  1705. with: [ self widget renderOn: html ] ]
  1706. ! !
  1707. !HLTabWidget methodsFor: 'testing'!
  1708. isActive
  1709. ^ self manager activeTab = self
  1710. ! !
  1711. !HLTabWidget class methodsFor: 'instance creation'!
  1712. on: aWidget labelled: aString
  1713. ^ self new
  1714. widget: aWidget;
  1715. label: aString;
  1716. yourself
  1717. ! !
  1718. HLWidget subclass: #HLTabsWidget
  1719. instanceVariableNames: 'tabs activeTab history selectionDisabled spotlight'
  1720. package: 'Helios-Core'!
  1721. !HLTabsWidget methodsFor: 'accessing'!
  1722. activeTab
  1723. ^ activeTab
  1724. !
  1725. history
  1726. ^ history ifNil: [ history := OrderedCollection new ]
  1727. !
  1728. history: aCollection
  1729. history := aCollection
  1730. !
  1731. spotlight
  1732. ^ spotlight ifNil: [ spotlight := HLSpotlightWidget new ]
  1733. !
  1734. tabWidth
  1735. ^ (window asJQuery width - 250) / self tabs size
  1736. !
  1737. tabs
  1738. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  1739. ! !
  1740. !HLTabsWidget methodsFor: 'actions'!
  1741. activate: aTab
  1742. self isSelectionDisabled ifTrue: [ ^ self ].
  1743. self manager keyBinder flushBindings.
  1744. aTab registerBindings.
  1745. activeTab := aTab.
  1746. self
  1747. refresh;
  1748. addToHistory: aTab;
  1749. show: aTab
  1750. !
  1751. activateNextTab
  1752. | nextTab |
  1753. self tabs ifEmpty: [ ^ self ].
  1754. nextTab := self tabs
  1755. at: (self tabs indexOf: self activeTab) + 1
  1756. ifAbsent: [ self tabs first ].
  1757. self activate: nextTab
  1758. !
  1759. activatePreviousTab
  1760. | previousTab |
  1761. self tabs ifEmpty: [ ^ self ].
  1762. previousTab := self tabs
  1763. at: (self tabs indexOf: self activeTab) - 1
  1764. ifAbsent: [ self tabs last ].
  1765. self activate: previousTab
  1766. !
  1767. addTab: aTab
  1768. self tabs add: aTab.
  1769. self activate: aTab
  1770. !
  1771. addToHistory: aTab
  1772. self removeFromHistory: aTab.
  1773. self history add: aTab
  1774. !
  1775. disableSelection
  1776. selectionDisabled := true
  1777. !
  1778. enableSelection
  1779. selectionDisabled := false
  1780. !
  1781. removeActiveTab
  1782. self removeTab: self activeTab
  1783. !
  1784. removeFromHistory: aTab
  1785. self history: (self history reject: [ :each | each == aTab ])
  1786. !
  1787. removeTab: aTab
  1788. (self tabs includes: aTab) ifFalse: [ ^ self ].
  1789. self removeFromHistory: aTab.
  1790. self tabs remove: aTab.
  1791. self manager keyBinder flushBindings.
  1792. aTab remove.
  1793. self refresh.
  1794. self history ifNotEmpty: [
  1795. self history last activate ]
  1796. !
  1797. removeTabForWidget: aWidget
  1798. self removeTab: (self tabs
  1799. detect: [ :each | each widget = aWidget ]
  1800. ifNone: [ ^ self ])
  1801. !
  1802. updateTabsOrder
  1803. tabs := '.nav-tabs li' asJQuery toArray
  1804. collect: [ :each | each at: 'tab-data' ]
  1805. ! !
  1806. !HLTabsWidget methodsFor: 'private'!
  1807. setupEvents
  1808. 'body' asJQuery keydown: [ :event |
  1809. "ctrl+> and ctrl+<"
  1810. (event ctrlKey and: [ event which = 188 ]) ifTrue: [
  1811. self activatePreviousTab.
  1812. event preventDefault ].
  1813. (event ctrlKey and: [ event which = 190 ]) ifTrue: [
  1814. self activateNextTab.
  1815. event preventDefault ] ]
  1816. ! !
  1817. !HLTabsWidget methodsFor: 'rendering'!
  1818. renderAddOn: html
  1819. html div
  1820. class: 'dropdown new_tab';
  1821. with: [
  1822. html a
  1823. class: 'dropdown-toggle';
  1824. at: 'data-toggle' put: 'dropdown';
  1825. with: [
  1826. (html tag: 'b') class: 'caret' ].
  1827. html ul
  1828. class: 'dropdown-menu';
  1829. with: [
  1830. ((HLWidget withAllSubclasses
  1831. select: [ :each | each canBeOpenAsTab ])
  1832. sorted: [ :a :b | a tabPriority < b tabPriority ])
  1833. do: [ :each |
  1834. html li with: [
  1835. html a
  1836. with: each tabLabel;
  1837. onClick: [ each openAsTab ] ] ] ] ]
  1838. !
  1839. renderContentOn: html
  1840. html div
  1841. class: 'navbar navbar-fixed-top';
  1842. with: [ html div
  1843. class: 'navbar-header';
  1844. at: 'role' put: 'tabpanel';
  1845. with: [ self renderTabsOn: html ] ].
  1846. html with: self spotlight.
  1847. self renderAddOn: html
  1848. !
  1849. renderTab: aTab on: html
  1850. | li |
  1851. li := html li
  1852. style: 'width: ', self tabWidth asString, 'px';
  1853. class: (aTab isActive ifTrue: [ 'tab active' ] ifFalse: [ 'tab inactive' ]);
  1854. with: [
  1855. html a
  1856. with: [
  1857. ((html tag: 'i') class: 'close')
  1858. onClick: [ self removeTab: aTab ].
  1859. html span
  1860. class: aTab cssClass;
  1861. title: aTab label;
  1862. with: aTab label ];
  1863. at: 'role' put: 'tab'];
  1864. onClick: [ aTab activate ].
  1865. li asDomNode at: 'tab-data' put: aTab
  1866. !
  1867. renderTabsOn: html
  1868. | ul |
  1869. ul := html ul
  1870. class: 'nav navbar-nav nav-tabs';
  1871. at: 'role' put: 'tablist';
  1872. with: [
  1873. self tabs do: [ :each |
  1874. self renderTab: each on: html ] ].
  1875. ul asJQuery sortable: #{
  1876. 'containment' -> 'parent'.
  1877. 'start' -> [ self disableSelection ].
  1878. 'stop' -> [ [ self enableSelection] valueWithTimeout: 300 ].
  1879. 'update' -> [ self updateTabsOrder ]
  1880. }
  1881. !
  1882. show: aTab
  1883. self tabs do: [ :each | each hide ].
  1884. aTab show; focus
  1885. ! !
  1886. !HLTabsWidget methodsFor: 'testing'!
  1887. isSelectionDisabled
  1888. ^ selectionDisabled ifNil: [ false ]
  1889. ! !
  1890. HLTabsWidget class instanceVariableNames: 'current'!
  1891. HLWidget subclass: #HLWelcomeWidget
  1892. instanceVariableNames: ''
  1893. package: 'Helios-Core'!
  1894. !HLWelcomeWidget methodsFor: 'accessing'!
  1895. cssClass
  1896. ^ 'welcome'
  1897. ! !
  1898. !HLWelcomeWidget methodsFor: 'actions'!
  1899. openClassBrowser
  1900. HLBrowser openAsTab
  1901. !
  1902. openHelp
  1903. !
  1904. openTestRunner
  1905. HLSUnit openAsTab
  1906. !
  1907. openWorkspace
  1908. HLWorkspace openAsTab
  1909. ! !
  1910. !HLWelcomeWidget methodsFor: 'rendering'!
  1911. renderButtonsOn: html
  1912. html button
  1913. class: 'button';
  1914. with: 'Class Browser';
  1915. onClick: [ self openClassBrowser ].
  1916. html button
  1917. class: 'button';
  1918. with: 'Workspace';
  1919. onClick: [ self openWorkspace ].
  1920. html button
  1921. class: 'button';
  1922. with: 'Test Runner';
  1923. onClick: [ self openTestRunner ].
  1924. "html button
  1925. class: 'button';
  1926. with: 'Help';
  1927. onClick: [ self openHelp ]"
  1928. !
  1929. renderContentOn: html
  1930. self
  1931. renderHelpOn: html;
  1932. renderButtonsOn: html
  1933. !
  1934. renderHelpOn: html
  1935. html h2 with: 'No tools are open'.
  1936. html ul with: [
  1937. html li with: 'Perform actions with ctrl + space'.
  1938. html li with: 'Open one of the common tools:' ]
  1939. ! !