Web.st 13 KB

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