Web.st 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. Smalltalk createPackage: 'Web'!
  2. (Smalltalk packageAt: 'Web' ifAbsent: [ self error: 'Package not created: Web' ]) imports: {'amber/core/Platform-DOM'. 'amber/jquery/Wrappers-JQuery'}!
  3. Object subclass: #HTMLCanvas
  4. instanceVariableNames: '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
  19. !
  20. root: aTagBrush
  21. root := aTagBrush
  22. ! !
  23. !HTMLCanvas methodsFor: 'adding'!
  24. entity: aString
  25. "Adds a character representing html entity, eg.
  26. html entity: 'copy'
  27. adds a copyright sign.
  28. If a name does not represent valid HTML entity, error is raised."
  29. | result |
  30. result := ('<span />' asJQuery html: '&', aString, ';') text.
  31. result size = 1 ifFalse: [ self error: 'Not an HTML entity: ', aString ].
  32. self with: result
  33. !
  34. with: anObject
  35. ^ self root with: anObject
  36. ! !
  37. !HTMLCanvas methodsFor: 'initialization'!
  38. initialize
  39. super initialize.
  40. root ifNil: [ root := TagBrush fromString: 'div' canvas: self ]
  41. !
  42. initializeFromJQuery: aJQuery
  43. root := TagBrush fromJQuery: aJQuery canvas: self
  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. ^ 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. !HTMLCanvas class methodsFor: 'instance creation'!
  368. onJQuery: aJQuery
  369. ^ self basicNew
  370. initializeFromJQuery: aJQuery;
  371. initialize;
  372. yourself
  373. ! !
  374. Object subclass: #TagBrush
  375. instanceVariableNames: 'canvas element'
  376. package: 'Web'!
  377. !TagBrush commentStamp!
  378. I am a brush for building a single DOM element (which I hold onto).
  379. All tags but `<style>` are instances of me (see the `StyleBrush` class).
  380. ## API
  381. 1. Nesting
  382. Use `#with:` to nest tags. `#with:` can take aString, `TagBrush` instance, a `Widget` or block closure as parameter.
  383. Example: `aTag with: aString with: aCanvas div`
  384. 2. Events
  385. The `events` protocol contains all methods related to events (delegating event handling to jQuery).
  386. Example: `aTag onClick: [ window alert: 'clicked' ]`
  387. 3. Attributes
  388. The `attribute` protocol contains methods for attribute manipulation (delegating to jQuery too).
  389. Example: `aTag at: 'value' put: 'hello world'`
  390. 4. Raw access and jQuery
  391. The `#element` method can be used to access to JavaScript DOM element object.
  392. Example: `aTag element cssStyle`
  393. Use `#asJQuery` to access to the receiver converted into a jQuery object.
  394. Example: `aTag asJQuery css: 'color' value: 'red'`!
  395. !TagBrush methodsFor: 'accessing'!
  396. element
  397. ^ element
  398. ! !
  399. !TagBrush methodsFor: 'adding'!
  400. addBrush: aTagBrush
  401. self appendChild: aTagBrush asDomNode.
  402. ^ aTagBrush
  403. !
  404. append: anObject
  405. anObject appendToBrush: self
  406. !
  407. appendBlock: aBlock
  408. | root |
  409. root := canvas root.
  410. canvas root: self.
  411. aBlock value: canvas.
  412. canvas root: root
  413. !
  414. appendChild: anElement
  415. "In IE7 and IE8 appendChild fails on several node types. So we need to check"
  416. <inlineJS: 'var element=$self["@element"];
  417. if (null == element.canHaveChildren || element.canHaveChildren) {
  418. element.appendChild(anElement);
  419. } else {
  420. element.text = String(element.text) + anElement.innerHTML;
  421. }'>
  422. !
  423. appendString: aString
  424. self appendChild: aString asDomNode
  425. !
  426. appendToBrush: aTagBrush
  427. aTagBrush addBrush: self
  428. !
  429. contents: anObject
  430. self
  431. empty;
  432. append: anObject
  433. !
  434. empty
  435. self asJQuery empty
  436. !
  437. with: anObject
  438. self append: anObject
  439. ! !
  440. !TagBrush methodsFor: 'attributes'!
  441. accesskey: aString
  442. self at: 'accesskey' put: aString
  443. !
  444. action: aString
  445. self at: 'action' put: aString
  446. !
  447. align: aString
  448. self at: 'align' put: aString
  449. !
  450. alt: aString
  451. self at: 'alt' put: aString
  452. !
  453. at: aString
  454. ^ self at: aString ifAbsent: [ Collection new errorNotFound ]
  455. !
  456. at: aString ifAbsent: aBlock
  457. <inlineJS: 'return $self["@element"].hasAttribute(aString) ? $self["@element"].getAttribute(aString) : aBlock._value()'>
  458. !
  459. at: aString put: aValue
  460. <inlineJS: '$self["@element"].setAttribute(aString, aValue); return aValue'>
  461. !
  462. class: aString
  463. <inlineJS: '$self["@element"].className = aString'>
  464. !
  465. cols: aString
  466. self at: 'cols' put: aString
  467. !
  468. contenteditable: aString
  469. self at: 'contenteditable' put: aString
  470. !
  471. contextmenu: aString
  472. self at: 'contextmenu' put: aString
  473. !
  474. draggable: aString
  475. self at: 'draggable' put: aString
  476. !
  477. for: aString
  478. self at: 'for' put: aString
  479. !
  480. height: aString
  481. self at: 'height' put: aString
  482. !
  483. hidden
  484. self at: 'hidden' put: 'hidden'
  485. !
  486. href: aString
  487. self at: 'href' put: aString
  488. !
  489. id: aString
  490. self at: 'id' put: aString
  491. !
  492. media: aString
  493. self at: 'media' put: aString
  494. !
  495. method: aString
  496. self at: 'method' put: aString
  497. !
  498. name: aString
  499. self at: 'name' put: aString
  500. !
  501. placeholder: aString
  502. self at: 'placeholder' put: aString
  503. !
  504. rel: aString
  505. self at: 'rel' put: aString
  506. !
  507. removeAt: aString
  508. <inlineJS: '$self["@element"].removeAttribute(aString)'>
  509. !
  510. rows: aString
  511. self at: 'rows' put: aString
  512. !
  513. src: aString
  514. self at: 'src' put: aString
  515. !
  516. style: aString
  517. self at: 'style' put: aString
  518. !
  519. tabindex: aNumber
  520. self at: 'tabindex' put: aNumber
  521. !
  522. target: aString
  523. self at: 'target' put: aString
  524. !
  525. title: aString
  526. self at: 'title' put: aString
  527. !
  528. type: aString
  529. self at: 'type' put: aString
  530. !
  531. valign: aString
  532. self at: 'valign' put: aString
  533. !
  534. value: aString
  535. self at: 'value' put: aString
  536. !
  537. width: aString
  538. self at: 'width' put: aString
  539. ! !
  540. !TagBrush methodsFor: 'converting'!
  541. asDomNode
  542. ^ element
  543. !
  544. asJQuery
  545. ^ self asDomNode asJQuery
  546. !
  547. asJQueryInContext: aContext
  548. ^ self asDomNode asJQueryInContext: aContext
  549. ! !
  550. !TagBrush methodsFor: 'events'!
  551. onBlur: aBlock
  552. self asJQuery bind: 'blur' do: aBlock
  553. !
  554. onChange: aBlock
  555. self asJQuery bind: 'change' do: aBlock
  556. !
  557. onClick: aBlock
  558. self asJQuery bind: 'click' do: aBlock
  559. !
  560. onDblClick: aBlock
  561. self asJQuery bind: 'dblclick' do: aBlock
  562. !
  563. onFocus: aBlock
  564. self asJQuery bind: 'focus' do: aBlock
  565. !
  566. onFocusIn: aBlock
  567. self asJQuery bind: 'focusin' do: aBlock
  568. !
  569. onFocusOut: aBlock
  570. self asJQuery bind: 'focusout' do: aBlock
  571. !
  572. onHover: aBlock
  573. self asJQuery bind: 'hover' do: aBlock
  574. !
  575. onKeyDown: aBlock
  576. self asJQuery bind: 'keydown' do: aBlock
  577. !
  578. onKeyPress: aBlock
  579. self asJQuery bind: 'keypress' do: aBlock
  580. !
  581. onKeyUp: aBlock
  582. self asJQuery bind: 'keyup' do: aBlock
  583. !
  584. onMouseDown: aBlock
  585. self asJQuery bind: 'mousedown' do: aBlock
  586. !
  587. onMouseEnter: aBlock
  588. self asJQuery bind: 'mouseenter' do: aBlock
  589. !
  590. onMouseLeave: aBlock
  591. self asJQuery bind: 'mouseleave' do: aBlock
  592. !
  593. onMouseMove: aBlock
  594. self asJQuery bind: 'mousemove' do: aBlock
  595. !
  596. onMouseOut: aBlock
  597. self asJQuery bind: 'mouseout' do: aBlock
  598. !
  599. onMouseOver: aBlock
  600. self asJQuery bind: 'mouseover' do: aBlock
  601. !
  602. onMouseUp: aBlock
  603. self asJQuery bind: 'mouseup' do: aBlock
  604. !
  605. onSelect: aBlock
  606. self asJQuery bind: 'select' do: aBlock
  607. !
  608. onSubmit: aBlock
  609. self asJQuery bind: 'submit' do: aBlock
  610. !
  611. onUnload: aBlock
  612. self asJQuery bind: 'unload' do: aBlock
  613. ! !
  614. !TagBrush methodsFor: 'initialization'!
  615. initializeFromJQuery: aJQuery canvas: aCanvas
  616. element := aJQuery get: 0.
  617. canvas := aCanvas
  618. !
  619. initializeFromString: aString canvas: aCanvas
  620. element := document createElement: aString.
  621. canvas := aCanvas
  622. ! !
  623. !TagBrush class methodsFor: 'instance creation'!
  624. fromJQuery: aJQuery
  625. ^ self fromJQuery: aJQuery canvas: HTMLCanvas new
  626. !
  627. fromJQuery: aJQuery canvas: aCanvas
  628. ^ self new
  629. initializeFromJQuery: aJQuery canvas: aCanvas;
  630. yourself
  631. !
  632. fromString: aString
  633. ^ self fromString: aString canvas: HTMLCanvas new
  634. !
  635. fromString: aString canvas: aCanvas
  636. ^ self new
  637. initializeFromString: aString canvas: aCanvas;
  638. yourself
  639. ! !
  640. Object subclass: #Widget
  641. instanceVariableNames: ''
  642. package: 'Web'!
  643. !Widget commentStamp!
  644. I am a presenter building HTML. Subclasses are typically reusable components.
  645. ## API
  646. Use `#renderContentOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).
  647. To add a widget to the page, the convenience method `#appendToJQuery:` is very useful.
  648. Exemple:
  649. Counter new appendToJQuery: 'body' asJQuery!
  650. !Widget methodsFor: 'adding'!
  651. appendToBrush: aTagBrush
  652. [ :html | self renderOn: html ] appendToBrush: aTagBrush
  653. !
  654. appendToJQuery: aJQuery
  655. self renderOn: (HTMLCanvas onJQuery: aJQuery)
  656. ! !
  657. !Widget methodsFor: 'rendering'!
  658. renderOn: html
  659. self
  660. ! !
  661. !Widget class methodsFor: 'accessing'!
  662. classTag
  663. "Returns a tag or general category for this class.
  664. Typically used to help tools do some reflection.
  665. Helios, for example, uses this to decide what icon the class should display."
  666. ^ 'widget'
  667. ! !
  668. !Association methodsFor: '*Web'!
  669. appendToBrush: aTagBrush
  670. aTagBrush at: self key put: self value
  671. ! !
  672. !BlockClosure methodsFor: '*Web'!
  673. appendToBrush: aTagBrush
  674. aTagBrush appendBlock: self
  675. !
  676. appendToJQuery: aJQuery
  677. self value: (HTMLCanvas onJQuery: aJQuery)
  678. ! !
  679. !Collection methodsFor: '*Web'!
  680. appendToBrush: aTagBrush
  681. self do: [ :each | aTagBrush append: each ]
  682. ! !
  683. !JSObjectProxy methodsFor: '*Web'!
  684. appendToBrush: aTagBrush
  685. (PlatformDom isDomNode: jsObject)
  686. ifTrue: [ aTagBrush appendChild: jsObject ]
  687. ifFalse: [ aTagBrush append: self asString ]
  688. ! !
  689. !Object methodsFor: '*Web'!
  690. appendToBrush: aTagBrush
  691. aTagBrush append: self asString
  692. !
  693. appendToJQuery: aJQuery
  694. aJQuery append: self asString
  695. ! !
  696. !String methodsFor: '*Web'!
  697. appendToBrush: aTagBrush
  698. aTagBrush appendString: self
  699. !
  700. appendToJQuery: aJQuery
  701. aJQuery append: self
  702. ! !