|
@@ -1,231 +1,53 @@
|
|
|
Smalltalk current createPackage: 'Documentation' properties: #{}!
|
|
|
-Object subclass: #DocumentationBuilder
|
|
|
- instanceVariableNames: 'chapters announcer widget'
|
|
|
- category: 'Documentation'!
|
|
|
-
|
|
|
-!DocumentationBuilder methodsFor: 'accessing'!
|
|
|
-
|
|
|
-chapters
|
|
|
- ^chapters ifNil: [chapters := self buildChapters]
|
|
|
-!
|
|
|
-
|
|
|
-announcer
|
|
|
- ^announcer ifNil: [announcer := Announcer new]
|
|
|
-!
|
|
|
-
|
|
|
-widget
|
|
|
- ^widget ifNil: [widget := DocumentationWidget on: self]
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationBuilder methodsFor: 'building'!
|
|
|
-
|
|
|
-buildChapters
|
|
|
- ^((self class methodDictionary values sorted: [:a :b | a selector < b selector])
|
|
|
- select: [:each | each category = 'chapters'])
|
|
|
- collect: [:each | self perform: each selector]
|
|
|
-!
|
|
|
+Object subclass: #ChapterSelectionAnnouncement
|
|
|
+ instanceVariableNames: 'id'
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
-buildOn: aCanvas
|
|
|
- aCanvas with: self widget.
|
|
|
- self
|
|
|
- checkHashChange;
|
|
|
- checkHash
|
|
|
-!
|
|
|
+!ChapterSelectionAnnouncement methodsFor: 'accessing'!
|
|
|
|
|
|
-buildOnJQuery: aJQuery
|
|
|
- self buildOn: (HTMLCanvas onJQuery: aJQuery)
|
|
|
+id
|
|
|
+ ^id
|
|
|
!
|
|
|
|
|
|
-build
|
|
|
- self buildOnJQuery: ('body' asJQuery)
|
|
|
+id: aString
|
|
|
+ id := aString
|
|
|
! !
|
|
|
|
|
|
-!DocumentationBuilder methodsFor: 'chapters'!
|
|
|
-
|
|
|
-ch1introduction
|
|
|
- ^DocChapter new
|
|
|
- title: 'Introduction';
|
|
|
- contents: '
|
|
|
-
|
|
|
-##Amber Smalltalk in a nutshell
|
|
|
-
|
|
|
-Amber is an implementation of the Smalltalk-80 language. It is designed to make client-side web development **faster, easier and more fun** as it allows developers to write HTML5 applications in a live Smalltalk environment!!
|
|
|
-
|
|
|
-Amber is written in itself, including the IDE and the compiler and it runs **directly inside your browser**. The IDE is fairly complete with a class browser, workspace, transcript, unit test runner, object inspectors, cross reference tools and even a debugger.
|
|
|
-
|
|
|
-Noteworthy features:
|
|
|
-
|
|
|
-- Amber is semantically and syntactically very close to [Pharo Smalltalk](http://www.pharo-project.org). Pharo is considered the reference implementation.
|
|
|
-- Amber **seamlessly interacts with JavaScript** and can use its full eco system of libraries without any glue code needed.
|
|
|
-- Amber **has no dependencies** and can be used in any JavaScript runtime, not only inside browsers. An important example is [Node.js](http://nodejs.org).
|
|
|
-- Amber is a live Smalltalk that **compiles incrementally into efficient JavaScript** often mapping one-to-one with JavaScript equivalents.
|
|
|
-- Amber has a **Seaside influenced canvas library** to dynamically generate HTML.
|
|
|
-
|
|
|
-## Arguments for using Amber
|
|
|
-In our humble opinion the main arguments for using Amber are:
|
|
|
-
|
|
|
-- JavaScript is quite a broken language with lots of traps and odd quirks. It is the assembler of the Internet which is cool, but we don''t want to write in it.
|
|
|
-- Smalltalk as a language is immensely cleaner and more mature, both syntactically and semantically.
|
|
|
-- Smalltalk has a simple class model with a lightweight syntax for closures, it is in many ways a perfect match for the Good Parts of JavaScript.
|
|
|
-- Having a true live interactive incremental development environment where you can build your application directly in the browser is unbeatable.
|
|
|
-
|
|
|
-## Disclaimer
|
|
|
-
|
|
|
-This documentation doesn''t aim to teach Smalltalk.
|
|
|
-Knowledge of Smalltalk is needed to understand the topics covered in this documentation.
|
|
|
-If you want to learn the Smalltalk language, you can read the excellent [Pharo By Example](http://www.pharobyexample.org) book.
|
|
|
-'
|
|
|
-!
|
|
|
-
|
|
|
-ch2differencesWithOtherSmalltalks
|
|
|
- ^DocChapter new
|
|
|
- title: 'Differences with other Smalltalks';
|
|
|
- contents: '
|
|
|
-Amber has some differences with other Smalltalk implementations. This makes porting code a non-trivial thing, but still quite manageable.
|
|
|
-Because it maps Smalltalk constructs one-to-one with the JavaScript equivalent, including Smalltalk classes to JavaScript constructors, the core class library is simplified compared to Pharo Smalltalk.
|
|
|
-And since we want Amber to be useful in building lean browser apps we can''t let it bloat too much.
|
|
|
-
|
|
|
-But apart from missing things other Smalltalks may have, there are also things that are plain different:
|
|
|
-
|
|
|
-- The collection class hierarchy is much simpler compared to most Smalltalk implementations. In part this is because we want to map reasonably well with JavaScript counter parts.
|
|
|
-- As of today, there is no SortedCollection. The size of arrays is dynamic, and they behave like an ordered collection. They can also be sorted with the `#sort*` methods.
|
|
|
-- The `Date` class behaves like the `Date` and `TimeStamp` classes in Pharo Smalltalk. Therefore both `Date today` and `Date now` are valid in Amber.
|
|
|
-- Amber does not have class Character, but `String` does implement some of Character behavior so a single character String can work as a Character.
|
|
|
-- Amber does support **class instance variables**, but not class variables.
|
|
|
-- Amber only has global classes and packages, but not arbitrary objects. Use classes instead like `Smalltalk current` instead of `Smalltalk` etc.
|
|
|
-- Amber does not support pool dictionaries.
|
|
|
-- Amber uses **< ...javascript code... >** to inline JavaScript code and does not have pragmas.
|
|
|
-- Amber does not have class categories. The left side in the browser lists real Packages, but they feel much the same.
|
|
|
-'
|
|
|
-!
|
|
|
-
|
|
|
-ch3GettingStarted
|
|
|
- ^DocChapter new
|
|
|
- title: 'Getting started';
|
|
|
- contents: '
|
|
|
-To get started hacking in Amber you can basically take three routes, independent of your platform:
|
|
|
-
|
|
|
-1. Just **try it out directly** at [www.amber-lang.net](http://www.amber-lang.net) - click the **Class browser** button there. But you will **not be able to save any code you write**!!
|
|
|
- Still, it works fine for looking at the IDE and playing around. Just **don''t press F5/reload** - it will lose any code you have written.
|
|
|
-2. Download an Amber zip-ball, install [Nodejs](http://www.nodejs.org), fire up the Amber server and then open Amber from localhost - then you **can save code**. Detailed instructions are below!!
|
|
|
-3. Same as above but install git first and get a proper clone from [http://github.com/NicolasPetton/amber](http://github.com/NicolasPetton/amber) instead of a zip/tar-ball.
|
|
|
- If you want to **contribute to Amber itself** this is really what you want to do. In fact, in most cases this is what you want to do. It requires installing git first, but it is quite simple - although we leave this bit as an "exercise to the reader" :)
|
|
|
-
|
|
|
-**PLEASE NOTE:** Amber core developers use Linux.
|
|
|
-We do not want to introduce dependencies that aren''t cross platform - but currently amberc (the command line compiler) is a bash script and we also use Makefiles
|
|
|
-(for building Amber itself and server side examples) written on Linux/Unix. So using Windows is currently a bit limited - you can''t run "make" in the .st directory to rebuild whole of Amber for example.
|
|
|
- BUT... if you only want to use Amber to build web client apps and not really get involved in hacking Amber itself - then you should be fine!!
|
|
|
-
|
|
|
-## Downloading Amber
|
|
|
-Currently you can download in zip or tar-ball format, either cutting edge or a release. [Downloads are available here](https://github.com/NicolasPetton/amber/archives/amber).
|
|
|
-
|
|
|
-Unpack wherever you like, but I would rename the directory that is unpacked to something slightly shorter - like say "amber". :)
|
|
|
-And yes, at this point you can double click the index.html file in the amber directory to get the IDE up, but again, **you will not be able to save code**. So please continue below :)
|
|
|
-
|
|
|
-## Installing Node.js
|
|
|
-[Node](http://www.nodejs.org) (for short) is simply the V8 Javascript VM from Google (used in Chrome) hooked together with some hard core C-libraries for doing "evented I/O".
|
|
|
-Basically it''s JavaScript for the server - on asynch steroids. Amber runs fine in Node and we use it for several Amber tools, like amberc (the command line Amber compiler) or the Amber server (see below).
|
|
|
-There are also several Amber-Node examples to look at if you want to play with running Amber programs server side. **In short - you really want to install Nodejs. :)**
|
|
|
-
|
|
|
-- Installing Node on Linux can be done using your package tool of choice (`apt-get install nodejs` for example) or any other way described at [the download page](http://nodejs.org/#download).
|
|
|
-- Installing Node on MacOS or Windows is probably done best by using the [installers available at Nodejs.org](http://nodejs.org/#download).
|
|
|
-
|
|
|
-## Starting Amber server
|
|
|
-Nicolas has written a minimal webDAV server that is the easiest way to get up and running Amber with the ability to save code. This little server is written in... Amber!!
|
|
|
-And it runs on top of Node. So to start it up serving your brand new directory tree of sweet Amber you do:
|
|
|
-
|
|
|
- cd amber (or whatever you called the directory you unpackaged)
|
|
|
- ./bin/server (in windows you type `node server\server.js` instead)
|
|
|
-
|
|
|
-It should say it is listening on port 4000. If it does, hooray!! That means both Node and Amber are good. In Windows you might get a question about opening that port in the local firewall - yep, do it!!
|
|
|
-
|
|
|
-## Firing up Amber
|
|
|
-The Amber IDE is written in... Amber. It uses [jQuery](http://jquery.com) and runs right in your browser as a ... well, a web page.
|
|
|
-We could open it up just using a file url - but the reason we performed the previous steps is so that we can load the IDE web page from a server that can handle PUTs (webDAV) of source code.
|
|
|
-According to web security Amber can only do PUT back to the same server it was loaded from. Thus we instead want to open it [through our little server now listening on port 4000](http://localhost:4000/index.html).
|
|
|
-Clicking that link and then pressing the **Class browser** should get your Amber IDE running with the ability to commit modified packages locally.
|
|
|
-
|
|
|
-To verify that you can indeed commit now - just select a Package in the browser, like say "Examples" and press the **Commit** button below. **If all goes well nothing happens :)**.
|
|
|
-So in order to really know if it worked we can check the modified date on the files **amber/st/Examples.st**, **amber/js/Examples.js** and **amber/js/Examples.deploy.js** - they should be brand new.
|
|
|
-
|
|
|
-NOTE: We can use any webDAV server and Apache2 has been used earlier and works fine. But the Amber server is smaller and simpler to start.
|
|
|
-'
|
|
|
-!
|
|
|
-
|
|
|
-ch5Index
|
|
|
- ^ClassesIndexChapter new
|
|
|
-!
|
|
|
-
|
|
|
-ch6KernelObjects
|
|
|
- ^PackageDocChapter on: (Package named: 'Kernel-Objects')
|
|
|
-!
|
|
|
-
|
|
|
-ch7KernelClasses
|
|
|
- ^PackageDocChapter on: (Package named: 'Kernel-Classes')
|
|
|
-!
|
|
|
-
|
|
|
-ch4Tutorials
|
|
|
- ^TutorialsChapter new
|
|
|
-!
|
|
|
-
|
|
|
-ch8KernelCollection
|
|
|
- ^PackageDocChapter on: (Package named: 'Kernel-Collections')
|
|
|
-!
|
|
|
-
|
|
|
-ch9KernelMethods
|
|
|
- ^PackageDocChapter on: (Package named: 'Kernel-Methods')
|
|
|
-! !
|
|
|
+Object subclass: #ClassSelectionAnnouncement
|
|
|
+ instanceVariableNames: 'theClass'
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
-!DocumentationBuilder methodsFor: 'routing'!
|
|
|
+!ClassSelectionAnnouncement methodsFor: 'accessing'!
|
|
|
|
|
|
-checkHashChange
|
|
|
- (window jQuery: window) bind: 'hashchange' do: [self checkHash]
|
|
|
+theClass
|
|
|
+ ^theClass
|
|
|
!
|
|
|
|
|
|
-checkHash
|
|
|
- | hash presentation |
|
|
|
- hash := document location hash replace: '^#' with: ''.
|
|
|
- self announcer announce: (ChapterSelectionAnnouncement new
|
|
|
- id: hash;
|
|
|
- yourself)
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationBuilder methodsFor: 'updating'!
|
|
|
-
|
|
|
-update
|
|
|
- chapters := nil.
|
|
|
- announcer := nil.
|
|
|
- widget := nil.
|
|
|
- (window jQuery: '.documentation') remove.
|
|
|
- self build
|
|
|
-! !
|
|
|
-
|
|
|
-DocumentationBuilder class instanceVariableNames: 'current'!
|
|
|
-
|
|
|
-!DocumentationBuilder class methodsFor: 'accessing'!
|
|
|
-
|
|
|
-current
|
|
|
- ^current ifNil: [current := self new]
|
|
|
+theClass: aClass
|
|
|
+ theClass := aClass
|
|
|
! !
|
|
|
|
|
|
-!DocumentationBuilder class methodsFor: 'initialization'!
|
|
|
+!ClassSelectionAnnouncement class methodsFor: 'instance creation'!
|
|
|
|
|
|
-initialize
|
|
|
- self current build
|
|
|
+on: aClass
|
|
|
+ ^self new
|
|
|
+ theClass: aClass;
|
|
|
+ yourself
|
|
|
! !
|
|
|
|
|
|
Widget subclass: #DocChapter
|
|
|
- instanceVariableNames: 'title contents parent'
|
|
|
- category: 'Documentation'!
|
|
|
+ instanceVariableNames: 'title contents parent level'
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
!DocChapter methodsFor: 'accessing'!
|
|
|
|
|
|
-title
|
|
|
- ^title ifNil: ['']
|
|
|
+announcer
|
|
|
+ ^DocumentationBuilder current announcer
|
|
|
!
|
|
|
|
|
|
-title: aString
|
|
|
- title := aString
|
|
|
+chapters
|
|
|
+ "A doc chapter can contain sub chapters"
|
|
|
+ ^#()
|
|
|
!
|
|
|
|
|
|
contents
|
|
@@ -236,17 +58,18 @@ contents: aString
|
|
|
contents := aString
|
|
|
!
|
|
|
|
|
|
-htmlContents
|
|
|
- ^(Showdown at: #converter) new makeHtml: self contents
|
|
|
+cssClass
|
|
|
+ ^'doc_chapter'
|
|
|
!
|
|
|
|
|
|
-chapters
|
|
|
- "A doc chapter can contain sub chapters"
|
|
|
- ^#()
|
|
|
+htmlContents
|
|
|
+ ^(Showdown at: #converter) new makeHtml: self contents
|
|
|
!
|
|
|
|
|
|
-cssClass
|
|
|
- ^'doc_chapter'
|
|
|
+id
|
|
|
+ "The id is used in url fragments.
|
|
|
+ It must be unique amoung all chapters"
|
|
|
+ ^self title replace: ' ' with: '-'
|
|
|
!
|
|
|
|
|
|
level
|
|
@@ -265,28 +88,26 @@ parent: aChapter
|
|
|
parent := aChapter
|
|
|
!
|
|
|
|
|
|
-id
|
|
|
- "The id is used in url fragments.
|
|
|
- It must be unique amoung all chapters"
|
|
|
- ^self title replace: ' ' with: '-'
|
|
|
+title
|
|
|
+ ^title ifNil: ['']
|
|
|
!
|
|
|
|
|
|
-announcer
|
|
|
- ^DocumentationBuilder current announcer
|
|
|
+title: aString
|
|
|
+ title := aString
|
|
|
! !
|
|
|
|
|
|
!DocChapter methodsFor: 'actions'!
|
|
|
|
|
|
-selectClass: aClass
|
|
|
- DocumentationBuilder current announcer announce: (ClassSelectionAnnouncement on: aClass)
|
|
|
+displayChapter: aChapter
|
|
|
+ DocumentationBuilder current widget displayChapter: aChapter
|
|
|
!
|
|
|
|
|
|
selectChapter: aChapter
|
|
|
document location hash: aChapter id
|
|
|
!
|
|
|
|
|
|
-displayChapter: aChapter
|
|
|
- DocumentationBuilder current widget displayChapter: aChapter
|
|
|
+selectClass: aClass
|
|
|
+ DocumentationBuilder current announcer announce: (ClassSelectionAnnouncement on: aClass)
|
|
|
! !
|
|
|
|
|
|
!DocChapter methodsFor: 'initialization'!
|
|
@@ -298,14 +119,6 @@ initialize
|
|
|
|
|
|
!DocChapter methodsFor: 'rendering'!
|
|
|
|
|
|
-renderOn: html
|
|
|
- html div
|
|
|
- class: self cssClass;
|
|
|
- with: [
|
|
|
- self renderDocOn: html.
|
|
|
- self renderLinksOn: html]
|
|
|
-!
|
|
|
-
|
|
|
renderDocOn: html
|
|
|
| div |
|
|
|
html h1 with: self title.
|
|
@@ -314,6 +127,17 @@ renderDocOn: html
|
|
|
div asJQuery html: self htmlContents
|
|
|
!
|
|
|
|
|
|
+renderLinksOn: html
|
|
|
+ html ul
|
|
|
+ class: 'links';
|
|
|
+ with: [
|
|
|
+ self chapters do: [:each |
|
|
|
+ html li with: [
|
|
|
+ html a
|
|
|
+ with: each title;
|
|
|
+ onClick: [self selectChapter: each]]]]
|
|
|
+!
|
|
|
+
|
|
|
renderNavigationOn: html
|
|
|
self parent ifNotNil: [
|
|
|
html div
|
|
@@ -323,15 +147,12 @@ renderNavigationOn: html
|
|
|
onClick: [self selectChapter: self parent]]]
|
|
|
!
|
|
|
|
|
|
-renderLinksOn: html
|
|
|
- html ul
|
|
|
- class: 'links';
|
|
|
+renderOn: html
|
|
|
+ html div
|
|
|
+ class: self cssClass;
|
|
|
with: [
|
|
|
- self chapters do: [:each |
|
|
|
- html li with: [
|
|
|
- html a
|
|
|
- with: each title;
|
|
|
- onClick: [self selectChapter: each]]]]
|
|
|
+ self renderDocOn: html.
|
|
|
+ self renderLinksOn: html]
|
|
|
! !
|
|
|
|
|
|
!DocChapter methodsFor: 'subscriptions'!
|
|
@@ -341,57 +162,12 @@ subscribe
|
|
|
ann id = self id ifTrue: [self displayChapter: self]]
|
|
|
! !
|
|
|
|
|
|
-DocChapter subclass: #PackageDocChapter
|
|
|
- instanceVariableNames: 'package chapters'
|
|
|
- category: 'Documentation'!
|
|
|
-
|
|
|
-!PackageDocChapter methodsFor: 'accessing'!
|
|
|
-
|
|
|
-package
|
|
|
- ^package
|
|
|
-!
|
|
|
-
|
|
|
-title
|
|
|
- ^'Package ', self package name
|
|
|
-!
|
|
|
-
|
|
|
-chapters
|
|
|
- ^chapters
|
|
|
-!
|
|
|
-
|
|
|
-contents
|
|
|
- ^'Classes in package ', self package name, ':'
|
|
|
-! !
|
|
|
-
|
|
|
-!PackageDocChapter methodsFor: 'initialization'!
|
|
|
-
|
|
|
-initializeWithPackage: aPackage
|
|
|
- package := aPackage.
|
|
|
- chapters := (aPackage classes sorted: [:a :b | a name < b name]) collect: [:each |
|
|
|
- (ClassDocChapter on: each)
|
|
|
- parent: self;
|
|
|
- yourself]
|
|
|
-! !
|
|
|
-
|
|
|
-!PackageDocChapter class methodsFor: 'instance creation'!
|
|
|
-
|
|
|
-on: aPackage
|
|
|
- ^self basicNew
|
|
|
- initializeWithPackage: aPackage;
|
|
|
- initialize;
|
|
|
- yourself
|
|
|
-! !
|
|
|
-
|
|
|
DocChapter subclass: #ClassDocChapter
|
|
|
instanceVariableNames: 'theClass'
|
|
|
- category: 'Documentation'!
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
!ClassDocChapter methodsFor: 'accessing'!
|
|
|
|
|
|
-theClass
|
|
|
- ^theClass
|
|
|
-!
|
|
|
-
|
|
|
contents
|
|
|
^self theClass comment isEmpty
|
|
|
ifTrue: [self theClass name, ' is not documented yet.']
|
|
@@ -402,12 +178,16 @@ cssClass
|
|
|
^'doc_class ', super cssClass
|
|
|
!
|
|
|
|
|
|
-title
|
|
|
- ^self theClass name
|
|
|
-!
|
|
|
-
|
|
|
initializeWithClass: aClass
|
|
|
theClass := aClass
|
|
|
+!
|
|
|
+
|
|
|
+theClass
|
|
|
+ ^theClass
|
|
|
+!
|
|
|
+
|
|
|
+title
|
|
|
+ ^self theClass name
|
|
|
! !
|
|
|
|
|
|
!ClassDocChapter methodsFor: 'rendering'!
|
|
@@ -440,106 +220,22 @@ on: aClass
|
|
|
yourself
|
|
|
! !
|
|
|
|
|
|
-Widget subclass: #DocumentationWidget
|
|
|
- instanceVariableNames: 'builder selectedChapter chapterDiv'
|
|
|
- category: 'Documentation'!
|
|
|
-
|
|
|
-!DocumentationWidget methodsFor: 'accessing'!
|
|
|
-
|
|
|
-builder
|
|
|
- ^builder
|
|
|
-!
|
|
|
-
|
|
|
-builder: aDocumentationBuilder
|
|
|
- builder := aDocumentationBuilder
|
|
|
-!
|
|
|
-
|
|
|
-chapters
|
|
|
- ^self builder chapters
|
|
|
-!
|
|
|
-
|
|
|
-selectedChapter
|
|
|
- ^selectedChapter ifNil: [selectedChapter := self chapters first]
|
|
|
-!
|
|
|
-
|
|
|
-selectedChapter: aChapter
|
|
|
- ^selectedChapter := aChapter
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationWidget methodsFor: 'actions'!
|
|
|
-
|
|
|
-displayChapter: aChapter
|
|
|
- self selectedChapter: aChapter.
|
|
|
- self updateChapterDiv
|
|
|
-!
|
|
|
-
|
|
|
-selectChapter: aChapter
|
|
|
- document location hash: aChapter id
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationWidget methodsFor: 'rendering'!
|
|
|
-
|
|
|
-renderOn: html
|
|
|
- html div
|
|
|
- class: 'documentation';
|
|
|
- with: [
|
|
|
- self renderMenuOn: html.
|
|
|
- chapterDiv := html div.
|
|
|
- self updateChapterDiv]
|
|
|
-!
|
|
|
-
|
|
|
-renderMenuOn: html
|
|
|
- html div
|
|
|
- class: 'menu';
|
|
|
- with: [
|
|
|
- html ol with: [
|
|
|
- self chapters do: [:each |
|
|
|
- html li with: [
|
|
|
- self renderChapterMenu: each on: html]]]]
|
|
|
-!
|
|
|
-
|
|
|
-renderChapterMenu: aChapter on: html
|
|
|
- html a
|
|
|
- with: aChapter title;
|
|
|
- onClick: [
|
|
|
- self selectChapter: aChapter].
|
|
|
- html ol with: [
|
|
|
- aChapter chapters do: [:each |
|
|
|
- html li with: [
|
|
|
- self renderChapterMenu: each on: html]]]
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationWidget methodsFor: 'updating'!
|
|
|
-
|
|
|
-updateChapterDiv
|
|
|
- chapterDiv contents: [:html |
|
|
|
- html with: self selectedChapter]
|
|
|
-! !
|
|
|
-
|
|
|
-!DocumentationWidget class methodsFor: 'instance creation'!
|
|
|
-
|
|
|
-on: aBuilder
|
|
|
- ^self new
|
|
|
- builder: aBuilder;
|
|
|
- yourself
|
|
|
-! !
|
|
|
-
|
|
|
DocChapter subclass: #ClassesIndexChapter
|
|
|
instanceVariableNames: ''
|
|
|
- category: 'Documentation'!
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
!ClassesIndexChapter methodsFor: 'accessing'!
|
|
|
|
|
|
+alphabet
|
|
|
+ ^'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
|
+!
|
|
|
+
|
|
|
cssClass
|
|
|
^'index_doc ', super cssClass
|
|
|
!
|
|
|
|
|
|
title
|
|
|
^'Smalltalk classes by index'
|
|
|
-!
|
|
|
-
|
|
|
-alphabet
|
|
|
- ^'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
|
! !
|
|
|
|
|
|
!ClassesIndexChapter methodsFor: 'rendering'!
|
|
@@ -557,74 +253,132 @@ renderDocOn: html
|
|
|
onClick: [self selectClass: each]]]]]
|
|
|
! !
|
|
|
|
|
|
-Object subclass: #ClassSelectionAnnouncement
|
|
|
- instanceVariableNames: 'theClass'
|
|
|
- category: 'Documentation'!
|
|
|
+DocChapter subclass: #PackageDocChapter
|
|
|
+ instanceVariableNames: 'package chapters'
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
-!ClassSelectionAnnouncement methodsFor: 'accessing'!
|
|
|
+!PackageDocChapter methodsFor: 'accessing'!
|
|
|
|
|
|
-theClass
|
|
|
- ^theClass
|
|
|
+chapters
|
|
|
+ ^chapters
|
|
|
!
|
|
|
|
|
|
-theClass: aClass
|
|
|
- theClass := aClass
|
|
|
-! !
|
|
|
+contents
|
|
|
+ ^'Classes in package ', self package name, ':'
|
|
|
+!
|
|
|
|
|
|
-!ClassSelectionAnnouncement class methodsFor: 'instance creation'!
|
|
|
+package
|
|
|
+ ^package
|
|
|
+!
|
|
|
|
|
|
-on: aClass
|
|
|
- ^self new
|
|
|
- theClass: aClass;
|
|
|
- yourself
|
|
|
+title
|
|
|
+ ^'Package ', self package name
|
|
|
! !
|
|
|
|
|
|
-Object subclass: #ChapterSelectionAnnouncement
|
|
|
- instanceVariableNames: 'id'
|
|
|
- category: 'Documentation'!
|
|
|
+!PackageDocChapter methodsFor: 'initialization'!
|
|
|
|
|
|
-!ChapterSelectionAnnouncement methodsFor: 'accessing'!
|
|
|
+initializeWithPackage: aPackage
|
|
|
+ package := aPackage.
|
|
|
+ chapters := (aPackage classes sorted: [:a :b | a name < b name]) collect: [:each |
|
|
|
+ (ClassDocChapter on: each)
|
|
|
+ parent: self;
|
|
|
+ yourself]
|
|
|
+! !
|
|
|
|
|
|
-id
|
|
|
- ^id
|
|
|
-!
|
|
|
+!PackageDocChapter class methodsFor: 'instance creation'!
|
|
|
|
|
|
-id: aString
|
|
|
- id := aString
|
|
|
+on: aPackage
|
|
|
+ ^self basicNew
|
|
|
+ initializeWithPackage: aPackage;
|
|
|
+ initialize;
|
|
|
+ yourself
|
|
|
! !
|
|
|
|
|
|
DocChapter subclass: #TutorialsChapter
|
|
|
instanceVariableNames: ''
|
|
|
- category: 'Documentation'!
|
|
|
+ package: 'Documentation'!
|
|
|
|
|
|
!TutorialsChapter methodsFor: 'accessing'!
|
|
|
|
|
|
-title
|
|
|
- ^'Tutorials'
|
|
|
+chapters
|
|
|
+ ^{ self firstAppChapter. self counterChapter }
|
|
|
!
|
|
|
|
|
|
contents
|
|
|
^'Here''s a serie of tutorials. If you are new to Smalltalk, you can also learn Amber online with [ProfStef](http://www.amber-lang.net/learn.html)'
|
|
|
!
|
|
|
|
|
|
-chapters
|
|
|
- ^{ self firstAppChapter. self counterChapter }
|
|
|
-!
|
|
|
-
|
|
|
-firstAppChapter
|
|
|
+counterChapter
|
|
|
^DocChapter new
|
|
|
- title: 'A first application';
|
|
|
+ title: 'The counter application';
|
|
|
contents: '
|
|
|
|
|
|
-Let''s make Hello World in Amber.
|
|
|
+This tutorial will teach you how to build HTML with Amber using jQuery and the HTMLCanvas API. It is freely adapted from
|
|
|
+the [Seaside counter example](http://www.seaside.st/about/examples/counter)
|
|
|
|
|
|
-First, you need a place for your new project. I made a new directory under amber:
|
|
|
+##The counter widget
|
|
|
|
|
|
- amber/projects/hello
|
|
|
+The counter is the most basic example of a widget. It allows to increment and decrement a number by clicking a button.
|
|
|
|
|
|
-This will store your project files. To get started, add a new index.html file to this folder, as well as empty js and st folders.
|
|
|
+Amber already comes with a counter example in the `Examples` package. To avoid class name conflict, we''ll name our counter class `TCounter`.
|
|
|
|
|
|
-Your index.html can be really basic. The most important thing it does is include amber.js and run loadAmber. Here is a basic index.html you can use:
|
|
|
+ Widget subclass: #TCounter
|
|
|
+ instanceVariableNames: ''count header''
|
|
|
+ package: ''Tutorials''
|
|
|
+
|
|
|
+The first method is used to initialize the component with the default state, in this case we set the counter to 0:
|
|
|
+
|
|
|
+ initialize
|
|
|
+ super initialize.
|
|
|
+ count := 0
|
|
|
+
|
|
|
+The method used for rendering a widget is `#renderOn:`. It takes an instance of HTMLCanvas as parameter.
|
|
|
+The `header` h1 kept as an instance variable, so when the count value change, we can update it''s contents accordingly.
|
|
|
+
|
|
|
+ renderOn: html
|
|
|
+ header := html h1
|
|
|
+ with: count asString;
|
|
|
+ yourself.
|
|
|
+ html button
|
|
|
+ with: ''++'';
|
|
|
+ onClick: [self increase].
|
|
|
+ html button
|
|
|
+ with: ''--'';
|
|
|
+ onClick: [self decrease]
|
|
|
+
|
|
|
+The counter is almost ready. All we need now is to implement the two action methods `#increase` and `#decrease` to change the state
|
|
|
+of our counter and update its header.
|
|
|
+
|
|
|
+ increase
|
|
|
+ count := count + 1.
|
|
|
+ header contents: [:html | html with: count asString]
|
|
|
+
|
|
|
+ decrease
|
|
|
+ count := count - 1.
|
|
|
+ header contents: [:html | html with: count asString]
|
|
|
+
|
|
|
+
|
|
|
+That''s it!! We can now display an instance of TCounter by rendering it on the page using jQuery:
|
|
|
+
|
|
|
+ TCounter new appendToJQuery: ''body'' asJQuery
|
|
|
+
|
|
|
+'
|
|
|
+!
|
|
|
+
|
|
|
+firstAppChapter
|
|
|
+ ^DocChapter new
|
|
|
+ title: 'A first application';
|
|
|
+ contents: '
|
|
|
+
|
|
|
+Let''s make Hello World in Amber.
|
|
|
+
|
|
|
+First, you need a place for your new project. I made a new directory under amber:
|
|
|
+
|
|
|
+ amber/projects/hello
|
|
|
+
|
|
|
+This will store your project files. To get started, add a new index.html file to this folder, as well as empty js and st folders.
|
|
|
+
|
|
|
+Your index.html can be really basic. The most important thing it does is include amber.js and run loadAmber. Here is a basic index.html you can use:
|
|
|
|
|
|
|
|
|
<!!DOCTYPE html>
|
|
@@ -699,60 +453,306 @@ From there, you can create new Smalltalk classes and messages to build up your a
|
|
|
'
|
|
|
!
|
|
|
|
|
|
-counterChapter
|
|
|
+title
|
|
|
+ ^'Tutorials'
|
|
|
+! !
|
|
|
+
|
|
|
+Object subclass: #DocumentationBuilder
|
|
|
+ instanceVariableNames: 'chapters announcer widget'
|
|
|
+ package: 'Documentation'!
|
|
|
+
|
|
|
+!DocumentationBuilder methodsFor: 'accessing'!
|
|
|
+
|
|
|
+announcer
|
|
|
+ ^announcer ifNil: [announcer := Announcer new]
|
|
|
+!
|
|
|
+
|
|
|
+chapters
|
|
|
+ ^chapters ifNil: [chapters := self buildChapters]
|
|
|
+!
|
|
|
+
|
|
|
+widget
|
|
|
+ ^widget ifNil: [widget := DocumentationWidget on: self]
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationBuilder methodsFor: 'building'!
|
|
|
+
|
|
|
+build
|
|
|
+ self buildOnJQuery: ('body' asJQuery)
|
|
|
+!
|
|
|
+
|
|
|
+buildChapters
|
|
|
+ ^((self class methodDictionary values sorted: [:a :b | a selector < b selector])
|
|
|
+ select: [:each | each category = 'chapters'])
|
|
|
+ collect: [:each | self perform: each selector]
|
|
|
+!
|
|
|
+
|
|
|
+buildOn: aCanvas
|
|
|
+ aCanvas with: self widget.
|
|
|
+ self
|
|
|
+ checkHashChange;
|
|
|
+ checkHash
|
|
|
+!
|
|
|
+
|
|
|
+buildOnJQuery: aJQuery
|
|
|
+ self buildOn: (HTMLCanvas onJQuery: aJQuery)
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationBuilder methodsFor: 'chapters'!
|
|
|
+
|
|
|
+ch1introduction
|
|
|
^DocChapter new
|
|
|
- title: 'The counter application';
|
|
|
+ title: 'Introduction';
|
|
|
contents: '
|
|
|
|
|
|
-This tutorial will teach you how to build HTML with Amber using jQuery and the HTMLCanvas API. It is freely adapted from
|
|
|
-the [Seaside counter example](http://www.seaside.st/about/examples/counter)
|
|
|
+##Amber Smalltalk in a nutshell
|
|
|
|
|
|
-##The counter widget
|
|
|
+Amber is an implementation of the Smalltalk-80 language. It is designed to make client-side web development **faster, easier and more fun** as it allows developers to write HTML5 applications in a live Smalltalk environment!!
|
|
|
|
|
|
-The counter is the most basic example of a widget. It allows to increment and decrement a number by clicking a button.
|
|
|
+Amber is written in itself, including the IDE and the compiler and it runs **directly inside your browser**. The IDE is fairly complete with a class browser, workspace, transcript, unit test runner, object inspectors, cross reference tools and even a debugger.
|
|
|
|
|
|
-Amber already comes with a counter example in the `Examples` package. To avoid class name conflict, we''ll name our counter class `TCounter`.
|
|
|
+Noteworthy features:
|
|
|
|
|
|
- Widget subclass: #TCounter
|
|
|
- instanceVariableNames: ''count header''
|
|
|
- package: ''Tutorials''
|
|
|
+- Amber is semantically and syntactically very close to [Pharo Smalltalk](http://www.pharo-project.org). Pharo is considered the reference implementation.
|
|
|
+- Amber **seamlessly interacts with JavaScript** and can use its full eco system of libraries without any glue code needed.
|
|
|
+- Amber **has no dependencies** and can be used in any JavaScript runtime, not only inside browsers. An important example is [Node.js](http://nodejs.org).
|
|
|
+- Amber is a live Smalltalk that **compiles incrementally into efficient JavaScript** often mapping one-to-one with JavaScript equivalents.
|
|
|
+- Amber has a **Seaside influenced canvas library** to dynamically generate HTML.
|
|
|
|
|
|
-The first method is used to initialize the component with the default state, in this case we set the counter to 0:
|
|
|
+## Arguments for using Amber
|
|
|
+In our humble opinion the main arguments for using Amber are:
|
|
|
|
|
|
- initialize
|
|
|
- super initialize.
|
|
|
- count := 0
|
|
|
+- JavaScript is quite a broken language with lots of traps and odd quirks. It is the assembler of the Internet which is cool, but we don''t want to write in it.
|
|
|
+- Smalltalk as a language is immensely cleaner and more mature, both syntactically and semantically.
|
|
|
+- Smalltalk has a simple class model with a lightweight syntax for closures, it is in many ways a perfect match for the Good Parts of JavaScript.
|
|
|
+- Having a true live interactive incremental development environment where you can build your application directly in the browser is unbeatable.
|
|
|
|
|
|
-The method used for rendering a widget is `#renderOn:`. It takes an instance of HTMLCanvas as parameter.
|
|
|
-The `header` h1 kept as an instance variable, so when the count value change, we can update it''s contents accordingly.
|
|
|
+## Disclaimer
|
|
|
|
|
|
- renderOn: html
|
|
|
- header := html h1
|
|
|
- with: count asString;
|
|
|
- yourself.
|
|
|
- html button
|
|
|
- with: ''++'';
|
|
|
- onClick: [self increase].
|
|
|
- html button
|
|
|
- with: ''--'';
|
|
|
- onClick: [self decrease]
|
|
|
+This documentation doesn''t aim to teach Smalltalk.
|
|
|
+Knowledge of Smalltalk is needed to understand the topics covered in this documentation.
|
|
|
+If you want to learn the Smalltalk language, you can read the excellent [Pharo By Example](http://www.pharobyexample.org) book.
|
|
|
+'
|
|
|
+!
|
|
|
|
|
|
-The counter is almost ready. All we need now is to implement the two action methods `#increase` and `#decrease` to change the state
|
|
|
-of our counter and update its header.
|
|
|
+ch2differencesWithOtherSmalltalks
|
|
|
+ ^DocChapter new
|
|
|
+ title: 'Differences with other Smalltalks';
|
|
|
+ contents: '
|
|
|
+Amber has some differences with other Smalltalk implementations. This makes porting code a non-trivial thing, but still quite manageable.
|
|
|
+Because it maps Smalltalk constructs one-to-one with the JavaScript equivalent, including Smalltalk classes to JavaScript constructors, the core class library is simplified compared to Pharo Smalltalk.
|
|
|
+And since we want Amber to be useful in building lean browser apps we can''t let it bloat too much.
|
|
|
|
|
|
- increase
|
|
|
- count := count + 1.
|
|
|
- header contents: [:html | html with: count asString]
|
|
|
+But apart from missing things other Smalltalks may have, there are also things that are plain different:
|
|
|
|
|
|
- decrease
|
|
|
- count := count - 1.
|
|
|
- header contents: [:html | html with: count asString]
|
|
|
+- The collection class hierarchy is much simpler compared to most Smalltalk implementations. In part this is because we want to map reasonably well with JavaScript counter parts.
|
|
|
+- As of today, there is no SortedCollection. The size of arrays is dynamic, and they behave like an ordered collection. They can also be sorted with the `#sort*` methods.
|
|
|
+- The `Date` class behaves like the `Date` and `TimeStamp` classes in Pharo Smalltalk. Therefore both `Date today` and `Date now` are valid in Amber.
|
|
|
+- Amber does not have class Character, but `String` does implement some of Character behavior so a single character String can work as a Character.
|
|
|
+- Amber does support **class instance variables**, but not class variables.
|
|
|
+- Amber only has global classes and packages, but not arbitrary objects. Use classes instead like `Smalltalk current` instead of `Smalltalk` etc.
|
|
|
+- Amber does not support pool dictionaries.
|
|
|
+- Amber uses **< ...javascript code... >** to inline JavaScript code and does not have pragmas.
|
|
|
+- Amber does not have class categories. The left side in the browser lists real Packages, but they feel much the same.
|
|
|
+'
|
|
|
+!
|
|
|
|
|
|
+ch3GettingStarted
|
|
|
+ ^DocChapter new
|
|
|
+ title: 'Getting started';
|
|
|
+ contents: '
|
|
|
+To get started hacking in Amber you can basically take three routes, independent of your platform:
|
|
|
|
|
|
-That''s it!! We can now display an instance of TCounter by rendering it on the page using jQuery:
|
|
|
+1. Just **try it out directly** at [www.amber-lang.net](http://www.amber-lang.net) - click the **Class browser** button there. But you will **not be able to save any code you write**!!
|
|
|
+ Still, it works fine for looking at the IDE and playing around. Just **don''t press F5/reload** - it will lose any code you have written.
|
|
|
+2. Download an Amber zip-ball, install [Nodejs](http://www.nodejs.org), fire up the Amber server and then open Amber from localhost - then you **can save code**. Detailed instructions are below!!
|
|
|
+3. Same as above but install git first and get a proper clone from [http://github.com/NicolasPetton/amber](http://github.com/NicolasPetton/amber) instead of a zip/tar-ball.
|
|
|
+ If you want to **contribute to Amber itself** this is really what you want to do. In fact, in most cases this is what you want to do. It requires installing git first, but it is quite simple - although we leave this bit as an "exercise to the reader" :)
|
|
|
|
|
|
- TCounter new appendToJQuery: ''body'' asJQuery
|
|
|
+**PLEASE NOTE:** Amber core developers use Linux.
|
|
|
+We do not want to introduce dependencies that aren''t cross platform - but currently amberc (the command line compiler) is a bash script and we also use Makefiles
|
|
|
+(for building Amber itself and server side examples) written on Linux/Unix. So using Windows is currently a bit limited - you can''t run "make" in the .st directory to rebuild whole of Amber for example.
|
|
|
+ BUT... if you only want to use Amber to build web client apps and not really get involved in hacking Amber itself - then you should be fine!!
|
|
|
+
|
|
|
+## Downloading Amber
|
|
|
+Currently you can download in zip or tar-ball format, either cutting edge or a release. [Downloads are available here](https://github.com/NicolasPetton/amber/archives/amber).
|
|
|
+
|
|
|
+Unpack wherever you like, but I would rename the directory that is unpacked to something slightly shorter - like say "amber". :)
|
|
|
+And yes, at this point you can double click the index.html file in the amber directory to get the IDE up, but again, **you will not be able to save code**. So please continue below :)
|
|
|
+
|
|
|
+## Installing Node.js
|
|
|
+[Node](http://www.nodejs.org) (for short) is simply the V8 Javascript VM from Google (used in Chrome) hooked together with some hard core C-libraries for doing "evented I/O".
|
|
|
+Basically it''s JavaScript for the server - on asynch steroids. Amber runs fine in Node and we use it for several Amber tools, like amberc (the command line Amber compiler) or the Amber server (see below).
|
|
|
+There are also several Amber-Node examples to look at if you want to play with running Amber programs server side. **In short - you really want to install Nodejs. :)**
|
|
|
|
|
|
+- Installing Node on Linux can be done using your package tool of choice (`apt-get install nodejs` for example) or any other way described at [the download page](http://nodejs.org/#download).
|
|
|
+- Installing Node on MacOS or Windows is probably done best by using the [installers available at Nodejs.org](http://nodejs.org/#download).
|
|
|
+
|
|
|
+## Starting Amber server
|
|
|
+Nicolas has written a minimal webDAV server that is the easiest way to get up and running Amber with the ability to save code. This little server is written in... Amber!!
|
|
|
+And it runs on top of Node. So to start it up serving your brand new directory tree of sweet Amber you do:
|
|
|
+
|
|
|
+ cd amber (or whatever you called the directory you unpackaged)
|
|
|
+ ./bin/server (in windows you type `node server\server.js` instead)
|
|
|
+
|
|
|
+It should say it is listening on port 4000. If it does, hooray!! That means both Node and Amber are good. In Windows you might get a question about opening that port in the local firewall - yep, do it!!
|
|
|
+
|
|
|
+## Firing up Amber
|
|
|
+The Amber IDE is written in... Amber. It uses [jQuery](http://jquery.com) and runs right in your browser as a ... well, a web page.
|
|
|
+We could open it up just using a file url - but the reason we performed the previous steps is so that we can load the IDE web page from a server that can handle PUTs (webDAV) of source code.
|
|
|
+According to web security Amber can only do PUT back to the same server it was loaded from. Thus we instead want to open it [through our little server now listening on port 4000](http://localhost:4000/index.html).
|
|
|
+Clicking that link and then pressing the **Class browser** should get your Amber IDE running with the ability to commit modified packages locally.
|
|
|
+
|
|
|
+To verify that you can indeed commit now - just select a Package in the browser, like say "Examples" and press the **Commit** button below. **If all goes well nothing happens :)**.
|
|
|
+So in order to really know if it worked we can check the modified date on the files **amber/st/Examples.st**, **amber/js/Examples.js** and **amber/js/Examples.deploy.js** - they should be brand new.
|
|
|
+
|
|
|
+NOTE: We can use any webDAV server and Apache2 has been used earlier and works fine. But the Amber server is smaller and simpler to start.
|
|
|
'
|
|
|
+!
|
|
|
+
|
|
|
+ch4Tutorials
|
|
|
+ ^TutorialsChapter new
|
|
|
+!
|
|
|
+
|
|
|
+ch5Index
|
|
|
+ ^ClassesIndexChapter new
|
|
|
+!
|
|
|
+
|
|
|
+ch6KernelObjects
|
|
|
+ ^PackageDocChapter on: (Package named: 'Kernel-Objects')
|
|
|
+!
|
|
|
+
|
|
|
+ch7KernelClasses
|
|
|
+ ^PackageDocChapter on: (Package named: 'Kernel-Classes')
|
|
|
+!
|
|
|
+
|
|
|
+ch8KernelCollection
|
|
|
+ ^PackageDocChapter on: (Package named: 'Kernel-Collections')
|
|
|
+!
|
|
|
+
|
|
|
+ch9KernelMethods
|
|
|
+ ^PackageDocChapter on: (Package named: 'Kernel-Methods')
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationBuilder methodsFor: 'routing'!
|
|
|
+
|
|
|
+checkHash
|
|
|
+ | hash presentation |
|
|
|
+ hash := document location hash replace: '^#' with: ''.
|
|
|
+ self announcer announce: (ChapterSelectionAnnouncement new
|
|
|
+ id: hash;
|
|
|
+ yourself)
|
|
|
+!
|
|
|
+
|
|
|
+checkHashChange
|
|
|
+ (window jQuery: window) bind: 'hashchange' do: [self checkHash]
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationBuilder methodsFor: 'updating'!
|
|
|
+
|
|
|
+update
|
|
|
+ chapters := nil.
|
|
|
+ announcer := nil.
|
|
|
+ widget := nil.
|
|
|
+ (window jQuery: '.documentation') remove.
|
|
|
+ self build
|
|
|
+! !
|
|
|
+
|
|
|
+DocumentationBuilder class instanceVariableNames: 'current'!
|
|
|
+
|
|
|
+!DocumentationBuilder class methodsFor: 'accessing'!
|
|
|
+
|
|
|
+current
|
|
|
+ ^current ifNil: [current := self new]
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationBuilder class methodsFor: 'initialization'!
|
|
|
+
|
|
|
+initialize
|
|
|
+ self current build
|
|
|
+! !
|
|
|
+
|
|
|
+Widget subclass: #DocumentationWidget
|
|
|
+ instanceVariableNames: 'builder selectedChapter chapterDiv'
|
|
|
+ package: 'Documentation'!
|
|
|
+
|
|
|
+!DocumentationWidget methodsFor: 'accessing'!
|
|
|
+
|
|
|
+builder
|
|
|
+ ^builder
|
|
|
+!
|
|
|
+
|
|
|
+builder: aDocumentationBuilder
|
|
|
+ builder := aDocumentationBuilder
|
|
|
+!
|
|
|
+
|
|
|
+chapters
|
|
|
+ ^self builder chapters
|
|
|
+!
|
|
|
+
|
|
|
+selectedChapter
|
|
|
+ ^selectedChapter ifNil: [selectedChapter := self chapters first]
|
|
|
+!
|
|
|
+
|
|
|
+selectedChapter: aChapter
|
|
|
+ ^selectedChapter := aChapter
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationWidget methodsFor: 'actions'!
|
|
|
+
|
|
|
+displayChapter: aChapter
|
|
|
+ self selectedChapter: aChapter.
|
|
|
+ self updateChapterDiv
|
|
|
+!
|
|
|
+
|
|
|
+selectChapter: aChapter
|
|
|
+ document location hash: aChapter id
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationWidget methodsFor: 'rendering'!
|
|
|
+
|
|
|
+renderChapterMenu: aChapter on: html
|
|
|
+ html a
|
|
|
+ with: aChapter title;
|
|
|
+ onClick: [
|
|
|
+ self selectChapter: aChapter].
|
|
|
+ html ol with: [
|
|
|
+ aChapter chapters do: [:each |
|
|
|
+ html li with: [
|
|
|
+ self renderChapterMenu: each on: html]]]
|
|
|
+!
|
|
|
+
|
|
|
+renderMenuOn: html
|
|
|
+ html div
|
|
|
+ class: 'menu';
|
|
|
+ with: [
|
|
|
+ html ol with: [
|
|
|
+ self chapters do: [:each |
|
|
|
+ html li with: [
|
|
|
+ self renderChapterMenu: each on: html]]]]
|
|
|
+!
|
|
|
+
|
|
|
+renderOn: html
|
|
|
+ html div
|
|
|
+ class: 'documentation';
|
|
|
+ with: [
|
|
|
+ self renderMenuOn: html.
|
|
|
+ chapterDiv := html div.
|
|
|
+ self updateChapterDiv]
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationWidget methodsFor: 'updating'!
|
|
|
+
|
|
|
+updateChapterDiv
|
|
|
+ chapterDiv contents: [:html |
|
|
|
+ html with: self selectedChapter]
|
|
|
+! !
|
|
|
+
|
|
|
+!DocumentationWidget class methodsFor: 'instance creation'!
|
|
|
+
|
|
|
+on: aBuilder
|
|
|
+ ^self new
|
|
|
+ builder: aBuilder;
|
|
|
+ yourself
|
|
|
! !
|
|
|
|