Web.st 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. Smalltalk createPackage: 'Web'!
  2. (Smalltalk packageAt: 'Web') imports: {'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 element.
  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. <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: (self createTextNodeFor: aString)
  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. <return self['@element'].hasAttribute(aString) ? self['@element'].getAttribute(aString) : aBlock._value()>
  458. !
  459. at: aString put: aValue
  460. <self['@element'].setAttribute(aString, aValue); return aValue>
  461. !
  462. class: aString
  463. <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. <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. asJQuery
  542. ^ self element asJQuery
  543. !
  544. asJQueryInContext: aContext
  545. ^ self element asJQueryInContext: aContext
  546. ! !
  547. !TagBrush methodsFor: 'events'!
  548. onBlur: aBlock
  549. self asJQuery bind: 'blur' do: aBlock
  550. !
  551. onChange: aBlock
  552. self asJQuery bind: 'change' do: aBlock
  553. !
  554. onClick: aBlock
  555. self asJQuery bind: 'click' do: aBlock
  556. !
  557. onDblClick: aBlock
  558. self asJQuery bind: 'dblclick' do: aBlock
  559. !
  560. onFocus: aBlock
  561. self asJQuery bind: 'focus' do: aBlock
  562. !
  563. onFocusIn: aBlock
  564. self asJQuery bind: 'focusin' do: aBlock
  565. !
  566. onFocusOut: aBlock
  567. self asJQuery bind: 'focusout' do: aBlock
  568. !
  569. onHover: aBlock
  570. self asJQuery bind: 'hover' do: aBlock
  571. !
  572. onKeyDown: aBlock
  573. self asJQuery bind: 'keydown' do: aBlock
  574. !
  575. onKeyPress: aBlock
  576. self asJQuery bind: 'keypress' do: aBlock
  577. !
  578. onKeyUp: aBlock
  579. self asJQuery bind: 'keyup' do: aBlock
  580. !
  581. onMouseDown: aBlock
  582. self asJQuery bind: 'mousedown' do: aBlock
  583. !
  584. onMouseEnter: aBlock
  585. self asJQuery bind: 'mouseenter' do: aBlock
  586. !
  587. onMouseLeave: aBlock
  588. self asJQuery bind: 'mouseleave' do: aBlock
  589. !
  590. onMouseMove: aBlock
  591. self asJQuery bind: 'mousemove' do: aBlock
  592. !
  593. onMouseOut: aBlock
  594. self asJQuery bind: 'mouseout' do: aBlock
  595. !
  596. onMouseOver: aBlock
  597. self asJQuery bind: 'mouseover' do: aBlock
  598. !
  599. onMouseUp: aBlock
  600. self asJQuery bind: 'mouseup' do: aBlock
  601. !
  602. onSelect: aBlock
  603. self asJQuery bind: 'select' do: aBlock
  604. !
  605. onSubmit: aBlock
  606. self asJQuery bind: 'submit' do: aBlock
  607. !
  608. onUnload: aBlock
  609. self asJQuery bind: 'unload' do: aBlock
  610. ! !
  611. !TagBrush methodsFor: 'initialization'!
  612. initializeFromJQuery: aJQuery canvas: aCanvas
  613. element := aJQuery get: 0.
  614. canvas := aCanvas
  615. !
  616. initializeFromString: aString canvas: aCanvas
  617. element := self createElementFor: aString.
  618. canvas := aCanvas
  619. ! !
  620. !TagBrush methodsFor: 'private'!
  621. appendDocumentFragment: anElement
  622. <var element=self['@element'].appendChild(anElement["@element"])>
  623. !
  624. createElementFor: aString
  625. <return document.createElement(String(aString))>
  626. !
  627. createTextNodeFor: aString
  628. <return document.createTextNode(String(aString))>
  629. ! !
  630. !TagBrush class methodsFor: 'instance creation'!
  631. fromJQuery: aJQuery
  632. ^ self fromJQuery: aJQuery canvas: HTMLCanvas new
  633. !
  634. fromJQuery: aJQuery canvas: aCanvas
  635. ^ self new
  636. initializeFromJQuery: aJQuery canvas: aCanvas;
  637. yourself
  638. !
  639. fromString: aString
  640. ^ self fromString: aString canvas: HTMLCanvas new
  641. !
  642. fromString: aString canvas: aCanvas
  643. ^ self new
  644. initializeFromString: aString canvas: aCanvas;
  645. yourself
  646. ! !
  647. Object subclass: #Widget
  648. instanceVariableNames: ''
  649. package: 'Web'!
  650. !Widget commentStamp!
  651. I am a presenter building HTML. Subclasses are typically reusable components.
  652. ## API
  653. Use `#renderContentOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).
  654. To add a widget to the page, the convenience method `#appendToJQuery:` is very useful.
  655. Exemple:
  656. Counter new appendToJQuery: 'body' asJQuery!
  657. !Widget methodsFor: 'adding'!
  658. appendToBrush: aTagBrush
  659. [ :html | self renderOn: html ] appendToBrush: aTagBrush
  660. !
  661. appendToJQuery: aJQuery
  662. self renderOn: (HTMLCanvas onJQuery: aJQuery)
  663. ! !
  664. !Widget methodsFor: 'rendering'!
  665. renderOn: html
  666. self
  667. ! !
  668. !Widget class methodsFor: 'accessing'!
  669. classTag
  670. "Returns a tag or general category for this class.
  671. Typically used to help tools do some reflection.
  672. Helios, for example, uses this to decide what icon the class should display."
  673. ^ 'widget'
  674. ! !
  675. !Association methodsFor: '*Web'!
  676. appendToBrush: aTagBrush
  677. aTagBrush at: self key put: self value
  678. ! !
  679. !BlockClosure methodsFor: '*Web'!
  680. appendToBrush: aTagBrush
  681. aTagBrush appendBlock: self
  682. !
  683. appendToJQuery: aJQuery
  684. self value: (HTMLCanvas onJQuery: aJQuery)
  685. ! !
  686. !Collection methodsFor: '*Web'!
  687. appendToBrush: aTagBrush
  688. self do: [ :each | aTagBrush append: each ]
  689. ! !
  690. !Object methodsFor: '*Web'!
  691. appendToBrush: aTagBrush
  692. aTagBrush append: self asString
  693. !
  694. appendToJQuery: aJQuery
  695. aJQuery append: self asString
  696. ! !
  697. !String methodsFor: '*Web'!
  698. appendToBrush: aTagBrush
  699. aTagBrush appendString: self
  700. !
  701. appendToJQuery: aJQuery
  702. aJQuery append: self
  703. ! !