Web.st 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  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. ## API
  373. 1. Nesting
  374. Use `#with:` to nest tags. `#with:` can take aString, `TagBrush` instance, a `Widget` or block closure as parameter.
  375. Example: `aTag with: aString with: aCanvas div`
  376. 2. Events
  377. The `events` protocol contains all methods related to events.
  378. Example: `aTag onClick: [ window alert: 'clicked' ]`
  379. 3. Attributes
  380. The `attribute` protocol contains methods for attribute manipulation.
  381. Example: `aTag at: 'value' put: 'hello world'`
  382. 4. Raw access and jQuery
  383. The `#asDomNode` method can be used to access to JavaScript DOM element object.
  384. Example: `aTag asDomNode cssStyle`
  385. With 'Web-JQuery' package there is `#asJQuery` to access to the receiver converted into a jQuery object.
  386. Example: `aTag asJQuery css: 'color' value: 'red'`!
  387. !TagBrush methodsFor: 'accessing'!
  388. element
  389. ^ element
  390. ! !
  391. !TagBrush methodsFor: 'adding'!
  392. addBrush: aTagBrush
  393. self appendChild: aTagBrush asDomNode.
  394. ^ aTagBrush
  395. !
  396. append: anObject
  397. anObject appendToBrush: self
  398. !
  399. appendBlock: aBlock
  400. canvas root: self do: aBlock
  401. !
  402. appendChild: anElement
  403. element appendChild: anElement
  404. !
  405. appendString: aString
  406. self appendChild: aString asDomNode
  407. !
  408. appendToBrush: aTagBrush
  409. aTagBrush addBrush: self
  410. !
  411. contents: anObject
  412. self
  413. empty;
  414. append: anObject
  415. !
  416. empty
  417. <inlineJS: '
  418. var element = $self.element, child;
  419. while (child = element.firstChild) element.removeChild(child);
  420. '>
  421. !
  422. with: anObject
  423. self append: anObject
  424. ! !
  425. !TagBrush methodsFor: 'attributes'!
  426. accesskey: aString
  427. self at: 'accesskey' put: aString
  428. !
  429. action: aString
  430. self at: 'action' put: aString
  431. !
  432. align: aString
  433. self at: 'align' put: aString
  434. !
  435. alt: aString
  436. self at: 'alt' put: aString
  437. !
  438. at: aString
  439. ^ self at: aString ifAbsent: [ Collection new errorNotFound ]
  440. !
  441. at: aString ifAbsent: aBlock
  442. <inlineJS: 'return $self.element.hasAttribute(aString) ? $self.element.getAttribute(aString) : aBlock._value()'>
  443. !
  444. at: aString put: aValue
  445. <inlineJS: '$self.element.setAttribute(aString, aValue); return aValue'>
  446. !
  447. class: aString
  448. <inlineJS: '$self.element.className = aString'>
  449. !
  450. cols: aString
  451. self at: 'cols' put: aString
  452. !
  453. contenteditable: aString
  454. self at: 'contenteditable' put: aString
  455. !
  456. contextmenu: aString
  457. self at: 'contextmenu' put: aString
  458. !
  459. draggable: aString
  460. self at: 'draggable' put: aString
  461. !
  462. for: aString
  463. self at: 'for' put: aString
  464. !
  465. height: aString
  466. self at: 'height' put: aString
  467. !
  468. hidden
  469. self at: 'hidden' put: 'hidden'
  470. !
  471. href: aString
  472. self at: 'href' put: aString
  473. !
  474. id: aString
  475. self at: 'id' put: aString
  476. !
  477. media: aString
  478. self at: 'media' put: aString
  479. !
  480. method: aString
  481. self at: 'method' put: aString
  482. !
  483. name: aString
  484. self at: 'name' put: aString
  485. !
  486. placeholder: aString
  487. self at: 'placeholder' put: aString
  488. !
  489. rel: aString
  490. self at: 'rel' put: aString
  491. !
  492. removeAt: aString
  493. <inlineJS: '$self.element.removeAttribute(aString)'>
  494. !
  495. rows: aString
  496. self at: 'rows' put: aString
  497. !
  498. src: aString
  499. self at: 'src' put: aString
  500. !
  501. style: aString
  502. self at: 'style' put: aString
  503. !
  504. tabindex: aNumber
  505. self at: 'tabindex' put: aNumber
  506. !
  507. target: aString
  508. self at: 'target' put: aString
  509. !
  510. title: aString
  511. self at: 'title' put: aString
  512. !
  513. type: aString
  514. self at: 'type' put: aString
  515. !
  516. valign: aString
  517. self at: 'valign' put: aString
  518. !
  519. value: aString
  520. self at: 'value' put: aString
  521. !
  522. width: aString
  523. self at: 'width' put: aString
  524. ! !
  525. !TagBrush methodsFor: 'converting'!
  526. asDomNode
  527. ^ element
  528. ! !
  529. !TagBrush methodsFor: 'events'!
  530. onBlur: aBlock
  531. self onEvent: 'blur' do: aBlock
  532. !
  533. onChange: aBlock
  534. self onEvent: 'change' do: aBlock
  535. !
  536. onClick: aBlock
  537. self onEvent: 'click' do: aBlock
  538. !
  539. onDblClick: aBlock
  540. self onEvent: 'dblclick' do: aBlock
  541. !
  542. onEvent: aString do: aBlock
  543. self asDomNode addEventListener: aString block: aBlock useCapture: false
  544. !
  545. onFocus: aBlock
  546. self onEvent: 'focus' do: aBlock
  547. !
  548. onFocusIn: aBlock
  549. self onEvent: 'focusin' do: aBlock
  550. !
  551. onFocusOut: aBlock
  552. self onEvent: 'focusout' do: aBlock
  553. !
  554. onKeyDown: aBlock
  555. self onEvent: 'keydown' do: aBlock
  556. !
  557. onKeyPress: aBlock
  558. self onEvent: 'keypress' do: aBlock
  559. !
  560. onKeyUp: aBlock
  561. self onEvent: 'keyup' do: aBlock
  562. !
  563. onMouseDown: aBlock
  564. self onEvent: 'mousedown' do: aBlock
  565. !
  566. onMouseEnter: aBlock
  567. self onEvent: 'mouseenter' do: aBlock
  568. !
  569. onMouseLeave: aBlock
  570. self onEvent: 'mouseleave' do: aBlock
  571. !
  572. onMouseMove: aBlock
  573. self onEvent: 'mousemove' do: aBlock
  574. !
  575. onMouseOut: aBlock
  576. self onEvent: 'mouseout' do: aBlock
  577. !
  578. onMouseOver: aBlock
  579. self onEvent: 'mouseover' do: aBlock
  580. !
  581. onMouseUp: aBlock
  582. self onEvent: 'mouseup' do: aBlock
  583. !
  584. onSelect: aBlock
  585. self onEvent: 'select' do: aBlock
  586. !
  587. onSubmit: aBlock
  588. self onEvent: 'submit' do: aBlock
  589. !
  590. onUnload: aBlock
  591. self onEvent: 'unload' do: aBlock
  592. ! !
  593. !TagBrush methodsFor: 'initialization'!
  594. initializeFromCssSelector: aString canvas: aCanvas
  595. element := document querySelector: aString.
  596. canvas := aCanvas
  597. !
  598. initializeFromString: aString canvas: aCanvas
  599. element := document createElement: aString.
  600. canvas := aCanvas
  601. ! !
  602. !TagBrush class methodsFor: 'instance creation'!
  603. fromCssSelector: aString
  604. ^ self fromCssSelector: aString canvas: HTMLCanvas new
  605. !
  606. fromCssSelector: aString canvas: aCanvas
  607. ^ self new
  608. initializeFromCssSelector: aString canvas: aCanvas;
  609. yourself
  610. !
  611. fromString: aString
  612. ^ self fromString: aString canvas: HTMLCanvas new
  613. !
  614. fromString: aString canvas: aCanvas
  615. ^ self new
  616. initializeFromString: aString canvas: aCanvas;
  617. yourself
  618. ! !
  619. Object subclass: #Widget
  620. slots: {}
  621. package: 'Web'!
  622. !Widget commentStamp!
  623. I am a presenter building HTML. Subclasses are typically reusable components.
  624. ## API
  625. Use `#renderOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).
  626. To add a widget to the page, the convenience method `#appendToBrush:` is very useful.
  627. Exemple:
  628. Counter new appendToBrush: 'body' asBrush!
  629. !Widget methodsFor: 'adding'!
  630. appendToBrush: aTagBrush
  631. [ :html | self renderOn: html ] appendToBrush: aTagBrush
  632. ! !
  633. !Widget methodsFor: 'rendering'!
  634. renderOn: html
  635. self
  636. ! !
  637. !Widget class methodsFor: 'accessing'!
  638. classTag
  639. "Returns a tag or general category for this class.
  640. Typically used to help tools do some reflection.
  641. Helios, for example, uses this to decide what icon the class should display."
  642. ^ 'widget'
  643. ! !
  644. !Association methodsFor: '*Web'!
  645. appendToBrush: aTagBrush
  646. aTagBrush at: self key put: self value
  647. ! !
  648. !BlockClosure methodsFor: '*Web'!
  649. appendToBrush: aTagBrush
  650. aTagBrush appendBlock: self
  651. ! !
  652. !Collection methodsFor: '*Web'!
  653. appendToBrush: aTagBrush
  654. self do: [ :each | aTagBrush append: each ]
  655. ! !
  656. !JSObjectProxy methodsFor: '*Web'!
  657. appendToBrush: aTagBrush
  658. (PlatformDom isDomNode: jsObject)
  659. ifTrue: [ aTagBrush appendChild: jsObject ]
  660. ifFalse: [ aTagBrush append: self asString ]
  661. ! !
  662. !Object methodsFor: '*Web'!
  663. appendToBrush: aTagBrush
  664. aTagBrush append: self asString
  665. ! !
  666. !String methodsFor: '*Web'!
  667. appendToBrush: aTagBrush
  668. aTagBrush appendString: self
  669. !
  670. asBrush
  671. ^ TagBrush fromCssSelector: self
  672. ! !