Web.st 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. Smalltalk createPackage: 'Web'!
  2. (Smalltalk packageAt: 'Web' ifAbsent: [ self error: 'Package not created: Web' ]) imports: {'amber/core/Platform-DOM'. 'amber/web/Web-JQuery'}!
  3. Object subclass: #HTMLCanvas
  4. slots: {#root}
  5. package: 'Web'!
  6. !HTMLCanvas commentStamp!
  7. I am a canvas for building HTML.
  8. I provide the `#tag:` method to create a `TagBrush` (wrapping a DOM element) and convenience methods in the `tags` protocol.
  9. ## API
  10. My instances are used as the argument of the `#renderOn:` method of `Widget` objects.
  11. The `#with:` method is used to compose HTML, nesting tags. `#with:` can take a `TagBrush`, a `String`, a `BlockClosure` or a `Widget` as argument.
  12. ## Usage example:
  13. aCanvas a
  14. with: [ aCanvas span with: 'click me' ];
  15. onClick: [ window alert: 'clicked!!' ]!
  16. !HTMLCanvas methodsFor: 'accessing'!
  17. root
  18. ^ root ifNil: [ root := TagBrush fromString: 'div' canvas: self ]
  19. !
  20. root: aTagBrush
  21. self deprecatedAPI.
  22. root := aTagBrush
  23. ! !
  24. !HTMLCanvas methodsFor: 'adding'!
  25. entity: aString
  26. "Adds a character representing html entity, eg.
  27. html entity: 'copy'
  28. adds a copyright sign.
  29. If a name does not represent valid HTML entity, error is raised."
  30. | result |
  31. result := (TagBrush fromString: 'span') asDomNode innerHTML: '&', aString, ';'; textContent.
  32. result size = 1 ifFalse: [ self error: 'Not an HTML entity: ', aString ].
  33. self with: result
  34. !
  35. root: aTagBrush do: aBlock
  36. | old |
  37. old := root.
  38. root := aTagBrush.
  39. aBlock value: self.
  40. root := old
  41. !
  42. with: anObject
  43. ^ self root with: anObject
  44. ! !
  45. !HTMLCanvas methodsFor: 'tags'!
  46. a
  47. ^ self tag: 'a'
  48. !
  49. abbr
  50. ^ self tag: 'abbr'
  51. !
  52. address
  53. ^ self tag: 'address'
  54. !
  55. area
  56. ^ self tag: 'area'
  57. !
  58. article
  59. ^ self tag: 'article'
  60. !
  61. aside
  62. ^ self tag: 'aside'
  63. !
  64. audio
  65. ^ self tag: 'audio'
  66. !
  67. base
  68. ^ self tag: 'base'
  69. !
  70. blockquote
  71. ^ self tag: 'blockquote'
  72. !
  73. body
  74. ^ self tag: 'body'
  75. !
  76. br
  77. ^ self tag: 'br'
  78. !
  79. button
  80. ^ self tag: 'button'
  81. !
  82. canvas
  83. ^ self tag: 'canvas'
  84. !
  85. caption
  86. ^ self tag: 'caption'
  87. !
  88. cite
  89. ^ self tag: 'cite'
  90. !
  91. code
  92. ^ self tag: 'code'
  93. !
  94. col
  95. ^ self tag: 'col'
  96. !
  97. colgroup
  98. ^ self tag: 'colgroup'
  99. !
  100. command
  101. ^ self tag: 'command'
  102. !
  103. datalist
  104. ^ self tag: 'datalist'
  105. !
  106. dd
  107. ^ self tag: 'dd'
  108. !
  109. del
  110. ^ self tag: 'del'
  111. !
  112. details
  113. ^ self tag: 'details'
  114. !
  115. div
  116. ^ self tag: 'div'
  117. !
  118. div: aBlock
  119. ^ self div with: aBlock
  120. !
  121. dl
  122. ^ self tag: 'dl'
  123. !
  124. dt
  125. ^ self tag: 'dt'
  126. !
  127. em
  128. ^ self tag: 'em'
  129. !
  130. embed
  131. ^ self tag: 'embed'
  132. !
  133. fieldset
  134. ^ self tag: 'fieldset'
  135. !
  136. figcaption
  137. ^ self tag: 'figcaption'
  138. !
  139. figure
  140. ^ self tag: 'figure'
  141. !
  142. footer
  143. ^ self tag: 'footer'
  144. !
  145. form
  146. ^ self tag: 'form'
  147. !
  148. h1
  149. ^ self tag: 'h1'
  150. !
  151. h1: anObject
  152. ^ self h1 with: anObject
  153. !
  154. h2
  155. ^ self tag: 'h2'
  156. !
  157. h2: anObject
  158. ^ self h2 with: anObject
  159. !
  160. h3
  161. ^ self tag: 'h3'
  162. !
  163. h3: anObject
  164. ^ self h3 with: anObject
  165. !
  166. h4
  167. ^ self tag: 'h4'
  168. !
  169. h4: anObject
  170. ^ self h4 with: anObject
  171. !
  172. h5
  173. ^ self tag: 'h5'
  174. !
  175. h5: anObject
  176. ^ self h5 with: anObject
  177. !
  178. h6
  179. ^ self tag: 'h6'
  180. !
  181. h6: anObject
  182. ^ self h6 with: anObject
  183. !
  184. head
  185. ^ self tag: 'head'
  186. !
  187. header
  188. ^ self tag: 'header'
  189. !
  190. hgroup
  191. ^ self tag: 'hgroup'
  192. !
  193. hr
  194. ^ self tag: 'hr'
  195. !
  196. html
  197. ^ self tag: 'html'
  198. !
  199. iframe
  200. ^ self tag: 'iframe'
  201. !
  202. iframe: aString
  203. ^ self iframe src: aString
  204. !
  205. img
  206. ^ self tag: 'img'
  207. !
  208. img: aString
  209. ^ self img src: aString
  210. !
  211. input
  212. ^ self tag: 'input'
  213. !
  214. label
  215. ^ self tag: 'label'
  216. !
  217. legend
  218. ^ self tag: 'legend'
  219. !
  220. li
  221. ^ self tag: 'li'
  222. !
  223. li: anObject
  224. ^ self li with: anObject
  225. !
  226. link
  227. ^ self tag: 'link'
  228. !
  229. map
  230. ^ self tag: 'map'
  231. !
  232. mark
  233. ^ self tag: 'mark'
  234. !
  235. menu
  236. ^ self tag: 'menu'
  237. !
  238. meta
  239. ^ self tag: 'meta'
  240. !
  241. nav
  242. ^ self tag: 'nav'
  243. !
  244. newTag: aString
  245. ^ TagBrush fromString: aString canvas: self
  246. !
  247. noscript
  248. ^ self tag: 'noscript'
  249. !
  250. object
  251. ^ self tag: 'object'
  252. !
  253. ol
  254. ^ self tag: 'ol'
  255. !
  256. ol: anObject
  257. ^ self ol with: anObject
  258. !
  259. optgroup
  260. ^ self tag: 'optgroup'
  261. !
  262. option
  263. ^ self tag: 'option'
  264. !
  265. output
  266. ^ self tag: 'output'
  267. !
  268. p
  269. ^ self tag: 'p'
  270. !
  271. p: anObject
  272. ^ self p with: anObject
  273. !
  274. param
  275. ^ self tag: 'param'
  276. !
  277. pre
  278. ^ self tag: 'pre'
  279. !
  280. progress
  281. ^ self tag: 'progress'
  282. !
  283. script
  284. ^ self tag: 'script'
  285. !
  286. section
  287. ^ self tag: 'section'
  288. !
  289. select
  290. ^ self tag: 'select'
  291. !
  292. small
  293. ^ self tag: 'small'
  294. !
  295. source
  296. ^ self tag: 'source'
  297. !
  298. span
  299. ^ self tag: 'span'
  300. !
  301. span: anObject
  302. ^ self span with: anObject
  303. !
  304. strong
  305. ^ self tag: 'strong'
  306. !
  307. strong: anObject
  308. ^ self strong with: anObject
  309. !
  310. style
  311. ^ self tag: 'style'
  312. !
  313. style: aString
  314. ^ self style with: aString; yourself
  315. !
  316. sub
  317. ^ self tag: 'sub'
  318. !
  319. summary
  320. ^ self tag: 'summary'
  321. !
  322. sup
  323. ^ self tag: 'sup'
  324. !
  325. table
  326. ^ self tag: 'table'
  327. !
  328. tag: aString
  329. ^ self root addBrush: (self newTag: aString)
  330. !
  331. tbody
  332. ^ self tag: 'tbody'
  333. !
  334. td
  335. ^ self tag: 'td'
  336. !
  337. textarea
  338. ^ self tag: 'textarea'
  339. !
  340. tfoot
  341. ^ self tag: 'tfoot'
  342. !
  343. th
  344. ^ self tag: 'th'
  345. !
  346. thead
  347. ^ self tag: 'thead'
  348. !
  349. time
  350. ^ self tag: 'time'
  351. !
  352. title
  353. ^ self tag: 'title'
  354. !
  355. tr
  356. ^ self tag: 'tr'
  357. !
  358. ul
  359. ^ self tag: 'ul'
  360. !
  361. ul: anObject
  362. ^ self ul with: anObject
  363. !
  364. video
  365. ^ self tag: 'video'
  366. ! !
  367. Object subclass: #TagBrush
  368. slots: {#canvas. #element}
  369. package: 'Web'!
  370. !TagBrush commentStamp!
  371. I am a brush for building a single DOM element (which I hold onto).
  372. All tags but `<style>` are instances of me (see the `StyleBrush` class).
  373. ## API
  374. 1. Nesting
  375. Use `#with:` to nest tags. `#with:` can take aString, `TagBrush` instance, a `Widget` or block closure as parameter.
  376. Example: `aTag with: aString with: aCanvas div`
  377. 2. Events
  378. The `events` protocol contains all methods related to events (delegating event handling to jQuery).
  379. Example: `aTag onClick: [ window alert: 'clicked' ]`
  380. 3. Attributes
  381. The `attribute` protocol contains methods for attribute manipulation (delegating to jQuery too).
  382. Example: `aTag at: 'value' put: 'hello world'`
  383. 4. Raw access and jQuery
  384. The `#element` method can be used to access to JavaScript DOM element object.
  385. Example: `aTag element cssStyle`
  386. Use `#asJQuery` to access to the receiver converted into a jQuery object.
  387. Example: `aTag asJQuery css: 'color' value: 'red'`!
  388. !TagBrush methodsFor: 'accessing'!
  389. element
  390. ^ element
  391. ! !
  392. !TagBrush methodsFor: 'adding'!
  393. addBrush: aTagBrush
  394. self appendChild: aTagBrush asDomNode.
  395. ^ aTagBrush
  396. !
  397. append: anObject
  398. anObject appendToBrush: self
  399. !
  400. appendBlock: aBlock
  401. canvas root: self do: aBlock
  402. !
  403. appendChild: anElement
  404. element appendChild: anElement
  405. !
  406. appendString: aString
  407. self appendChild: aString asDomNode
  408. !
  409. appendToBrush: aTagBrush
  410. aTagBrush addBrush: self
  411. !
  412. contents: anObject
  413. self
  414. empty;
  415. append: anObject
  416. !
  417. empty
  418. <inlineJS: '
  419. var element = $self.element, child;
  420. while (child = element.firstChild) element.removeChild(child);
  421. '>
  422. !
  423. with: anObject
  424. self append: anObject
  425. ! !
  426. !TagBrush methodsFor: 'attributes'!
  427. accesskey: aString
  428. self at: 'accesskey' put: aString
  429. !
  430. action: aString
  431. self at: 'action' put: aString
  432. !
  433. align: aString
  434. self at: 'align' put: aString
  435. !
  436. alt: aString
  437. self at: 'alt' put: aString
  438. !
  439. at: aString
  440. ^ self at: aString ifAbsent: [ Collection new errorNotFound ]
  441. !
  442. at: aString ifAbsent: aBlock
  443. <inlineJS: 'return $self.element.hasAttribute(aString) ? $self.element.getAttribute(aString) : aBlock._value()'>
  444. !
  445. at: aString put: aValue
  446. <inlineJS: '$self.element.setAttribute(aString, aValue); return aValue'>
  447. !
  448. class: aString
  449. <inlineJS: '$self.element.className = aString'>
  450. !
  451. cols: aString
  452. self at: 'cols' put: aString
  453. !
  454. contenteditable: aString
  455. self at: 'contenteditable' put: aString
  456. !
  457. contextmenu: aString
  458. self at: 'contextmenu' put: aString
  459. !
  460. draggable: aString
  461. self at: 'draggable' put: aString
  462. !
  463. for: aString
  464. self at: 'for' put: aString
  465. !
  466. height: aString
  467. self at: 'height' put: aString
  468. !
  469. hidden
  470. self at: 'hidden' put: 'hidden'
  471. !
  472. href: aString
  473. self at: 'href' put: aString
  474. !
  475. id: aString
  476. self at: 'id' put: aString
  477. !
  478. media: aString
  479. self at: 'media' put: aString
  480. !
  481. method: aString
  482. self at: 'method' put: aString
  483. !
  484. name: aString
  485. self at: 'name' put: aString
  486. !
  487. placeholder: aString
  488. self at: 'placeholder' put: aString
  489. !
  490. rel: aString
  491. self at: 'rel' put: aString
  492. !
  493. removeAt: aString
  494. <inlineJS: '$self.element.removeAttribute(aString)'>
  495. !
  496. rows: aString
  497. self at: 'rows' put: aString
  498. !
  499. src: aString
  500. self at: 'src' put: aString
  501. !
  502. style: aString
  503. self at: 'style' put: aString
  504. !
  505. tabindex: aNumber
  506. self at: 'tabindex' put: aNumber
  507. !
  508. target: aString
  509. self at: 'target' put: aString
  510. !
  511. title: aString
  512. self at: 'title' put: aString
  513. !
  514. type: aString
  515. self at: 'type' put: aString
  516. !
  517. valign: aString
  518. self at: 'valign' put: aString
  519. !
  520. value: aString
  521. self at: 'value' put: aString
  522. !
  523. width: aString
  524. self at: 'width' put: aString
  525. ! !
  526. !TagBrush methodsFor: 'converting'!
  527. asDomNode
  528. ^ element
  529. ! !
  530. !TagBrush methodsFor: 'events'!
  531. onBlur: aBlock
  532. self onEvent: 'blur' do: aBlock
  533. !
  534. onChange: aBlock
  535. self onEvent: 'change' do: aBlock
  536. !
  537. onClick: aBlock
  538. self onEvent: 'click' do: aBlock
  539. !
  540. onDblClick: aBlock
  541. self onEvent: 'dblclick' do: aBlock
  542. !
  543. onEvent: aString do: aBlock
  544. self asJQuery bind: aString do: aBlock
  545. !
  546. onFocus: aBlock
  547. self onEvent: 'focus' do: aBlock
  548. !
  549. onFocusIn: aBlock
  550. self onEvent: 'focusin' do: aBlock
  551. !
  552. onFocusOut: aBlock
  553. self onEvent: 'focusout' do: aBlock
  554. !
  555. onHover: aBlock
  556. self onEvent: 'hover' do: aBlock
  557. !
  558. onKeyDown: aBlock
  559. self onEvent: 'keydown' do: aBlock
  560. !
  561. onKeyPress: aBlock
  562. self onEvent: 'keypress' do: aBlock
  563. !
  564. onKeyUp: aBlock
  565. self onEvent: 'keyup' do: aBlock
  566. !
  567. onMouseDown: aBlock
  568. self onEvent: 'mousedown' do: aBlock
  569. !
  570. onMouseEnter: aBlock
  571. self onEvent: 'mouseenter' do: aBlock
  572. !
  573. onMouseLeave: aBlock
  574. self onEvent: 'mouseleave' do: aBlock
  575. !
  576. onMouseMove: aBlock
  577. self onEvent: 'mousemove' do: aBlock
  578. !
  579. onMouseOut: aBlock
  580. self onEvent: 'mouseout' do: aBlock
  581. !
  582. onMouseOver: aBlock
  583. self onEvent: 'mouseover' do: aBlock
  584. !
  585. onMouseUp: aBlock
  586. self onEvent: 'mouseup' do: aBlock
  587. !
  588. onSelect: aBlock
  589. self onEvent: 'select' do: aBlock
  590. !
  591. onSubmit: aBlock
  592. self onEvent: 'submit' do: aBlock
  593. !
  594. onUnload: aBlock
  595. self onEvent: 'unload' do: aBlock
  596. ! !
  597. !TagBrush methodsFor: 'initialization'!
  598. initializeFromCssSelector: aString canvas: aCanvas
  599. element := document querySelector: aString.
  600. canvas := aCanvas
  601. !
  602. initializeFromString: aString canvas: aCanvas
  603. element := document createElement: aString.
  604. canvas := aCanvas
  605. ! !
  606. !TagBrush class methodsFor: 'instance creation'!
  607. fromCssSelector: aString
  608. ^ self fromCssSelector: aString canvas: HTMLCanvas new
  609. !
  610. fromCssSelector: aString canvas: aCanvas
  611. ^ self new
  612. initializeFromCssSelector: aString canvas: aCanvas;
  613. yourself
  614. !
  615. fromString: aString
  616. ^ self fromString: aString canvas: HTMLCanvas new
  617. !
  618. fromString: aString canvas: aCanvas
  619. ^ self new
  620. initializeFromString: aString canvas: aCanvas;
  621. yourself
  622. ! !
  623. Object subclass: #Widget
  624. slots: {}
  625. package: 'Web'!
  626. !Widget commentStamp!
  627. I am a presenter building HTML. Subclasses are typically reusable components.
  628. ## API
  629. Use `#renderContentOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).
  630. To add a widget to the page, the convenience method `#appendToJQuery:` is very useful.
  631. Exemple:
  632. Counter new appendToJQuery: 'body' asJQuery!
  633. !Widget methodsFor: 'adding'!
  634. appendToBrush: aTagBrush
  635. [ :html | self renderOn: html ] appendToBrush: aTagBrush
  636. ! !
  637. !Widget methodsFor: 'rendering'!
  638. renderOn: html
  639. self
  640. ! !
  641. !Widget class methodsFor: 'accessing'!
  642. classTag
  643. "Returns a tag or general category for this class.
  644. Typically used to help tools do some reflection.
  645. Helios, for example, uses this to decide what icon the class should display."
  646. ^ 'widget'
  647. ! !
  648. !Association methodsFor: '*Web'!
  649. appendToBrush: aTagBrush
  650. aTagBrush at: self key put: self value
  651. ! !
  652. !BlockClosure methodsFor: '*Web'!
  653. appendToBrush: aTagBrush
  654. aTagBrush appendBlock: self
  655. ! !
  656. !Collection methodsFor: '*Web'!
  657. appendToBrush: aTagBrush
  658. self do: [ :each | aTagBrush append: each ]
  659. ! !
  660. !JSObjectProxy methodsFor: '*Web'!
  661. appendToBrush: aTagBrush
  662. (PlatformDom isDomNode: jsObject)
  663. ifTrue: [ aTagBrush appendChild: jsObject ]
  664. ifFalse: [ aTagBrush append: self asString ]
  665. ! !
  666. !Object methodsFor: '*Web'!
  667. appendToBrush: aTagBrush
  668. aTagBrush append: self asString
  669. ! !
  670. !String methodsFor: '*Web'!
  671. appendToBrush: aTagBrush
  672. aTagBrush appendString: self
  673. !
  674. asBrush
  675. ^ TagBrush fromCssSelector: self
  676. ! !