Helios-Core.st 45 KB

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