Helios-Core.st 47 KB

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