diff --git a/Chapters/08-Tasks/tasks.md b/Chapters/08-Tasks/tasks.md
index cd37c13..c6c3e56 100644
--- a/Chapters/08-Tasks/tasks.md
+++ b/Chapters/08-Tasks/tasks.md
@@ -1,7 +1,30 @@
-## Tasks
@cha:tasks
% +Embedding a ContactView into another component.>file://figures/iAddress-ListAndEditor.png|width=80|label=ref:listAndItem+
In Seaside, it is possible to define components whose responsibility is to represent the flow of control between existing components. These components are called tasks. In this chapter, we explain how you can define a task. We also show how Seaside supports application control flow by isolating certain paths from others. We will start by presenting a little game, the number guessing game. Then, we will implement two small hotel registration applications using the calendar component to illustrate tasks.
### Sequencing Components
Tasks are used to encapsulate a process or control flow. They do not directly render XHTML, but may do so via the components that they call. Tasks are defined as subclasses of `WATask`, which implements the key method `WATask>>go`, which is invoked as soon as a task is displayed and can call other components.
Let's start by building our first example: a number guessing game \(which was one of the first Seaside tutorials\). In this game, the computer selects a random number between 1 and 100 and then proceeds to repeatedly prompt the user for a guess. The computer reports whether the guess is too high or too low. The game ends when the user guesses the number.
!!note Those of you who remember learning to program in BASIC will recognise this as one of the common exercises to demonstrate simple user interaction. As you will see below, in Seaside it remains a simple exercise, despite the addition of the web layer. This comes as a stark contrast to other web development frameworks, which would require pages of boilerplate code to deliver such straightforward functionality.
We create a subclass of `WATask` and implement the `go` method:
```
WATask subclass: #GuessingGameTask
- instanceVariableNames: ''
- classVariableNames: ''
- package: 'SeasideBook'
```
```
GuessingGameTask >> go
+## Tasks
+
+@cha:tasks
+
+% +Embedding a ContactView into another component.>file://figures/iAddress-ListAndEditor.png|width=80|anchor=ref:listAndItem+
+
+In Seaside, it is possible to define components whose responsibility is to represent the flow of control between existing components. These components are called tasks. In this chapter, we explain how you can define a task. We also show how Seaside supports application control flow by isolating certain paths from others. We will start by presenting a little game, the number guessing game. Then, we will implement two small hotel registration applications using the calendar component to illustrate tasks.
+
+### Sequencing Components
+
+
+Tasks are used to encapsulate a process or control flow. They do not directly render XHTML, but may do so via the components that they call. Tasks are defined as subclasses of `WATask`, which implements the key method `WATask>>go`, which is invoked as soon as a task is displayed and can call other components.
+
+Let's start by building our first example: a number guessing game \(which was one of the first Seaside tutorials\). In this game, the computer selects a random number between 1 and 100 and then proceeds to repeatedly prompt the user for a guess. The computer reports whether the guess is too high or too low. The game ends when the user guesses the number.
+
+!!note Those of you who remember learning to program in BASIC will recognise this as one of the common exercises to demonstrate simple user interaction. As you will see below, in Seaside it remains a simple exercise, despite the addition of the web layer. This comes as a stark contrast to other web development frameworks, which would require pages of boilerplate code to deliver such straightforward functionality.
+
+We create a subclass of `WATask` and implement the `go` method:
+
+```
+WATask << #GuessingGameTask
+ package: 'SeasideBook'
+```
+
+
+```
+GuessingGameTask >> go
| number guess |
number := 100 atRandom.
[ guess := (self request: 'Enter your guess') asNumber.
@@ -10,17 +33,63 @@
guess > number
ifTrue: [ self inform: 'Your guess was too high' ].
guess = number ] whileFalse.
- self inform: 'You got it!'
```
The method `go` randomly draws a number. Then, it asks the user to guess a number and gives feedback depending on the input number. The methods `request:` and `inform:` create components \(`WAInputDialog` and `WAFormDialog`\) on the fly, which are then displayed by the task. Note that unlike the components we've developed previously, this class has no `renderContentOn:` method, just the method `go`. Its purpose is to drive the user through a sequence of steps.
Register the application \(as 'guessinggame'\) and give it a go. Figure *@ref:game-interaction@* shows a typical execution.
![Guessing Game interaction.](figures/GuessingGame.png width=80&label=ref:game-interaction)
Why not try modifying the game to count the number of guesses that were needed?
This example demonstrates that with Seaside you can use plain Smalltalk code \(conditionals, loops, etc.,\) to define the control flow of your application. You do not have to use yet another language or build a scary XML state-machine, as required in other frameworks. In some sense, tasks are simply components that start their life in a callback.
Because tasks are indeed components \(`WATask` is a subclass of `WAComponent`\), all of the facilities available to components, such as `call:` and `answer:` messages, are available to tasks as well. This allows you to combine components and tasks, so your `LoginUserComponent` can call a `RegisterNewUserTask`, and so on.
!!note Important Tasks do not render themselves. Don't override `renderContentOn:` in your tasks. Their purpose is simply to sequence through other views.
!!note Important If you are reusing components in a task -- that is, you store them in instance variables instead of creating new instances in the `go` method -- be sure to return these instances in the #children method so that they are backtracked properly and you get the correct control flow.
### Hotel Reservation: Tasks vs. Components
To compare when to use a task or a component, let's build a minimal hotel reservation application using a task and a component with children. Using a task, it is easy to reuse components and build a flow. Here is a small application that illustrates how to do this. We want to ask the user to specify starting and ending reservation dates. We will define a new subclass of `WATask` with two instance variables `startDate` and `endDate` of the selected period.
```
WATask subclass: #HotelTask
- instanceVariableNames: 'startDate endDate'
- classVariableNames: ''
- package: 'Calendars'
```
We define a method `go` that will first create a calendar with selectable dates after today, then create a second calendar with selectable days after the one selected during the first interaction, and finally we will display the dates selected as shown in *@ref:hotel@*.
```
HotelTask >> go
+ self inform: 'You got it!'
+```
+
+
+
+The method `go` randomly draws a number. Then, it asks the user to guess a number and gives feedback depending on the input number. The methods `request:` and `inform:` create components \(`WAInputDialog` and `WAFormDialog`\) on the fly, which are then displayed by the task. Note that unlike the components we've developed previously, this class has no `renderContentOn:` method, just the method `go`. Its purpose is to drive the user through a sequence of steps.
+
+Register the application \(as 'guessinggame'\) and give it a go. Figure *@ref:game-interaction@* shows a typical execution.
+
+![Guessing Game interaction. %width=80&anchor=ref:game-interaction](figures/GuessingGame.png )
+
+Why not try modifying the game to count the number of guesses that were needed?
+
+This example demonstrates that with Seaside you can use plain Smalltalk code \(conditionals, loops, etc.,\) to define the control flow of your application. You do not have to use yet another language or build a scary XML state-machine, as required in other frameworks. In some sense, tasks are simply components that start their life in a callback.
+
+Because tasks are indeed components \(`WATask` is a subclass of `WAComponent`\), all of the facilities available to components, such as `call:` and `answer:` messages, are available to tasks as well. This allows you to combine components and tasks, so your `LoginUserComponent` can call a `RegisterNewUserTask`, and so on.
+
+!!note Important Tasks do not render themselves. Don't override `renderContentOn:` in your tasks. Their purpose is simply to sequence through other views.
+
+!!note Important If you are reusing components in a task -- that is, you store them in instance variables instead of creating new instances in the `go` method -- be sure to return these instances in the #children method so that they are backtracked properly and you get the correct control flow.
+
+
+### Hotel Reservation: Tasks vs. Components
+
+
+To compare when to use a task or a component, let's build a minimal hotel reservation application using a task and a component with children. Using a task, it is easy to reuse components and build a flow. Here is a small application that illustrates how to do this. We want to ask the user to specify starting and ending reservation dates. We will define a new subclass of `WATask` with two instance variables `startDate` and `endDate` of the selected period.
+
+```
+WATask << #HotelTask
+ slots: { #startDate . #endDate};
+ package: 'Calendars'
+```
+
+
+We define a method `go` that will first create a calendar with selectable dates after today, then create a second calendar with selectable days after the one selected during the first interaction, and finally we will display the dates selected as shown in Figure *@ref:hotel@*.
+
+```
+HotelTask >> go
startDate := self call: (WAMiniCalendar new
canSelectBlock: [ :date | date > Date today ]).
endDate := self call: (WAMiniCalendar new
canSelectBlock: [ :date | startDate isNil or: [ startDate < date ] ]).
self inform: 'from ' , startDate asString , ' to ' ,
endDate asString , ' ' , (endDate - startDate) days asString ,
- ' days'
```
![ A simple reservation based on task.](figures/hotel.png width=80&label=ref:hotel)
Note that you could add a confirmation step and loop until the user is OK with his reservation.
Now this solution is not satisfying because the user cannot see both calendars while making his selection. Since we can't render components in our task, it's not easy to remedy the situation. We could use the message `addMessage: aString` to add a message to a component but this is still not good enough. This example demonstrates that tasks are about flow and not about presentation.
```
HotelTask >> go
+ ' days'
+```
+
+
+![ A simple reservation based on task. % width=80&anchor=ref:hotel](figures/hotel.png)
+
+
+Note that you could add a confirmation step and loop until the user is OK with his reservation.
+
+Now this solution is not satisfying because the user cannot see both calendars while making his selection. Since we can't render components in our task, it's not easy to remedy the situation. We could use the message `addMessage: aString` to add a message to a component but this is still not good enough. This example demonstrates that tasks are about flow and not about presentation.
+
+```
+HotelTask >> go
startDate := self call: (WAMiniCalendar new
canSelectBlock: [ :date | date > Date today ];
addMessage: 'Select your starting date';
@@ -30,11 +99,34 @@
addMessage: 'Select your leaving date';
yourself).
self inform: (endDate - startDate) days asString , ' days: from ' ,
- startDate asString , ' to ' , endDate asString , ' '
```
### Mini Inn: Embedding Components
Let's solve the same problem using component embedding. We define a component with two calendars and two dates. The idea is that we want to always have the two mini-calendars visible on the same page and provide some feedback to the user as shown by *@ref:resa@*.
```
WAComponent subclass: #MiniInn
- instanceVariableNames: 'calendar1 calendar2 startDate endDate'
- classVariableNames: ''
- package: 'Calendars'
```
Since we want to show the two calendars on the same page we return them as children.
```
MiniInn >> children
- ^ Array with: calendar1 with: calendar2
```
We initialize the calendars and make sure that we store the results of their answers.
```
MiniInn >> initialize
+ startDate asString , ' to ' , endDate asString , ' '
+```
+
+
+### Mini Inn: Embedding Components
+
+
+Let's solve the same problem using component embedding. We define a component with two calendars and two dates. The idea is that we want to always have the two mini-calendars visible on the same page and provide some feedback to the user as shown by *@ref:resa@*.
+
+```
+WAComponent << #MiniInn
+ slots: { #calendar1 . #calendar2 . #startDate . #endDate};
+ package: 'Calendars'
+```
+
+
+Since we want to show the two calendars on the same page we return them as children.
+
+```
+MiniInn >> children
+ ^ Array with: calendar1 with: calendar2
+```
+
+
+We initialize the calendars and make sure that we store the results of their answers.
+
+```
+MiniInn >> initialize
super initialize.
calendar1 := WAMiniCalendar new.
calendar1
@@ -43,7 +135,14 @@
calendar2 := WAMiniCalendar new.
calendar2
canSelectBlock: [ :date | startDate isNil or: [ startDate < date ] ];
- onAnswer: [ :date | endDate := date ]
```
Finally, we render the application, and this time we can provide some simple feedback to the user. The feedback is simple but this is just to illustrate our point.
```
MiniInn >> renderContentOn: html
+ onAnswer: [ :date | endDate := date ]
+```
+
+
+Finally, we render the application, and this time we can provide some simple feedback to the user. The feedback is simple but this is just to illustrate our point.
+
+```
+MiniInn >> renderContentOn: html
html heading: 'Starting date'.
html render: calendar1.
startDate isNil
@@ -53,4 +152,17 @@
(startDate isNil not and: [ endDate isNil not ]) ifTrue: [
html text: (endDate - startDate) days asString ,
' days from ' , startDate asString , ' to ' ,
- endDate asString , ' ' ]
```
![A simple reservation with feedback.](figures/resa.png width=80&label=ref:resa)
### Summary
In this chapter, we presented tasks, subclasses of Task. Tasks are components that do not render themselves but are used to build application flow based on the composition of other components. We saw that the composition is expressed in plain Pharo.
\ No newline at end of file
+ endDate asString , ' ' ]
+```
+
+
+![A simple reservation with feedback. % width=80&anchor=ref:resa](figures/resa.png)
+
+### Summary
+
+In this chapter, we presented tasks, subclasses of `Task`. Tasks are components that do not render themselves but are used to build application flow based on the composition of other components. We saw that the composition is expressed in plain Pharo.
+
+
+
+
+
diff --git a/Chapters/09-Slime/slime.md b/Chapters/09-Slime/slime.md
index d0528d0..9d61e83 100644
--- a/Chapters/09-Slime/slime.md
+++ b/Chapters/09-Slime/slime.md
@@ -1 +1,63 @@
-## Writing good Seaside Code
@cha:slime
This short chapter explains how you can improve the quality of your code and your programming skills in general by running _Slime_, a Seaside-specific code critics tool. For example, Slime can detect if you do not follow the canonical forms for brush usage that we presented in Chapter . It will also help you identify other potential bugs early on, and help you produce better code. Furthermore, if you work on a Seaside library, it is able to point out portability issues between the different Smalltalk dialects.
### A Seaside Program Checker
Slime analyzes your Seaside code and reveals potential problems. Slime is an extension of _Code Critics_ that is shipped with the _Refactoring Browser_. Code Critics, also called _SmallLint_, is available with the Refactoring Browser originally developed by John Brant and Don Roberts. Lukas Renggli and the Seaside community extended Code Critics to check common errors or bad style in Seaside code. The refactoring tools and Slime are available in the One-Click Image and we encourage you to use them to improve your code quality.
Pay attention that the rules are not bulletproof and by no means complete. It could well be that you encounter false positives or places where it misses some serious problems, but it should give you an idea where your code might need some further investigation.
Here are some of the problems that Slime detects:
**Possible Bugs.** This group of rules detects severe problems that are most certainly serious bugs in the source code:
- The message `with:` is not last in the cascade,
- Instantiates new component while generating HTML,
- Manually invokes `renderContentOn:`,
- Uses the wrong output stream,
- Misses call to super implementation,
- Calls functionality not available while generating output, and
- Calls functionality not available within a framework callback.
**Bad style.** These rules detect some less severe problems that might pose maintainability problems in the future but that do not cause immediate bugs.
- Extract callback code to separate method,
- Use of deprecated API, and
- Non-standard object initialization.
**Suboptimal Code.** This set of rules suggests optimization that can be applied to code without changing its behavior.
- Unnecessary block passed to brush.
**Non-Portable Code.** While this set of rules is less important for application code, it is central to the Seaside code base itself. The framework runs without modification on many different Smalltalk platforms, which differ in the syntax and the libraries they support. To avoid that contributors from a specific platform accidentally submit code that only works with their platform we've added some rules that check for compatibility. The rules in this category include:
- Invalid object initialization,
- Uses curly brace arrays,
- Uses literal byte arrays,
- Uses method annotations,
- Uses non-portable class,
- Uses non-portable message,
- ANSI booleans,
- ANSI collections,
- ANSI conditionals,
- ANSI convertor,
- ANSI exceptions, and
- ANSI streams.
### Summary
In this chapter, we presented tasks, subclasses of Task. Tasks are components that do not render themselves but are used to build application flow based on the composition of other components. We saw that the composition is expressed in plain Pharo.
\ No newline at end of file
+## Writing good Seaside Code
+@cha:slime
+
+This short chapter explains how you can improve the quality of your code and your programming skills in general by running _Slime_, a Seaside-specific code critics tool. For example, Slime can detect if you do not follow the canonical forms for brush usage that we presented in Chapter XXX. It will also help you identify other potential bugs early on, and help you produce better code. Furthermore, if you work on a Seaside library, it is able to point out portability issues between the different Smalltalk dialects.
+
+### A Seaside Program Checker
+
+
+Slime analyzes your Seaside code and reveals potential problems. Slime is an extension of _Code Critics_ that is shipped with the _Refactoring Browser_. Code Critics, also called _SmallLint_, is available with the Refactoring Browser originally developed by John Brant and Don Roberts. Lukas Renggli and the Seaside community extended Code Critics to check common errors or bad style in Seaside code. The refactoring tools and Slime are available in the One-Click Image and we encourage you to use them to improve your code quality.
+
+Pay attention that the rules are not bulletproof and by no means complete. It could well be that you encounter false positives or places where it misses some serious problems, but it should give you an idea where your code might need some further investigation.
+
+Here are some of the problems that Slime detects:
+
+**Possible Bugs.** This group of rules detects severe problems that are most certainly serious bugs in the source code:
+
+- The message `with:` is not last in the cascade,
+- Instantiates new component while generating HTML,
+- Manually invokes `renderContentOn:`,
+- Uses the wrong output stream,
+- Misses call to super implementation,
+- Calls functionality not available while generating output, and
+- Calls functionality not available within a framework callback.
+
+
+**Bad style.** These rules detect some less severe problems that might pose maintainability problems in the future but that do not cause immediate bugs.
+
+- Extract callback code to separate method,
+- Use of deprecated API, and
+- Non-standard object initialization.
+
+
+**Suboptimal Code.** This set of rules suggests optimization that can be applied to code without changing its behavior.
+
+- Unnecessary block passed to brush.
+
+
+**Non-Portable Code.** While this set of rules is less important for application code, it is central to the Seaside code base itself. The framework runs without modification on many different Smalltalk platforms, which differ in the syntax and the libraries they support. To avoid that contributors from a specific platform accidentally submit code that only works with their platform we've added some rules that check for compatibility. The rules in this category include:
+
+- Invalid object initialization,
+- Uses curly brace arrays,
+- Uses literal byte arrays,
+- Uses method annotations,
+- Uses non-portable class,
+- Uses non-portable message,
+- ANSI booleans,
+- ANSI collections,
+- ANSI conditionals,
+- ANSI convertor,
+- ANSI exceptions, and
+- ANSI streams.
+
+
+
+### Summary
+
+
+In this chapter, we presented tasks, subclasses of Task. Tasks are components that do not render themselves but are used to build application flow based on the composition of other components. We saw that the composition is expressed in plain Pharo.
+
+
+
+
+
diff --git a/Chapters/11-Sudoko/sudoko.md b/Chapters/11-Sudoko/sudoko.md
index a3953b6..df64d4f 100644
--- a/Chapters/11-Sudoko/sudoko.md
+++ b/Chapters/11-Sudoko/sudoko.md
@@ -1,15 +1,82 @@
-## A Web Sudoku Player
@cha:sudoko
In this chapter we will build a Sudoku web application as shown in Figure *@fig:upTo6@*. This gives us another opportunity to revisit how we build a simple application in Seaside.
![Just started playing.](figures/upTo6.png width=70&label=fig:upTo6)
### The solver
For the Sudoku model we use the ML-Sudoku package developed by Martin Laubach which is available on SqueakSource. We thank him for allowing us to use this material. To load the package, open a Monticello browser and click on the _+Repository_ button. Select HTTP as the type of repository and specify it as follows:
```
MCHttpRepository
+## A Web Sudoku Player
+
+@cha:sudoko
+
+In this chapter we will build a Sudoku web application as shown in Figure *@fig:upTo6@*. This gives us another opportunity to revisit how we build a simple application in Seaside.
+
+![Just started playing. %width=70&anchor=fig:upTo6](figures/upTo6.png )
+
+
+### The solver
+
+
+For the Sudoku model we use the ML-Sudoku package developed by Martin Laubach which is available on SqueakSource. We thank him for allowing us to use this material. To load the package, open a Monticello browser and click on the _+Repository_ button. Select HTTP as the type of repository and specify it as follows:
+
+
+```
+MCHttpRepository
location: 'http://www.squeaksource.com/MLSudoku'
user: ''
- password: ''
```
Click on the _Open_ button, select the most recent version and click _Load_.
ML-Sudoku is composed of 4 classes: `MLSudoku`, `MLBoard`, `MLCell`, and `MLPossibilitySet`. The class responsibilities are distributed as follows:
- `MLSudoku` is the Sudoku solver. It knows how to solve a Sudoku.
- `MLCell` knows its neighbors and their location on the game board. A cell does not know its possibility set, see `MLPossibilitySet` below.
- `MLBoard` contains the cells and their possibility sets.
- ` MLPossibilitySet` is a list of possible numbers between 1 and 9 that can go into a cell. These are the values that are possible without violating the Sudoku rule that each row, column and 3-by-3 sub-grid contains each number once.
### Sudoku
First we define the class `WebSudoku` which is the Sudoku UI. We will create this class in the new `ML-WebSudoku` category:
```
WAComponent subclass: #WebSudoku
- instanceVariableNames: 'sudoku'
- classVariableNames: ''
- package: 'ML-WebSudoku'
```
This component will contain a Sudoku solver \(an instance of `MLSudoku`\) which we will refer to using the instance variable `sudoku`. We initialize this variable by defining the following `WebSudoku>>initialize` method.
```
WebSudoku >> initialize
+ password: ''
+```
+
+
+Click on the _Open_ button, select the most recent version and click _Load_.
+
+ML-Sudoku is composed of 4 classes: `MLSudoku`, `MLBoard`, `MLCell`, and `MLPossibilitySet`. The class responsibilities are distributed as follows:
+
+- `MLSudoku` is the Sudoku solver. It knows how to solve a Sudoku.
+- `MLCell` knows its neighbors and their location on the game board. A cell does not know its possibility set, see `MLPossibilitySet` below.
+- `MLBoard` contains the cells and their possibility sets.
+- ` MLPossibilitySet` is a list of possible numbers between 1 and 9 that can go into a cell. These are the values that are possible without violating the Sudoku rule that each row, column and 3-by-3 sub-grid contains each number once.
+
+
+### Sudoku
+
+
+First we define the class `WebSudoku` which is the Sudoku UI. We will create this class in the new `ML-WebSudoku` category:
+
+```
+WAComponent << #WebSudoku
+ slots: {sudoku};
+ package: 'ML-WebSudoku'
+```
+
+
+This component will contain a Sudoku solver \(an instance of `MLSudoku`\) which we will refer to using the instance variable `sudoku`. We initialize this variable by defining the following `WebSudoku>>initialize` method.
+
+```
+WebSudoku >> initialize
super initialize.
- sudoku := MLSudoku new
```
**Describing and registering the application.** Now we add a few methods to the _class_ side of our component. We describe the application by defining the `description` method. We register our component as an application by defining the class `initialize` method and declare that the component `WebSudoku` can be a standalone application by having `canBeRoot` return true:
```
WebSudoku class >> description
- ^ 'Play Sudoku'
```
```
WebSudoku class >> initialize
- WAAdmin register: self asApplicationAt: 'sudoku'
```
```
WebSudoku class >> canBeRoot
- ^ true
```
Finally we define a CSS style for the Sudoku component:
```
WebSudoku >> style
+ sudoku := MLSudoku new
+```
+
+
+**Describing and registering the application.** Now we add a few methods to the _class_ side of our component. We describe the application by defining the `description` method. We register our component as an application by defining the class `initialize` method and declare that the component `WebSudoku` can be a standalone application by having `canBeRoot` return true:
+
+```
+WebSudoku class >> description
+ ^ 'Play Sudoku'
+```
+
+
+
+```
+WebSudoku class >> initialize
+ WAAdmin register: self asApplicationAt: 'sudoku'
+```
+
+
+```
+WebSudoku class >> canBeRoot
+ ^ true
+```
+
+
+Finally we define a CSS style for the Sudoku component:
+
+```
+WebSudoku >> style
^ '#sudokuBoard .sudokuHeader {
font-weight: bold;
color: white;
@@ -47,23 +114,80 @@
#sudokuBoard a:hover {
color: black;
-}'
```
### Rendering the Sudoku Grid
What we need to do is to render a table that looks like a Sudoku grid. We start by defining a method that creates a table and uses style tags for formatting.
```
WebSudoku >> renderHeaderFor: aString on: html
+}'
+```
+
+
+### Rendering the Sudoku Grid
+
+
+What we need to do is to render a table that looks like a Sudoku grid. We start by defining a method that creates a table and uses style tags for formatting.
+
+```
+WebSudoku >> renderHeaderFor: aString on: html
html tableData
class: 'sudokuHeader';
class: 'sudokuHBorder';
class: 'sudokuVBorder';
- with: aString
```
```
WebSudoku >> renderContentOn: html
- self renderHeaderFor: 'This is a test' on: html
```
Make sure that you invoked the class side `initialize` method and then run the application by visiting [http://localhost:8080/sudoku](http://localhost:8080/sudoku). Your browser should display the string _This is a test_.
We need two helper methods when creating the labels for the `x` and `y` axis of our Sudoku grid. You don't need to actually add these helper methods yourself, they were already loaded when you loaded the Sudoku package:
```
Integer >> asSudokuCol
+ with: aString
+```
+
+
+```
+WebSudoku >> renderContentOn: html
+ self renderHeaderFor: 'This is a test' on: html
+```
+
+
+Make sure that you invoked the class side `initialize` method and then run the application by visiting [http://localhost:8080/sudoku](http://localhost:8080/sudoku). Your browser should display the string _This is a test_.
+
+We need two helper methods when creating the labels for the `x` and `y` axis of our Sudoku grid. You don't need to actually add these helper methods yourself, they were already loaded when you loaded the Sudoku package:
+
+```
+Integer >> asSudokuCol
"Label for columns"
- ^ ($1 to: $9) at: self
```
```
Integer >> asSudokuRow
+ ^ ($1 to: $9) at: self
+```
+
+
+```
+Integer >> asSudokuRow
"Label for rows"
- ^ ($A to: $I) at: self
```
First we print a space to get our labels aligned and then draw the label for each column.
```
WebSudoku >> renderBoardOn: html
+ ^ ($A to: $I) at: self
+```
+
+
+First we print a space to get our labels aligned and then draw the label for each column.
+
+```
+WebSudoku >> renderBoardOn: html
html table: [
html tableRow: [
self renderHeaderFor: '' on: html.
1 to: 9 do: [ :col |
- self renderHeaderFor: col asSudokuCol on: html ] ] ]
```
We make sure that the method `WebSudoku>>renderContentOn:` invokes the board rendering method we just defined.
```
WebSudoku >> renderContentOn: html
- self renderBoardOn: html
```
% +rowOfNumbers|width=50%+
![The column labels look like this.](figures/rowofnumbers.png width=60&label=fig:rowOfNumbers)
If you run the application again, you should see the column labels as shown in Figure *@fig:rowOfNumbers@*.
We now draw each row with its label, identifying the cells with the product of its row and column number.
```
WebSudoku >> renderBoardOn: html
+ self renderHeaderFor: col asSudokuCol on: html ] ] ]
+```
+
+
+We make sure that the method `WebSudoku>>renderContentOn:` invokes the board rendering method we just defined.
+
+```
+WebSudoku >> renderContentOn: html
+ self renderBoardOn: html
+```
+
+
+
+
+![The column labels look like this. % width=60&anchor=fig:rowOfNumbers](figures/rowofnumbers.png)
+
+
+If you run the application again, you should see the column labels as shown in Figure *@fig:rowOfNumbers@*.
+
+We now draw each row with its label, identifying the cells with the product of its row and column number.
+
+```
+WebSudoku >> renderBoardOn: html
html table: [
html tableRow: [
self renderHeaderFor: '' on: html.
@@ -72,13 +196,40 @@
html tableRow: [
self renderHeaderFor: row asSudokuRow on: html.
1 to: 9 do: [ :col |
- html tableData: (col * row) asString ] ] ] ]
```
If you have entered everything correctly, your page should now look like Figure *@fig:tableOfNumbers@*.
% +tableOfNumbers|width=50%+
![Row labels are letters, column labels are numbers.](figures/table-of-numbers.png width=50&label=fig:tableOfNumbers)
Now we define the method `renderCellAtRow:col:on:` that sets the style tags and redefine the `renderContentOn:` as follows so that it uses our style sheet.
```
WebSudoku >> renderContentOn: html
+ html tableData: (col * row) asString ] ] ] ]
+```
+
+
+If you have entered everything correctly, your page should now look like Figure *@fig:tableOfNumbers@*.
+
+% +tableOfNumbers|width=50%+
+
+![Row labels are letters, column labels are numbers. %width=50&anchor=fig:tableOfNumbers](figures/table-of-numbers.png )
+
+
+
+Now we define the method `renderCellAtRow:col:on:` that sets the style tags and redefine the `renderContentOn:` as follows so that it uses our style sheet.
+
+```
+WebSudoku >> renderContentOn: html
html div
id: 'sudokuBoard';
- with: [ self renderBoardOn: html ]
```
```
WebSudoku >> renderCellAtRow: rowInteger col: colInteger on: html
+ with: [ self renderBoardOn: html ]
+```
+
+
+```
+WebSudoku >> renderCellAtRow: rowInteger col: colInteger on: html
html tableData
class: 'sudokuHBorder' if: rowInteger \\ 3 == 0;
- class: 'sudokuVBorder' if: colInteger \\ 3 == 0
```
You also need to change `WebSudoku>>renderBoardOn:` so that it uses our new method `WebSudoku>>renderCellAtRow:col:on:`.
```
WebSudoku >> renderBoardOn: html
+ class: 'sudokuVBorder' if: colInteger \\ 3 == 0
+```
+
+
+You also need to change `WebSudoku>>renderBoardOn:` so that it uses our new method `WebSudoku>>renderCellAtRow:col:on:`.
+
+```
+WebSudoku >> renderBoardOn: html
html table: [
html tableRow: [
self renderHeaderFor: '' on: html.
@@ -86,11 +237,32 @@
1 to: 9 do: [ :row |
html tableRow: [
self renderHeaderFor: row asSudokuRow on: html.
- 1 to: 9 do: [ :col | self renderCellAtRow: row col: col on: html ] ] ] ]
```
If you refresh your page again, you should finally see a styled Sudoku grid as show in *@fig:empty-sudoku@*.
% +empty-sudoku|width=70%+
![The Sudoku board with the style sheet applied.](figures/empty.png width=70&label=fig:empty-sudoku)
Next we will use a small helper method `asCompactString` that given a collection returns a string containing all the elements printed one after the other without spaces. Again, you do not need to type this method, it was loaded with the ML-Sudoku code.
```
Collection >> asCompactString
+ 1 to: 9 do: [ :col | self renderCellAtRow: row col: col on: html ] ] ] ]
+```
+
+
+If you refresh your page again, you should finally see a styled Sudoku grid as shown in Figure *@fig:empty-sudoku@*.
+
+% +empty-sudoku|width=70%+
+
+![The Sudoku board with the style sheet applied. % width=70&anchor=fig:empty-sudoku](figures/empty.png)
+
+
+Next we will use a small helper method `asCompactString` that given a collection returns a string containing all the elements printed one after the other without spaces. Again, you do not need to type this method, it was loaded with the ML-Sudoku code.
+
+```
+Collection >> asCompactString
| stream |
stream := WriteStream on: String new.
self do: [ :each | ws nextPutAll: each printString ].
- ^ stream contents
```
We define a new method `renderCellContentAtRow:col:on:` that uses `asCompactString` to display the contents of a cell. Each cell displays its possibility set. These are the values that may legally appear in that cell.
```
WebSudoku >> renderCellContentAtRow: rowInteger col: colInteger on: html
+ ^ stream contents
+```
+
+
+We define a new method `renderCellContentAtRow:col:on:` that uses `asCompactString` to display the contents of a cell. Each cell displays its possibility set. These are the values that may legally appear in that cell.
+
+```
+WebSudoku >> renderCellContentAtRow: rowInteger col: colInteger on: html
| currentCell possibilites |
currentCell := MLCell row: rowInteger col: colInteger.
possibilites := sudoku possibilitiesAt: currentCell.
@@ -99,12 +271,39 @@
ifFalse: [
html span
class: 'sudokuPossibilities';
- with: possibilites asCompactString ]
```
We make sure that the `renderCellAtRow:col:on:` invokes the method rendering cell contents.
```
WebSudoku >> renderCellAtRow: rowInteger col: colInteger on: html
+ with: possibilites asCompactString ]
+```
+
+
+We make sure that the `renderCellAtRow:col:on:` invokes the method rendering cell contents.
+
+```
+WebSudoku >> renderCellAtRow: rowInteger col: colInteger on: html
html tableData
class: 'sudokuHBorder' if: rowInteger \\ 3 = 0;
class: 'sudokuVBorder' if: colInteger \\ 3 = 0;
- with: [ self renderCellContentAtRow: rowInteger col: colInteger on: html ]
```
Refresh your application again, and your grid should appear as in *@fig:with-possibilities@*.
% +with-possibilities|width=80%+
![The Sudoku grid is showing the possible values for each cell.](figures/incomplete.png width=70&label=fig:with-possibilities)
### Adding Input
Now we will change our application so that we can enter numbers into the cells of the Sudoku grid. We define the method `setCell:to:` that changes the state of a cell and we extend the method `renderCellContentAtRow:col:on:` to use this new method.
```
WebSudoku >> setCell: aCurrentCell to: anInteger
- sudoku atCell: aCurrentCell removeAllPossibilitiesBut: anInteger
```
```
WebSudoku >> renderCellContentAtRow: rowInteger col: colInteger on: html
+ with: [ self renderCellContentAtRow: rowInteger col: colInteger on: html ]
+```
+
+Refresh your application again, and your grid should appear as in *@fig:with-possibilities@*.
+
+% +with-possibilities|width=80%+
+![The Sudoku grid is showing the possible values for each cell. % width=70&anchor=fig:with-possibilities](figures/incomplete.png)
+
+
+### Adding Input
+
+
+Now we will change our application so that we can enter numbers into the cells of the Sudoku grid. We define the method `setCell:to:` that changes the state of a cell and we extend the method `renderCellContentAtRow:col:on:` to use this new method.
+
+```
+WebSudoku >> setCell: aCurrentCell to: anInteger
+ sudoku atCell: aCurrentCell removeAllPossibilitiesBut: anInteger
+```
+
+
+```
+WebSudoku >> renderCellContentAtRow: rowInteger col: colInteger on: html
| currentCell possibilities |
currentCell := MLCell row: rowInteger col: colInteger.
possibilities := sudoku possibilitiesAt: currentCell.
@@ -122,17 +321,81 @@
integerValue := value asInteger.
integerValue isNil ifFalse: [
(possibilities includes: integerValue)
- ifTrue: [ self setCell: currentCell to: integerValue ] ] ] ]
```
The above code renders a text input box within a form tag, in each cell where there are more than one possibilities. Now you can type a value into the Sudoku grid and press return to save it, as seen in *@fig:incomplete@*. As you enter new values, you will see the possibilities for cells automatically be automatically reduced.
% +incomplete|width=70%+
![A partially filled Sudoku grid.](figures/incomplete.png width=70&label=fig:incomplete)
Now we can also ask the Sudoku model to solve itself by modifying the method `renderContentOn:`. We first check whether the Sudoku grid is solved and if not, we add an anchor whose callback will solve the puzzle.
```
WebSudoku>>renderContentOn: html
+ ifTrue: [ self setCell: currentCell to: integerValue ] ] ] ]
+```
+
+
+The above code renders a text input box within a form tag, in each cell where there are more than one possibilities. Now you can type a value into the Sudoku grid and press return to save it, as seen in Figure *@fig:incomplete@*. As you enter new values, you will see the possibilities for cells automatically be automatically reduced.
+
+
+![A partially filled Sudoku grid. % width=70&anchor=fig:incomplete](figures/incomplete.png)
+
+
+
+Now we can also ask the Sudoku model to solve itself by modifying the method `renderContentOn:`. We first check whether the Sudoku grid is solved and if not, we add an anchor whose callback will solve the puzzle.
+
+```
+WebSudoku>>renderContentOn: html
html div id: 'sudokuBoard'; with: [
self renderBoardOn: html.
sudoku solved ifFalse: [
html break.
html anchor
callback: [ sudoku := sudoku solve ];
- with: 'Solve' ] ]
```
Note that the solver uses backtracking, i.e., it finds a missing number by trying a possibility and if it fails to find a solution, it restarts with a different number. To backtrack the solver works on copies of the Sudoku grid, throwing away grids that don't work and restarting. This is why we need to assign the result of sending the message `solve` since it returns a new Sudoku grid. Figure *@fig:complete@* shows the result of clicking on Solve.
![A solved Sudoku grid.](figures/complete.png width=70&label=fig:complete)
### Back Button
Now let's play a bit. Suppose we have entered the values 1 through 6 as shown in Figure *@fig:upTo6@* and we want to replace the 6 with 7. If we press the _Back_ button, change the 6 to 7 and press return, we get 6 instead of 7. The problem is that we need to copy the state of the Sudoku grid before making the cell assignment in `setCell:to:`.
```
WebSudoku >> setCell: currentCell to: anInteger
+ with: 'Solve' ] ]
+```
+
+
+Note that the solver uses backtracking, i.e., it finds a missing number by trying a possibility and if it fails to find a solution, it restarts with a different number. To backtrack the solver works on copies of the Sudoku grid, throwing away grids that don't work and restarting. This is why we need to assign the result of sending the message `solve` since it returns a new Sudoku grid. Figure *@fig:complete@* shows the result of clicking on Solve.
+
+![A solved Sudoku grid. % width=70&anchor=fig:complete](figures/complete.png)
+
+
+### Back Button
+
+
+Now let's play a bit. Suppose we have entered the values 1 through 6 as shown in Figure *@fig:upTo6@* and we want to replace the 6 with 7. If we press the _Back_ button, change the 6 to 7 and press return, we get 6 instead of 7. The problem is that we need to copy the state of the Sudoku grid before making the cell assignment in `setCell:to:`.
+
+```
+WebSudoku >> setCell: currentCell to: anInteger
sudoku := sudoku copy
atCell: currentCell
- removeAllPossibilitiesBut: anInteger
```
If you change the definition of `setCell:to:` and try to replace 6 with 7 you will get a stack error similar to that shown in *@fig:error@*.
![Error when trying to replace 6 by 7.](figures/error.png width=70&label=fig:error)
If you click on the debug link at the top of the stack trace and then look at your Pharo image, you will see that it has opened a debugger. Now you can check the problem. If you select the expression
```
self possibilitiesAt: aCell
```
and print it, you will get a possibility set with 6, which is the previous value you gave to the cell. The code of the method `MLSudoku>>verifyPossibility:for:` raises an error if the new value is not among the possible values for that cell.
```
MLSudoku >> verifyPossibility: anInteger for: aCell
+ removeAllPossibilitiesBut: anInteger
+```
+
+
+If you change the definition of `setCell:to:` and try to replace 6 with 7 you will get a stack error similar to that shown in *@fig:error@*.
+
+![Error when trying to replace 6 by 7. % width=70&anchor=fig:error](figures/error.png)
+
+
+If you click on the debug link at the top of the stack trace and then look at your Pharo image, you will see that it has opened a debugger. Now you can check the problem. If you select the expression
+
+```
+self possibilitiesAt: aCell
+```
+
+
+and print it, you will get a possibility set with 6, which is the previous value you gave to the cell. The code of the method `MLSudoku>>verifyPossibility:for:` raises an error if the new value is not among the possible values for that cell.
+
+```
+MLSudoku >> verifyPossibility: anInteger for: aCell
((self possibilitiesAt: aCell) includes: anInteger)
- ifFalse: [ Error signal ]
```
In fact when you pressed the _Back_ button, the Sudoku UI was refreshed but its model was still holding the old values. What we need to do is to indicate to Seaside that when we press the _Back_ button the state of the model should be kept in sync and rollback to the corresponding older version. We do so by defining the method `states` which returns the elements that should be kept in sync.
```
WebSudoku >> states
- ^ Array with: self
```
### Summary
While the Sudoku solver introduces some subtleties because of its backtracking behavior, this application shows the power of Seaside to manage state.
Now you have a solid basis for building a really powerful Sudoku online application. Have a look at the class MLSudoku. Extend the application by loading challenging Sudoku grids that are defined by a string.
\ No newline at end of file
+ ifFalse: [ Error signal ]
+```
+
+
+In fact when you pressed the _Back_ button, the Sudoku UI was refreshed but its model was still holding the old values. What we need to do is to indicate to Seaside that when we press the _Back_ button the state of the model should be kept in sync and rollback to the corresponding older version. We do so by defining the method `states` which returns the elements that should be kept in sync.
+
+```
+WebSudoku >> states
+ ^ Array with: self
+```
+
+
+### Summary
+
+
+While the Sudoku solver introduces some subtleties because of its backtracking behavior, this application shows the power of Seaside to manage state.
+
+Now you have a solid basis for building a really powerful Sudoku online application. Have a look at the class MLSudoku. Extend the application by loading challenging Sudoku grids that are defined by a string.
\ No newline at end of file
diff --git a/Chapters/12-Serving/serving.log b/Chapters/12-Serving/serving.log
new file mode 100644
index 0000000..e69de29
diff --git a/Chapters/12-Serving/serving.md b/Chapters/12-Serving/serving.md
index 7d9441d..10a4967 100644
--- a/Chapters/12-Serving/serving.md
+++ b/Chapters/12-Serving/serving.md
@@ -1,24 +1,240 @@
-## Serving Files
@cha:serving
% +Just started playing.>file://figures/upTo6.png|width=70|label=fig:upTo6+
Most web-based applications make heavy use of static resources. By \`\`static'' we mean resources whose contents are not sensitive to the context in which they are used. These resources are not dependent on the user or session state and while they may change from time to time they typically don't change during the time span of a single user's session. Static resources include for example images, style sheets and JavaScript files.
Using these resources in a Seaside application need be no different from using them in any other web application development framework: when deploying your application you can serve these resources using a web server and reference them in your Seaside application, as described in Chapter *@cha:deployment@*.
In addition, Seaside supports a more tightly integrated file serving technique, called _FileLibrary_, which has some advantages over using a separate web server. In this chapter we will cover how to reference external resources and how to use the integrated FileLibrary to serve them from your Smalltalk image. Note that using FileLibrary to serve static resources is often slower than using a dedicated web server. In Chapter we explain how to serve static files in a more efficient way using Apache.
### Images
We illustrate the inclusion of static resources by displaying an external picture within an otherwise empty component as shown in Figure *@fig:external@*. Create
a component and use the method `WAImageTag>>url:` to add a URL to an image as follows:
```
ComponentWithExternalResource >> renderContentOn: html
- html image url: 'http://www.seaside.st/styles/logo-plain.png'
```
![Including an external picture into your components.](figures/external.png width=70&label=fig:external)
% +external-resource|width=70%+
If you have many static files that all live in the same location, it is annoying to have to repeat the base-path over and over again. In this case you should use `WAImageTag>>resourceUrl:` to provide the tail of the URL.
```
ComponentWithExternalResource >> renderContentOn: html
- html image resourceUrl: 'styles/logo-plain.png'
```
To tell Seaside about the part of the URL that you left out in your rendering code you have to go to the application configuration page \(at [http://localhost:8080/config](http://localhost:8080/config)\) and specify the _Resource Base URL_ in the server settings. Just enter `http://www.seaside.st` as shown in Figure *@fig:baseUrl@*. Seaside will automatically prepend this string to all URLs specified using `resourceUrl:>>resourceUrl:`. This reduces your code size and can be very useful if you want to move the resource location during deployment.
% +resource-base-url|width=60%+
![Including an external picture into your components.](figures/resourcebase.png width=950&label=fig:baseUrl)
Be careful where you put the slash. Normally directories in URLs end with a slash, that's why we specified the resource base URL ending with a slash. Thus, you should avoid putting a slash at the beginning of the URL fragments you pass to `resourceUrl:`.
#### Serving a generated image
Another interesting way to serve a picture is to use a dynamically generated picture from within your image \(see Figure *@fig:form@*\). It is possible to use `WAImageTag>>form:` to pass a Pharo `Form` directly to the image brush.
```
ComponentWithForm >> renderContentOn: html
- html image form: aForm
```
That works reasonably well for simple graphics, however most visual things in Pharo are made using morphs. Luckily it is simple to convert a morph to a form:
```
ComponentWithForm >> renderContentOn: html
+## Serving Files
+
+@cha:serving
+
+% +Just started playing.>file://figures/upTo6.png|width=70|anchor=fig:upTo6+
+
+Most web-based applications make heavy use of static resources. By \`\`static'' we mean resources whose contents are not sensitive to the context in which they are used. These resources are not dependent on the user or session state and while they may change from time to time they typically don't change during the time span of a single user's session. Static resources include for example images, style sheets and JavaScript files.
+
+Using these resources in a Seaside application need be no different from using them in any other web application development framework: when deploying your application you can serve these resources using a web server and reference them in your Seaside application, as described in Chapter *@cha:deployment@*.
+
+In addition, Seaside supports a more tightly integrated file serving technique, called _FileLibrary_, which has some advantages over using a separate web server. In this chapter we will cover how to reference external resources and how to use the integrated FileLibrary to serve them from your Smalltalk image. Note that using FileLibrary to serve static resources is often slower than using a dedicated web server. In Chapter we explain how to serve static files in a more efficient way using Apache.
+
+
+### Images
+
+
+We illustrate the inclusion of static resources by displaying an external picture within an otherwise empty component as shown in Figure *@fig:external@*. Create
+a component and use the method `WAImageTag>>url:` to add a URL to an image as follows:
+
+```
+ComponentWithExternalResource >> renderContentOn: html
+ html image url: 'http://www.seaside.st/styles/logo-plain.png'
+```
+
+
+![Including an external picture into your components. % width=70&anchor=fig:external](figures/external.png)
+
+
+If you have many static files that all live in the same location, it is annoying to have to repeat the base-path over and over again. In this case you should use `WAImageTag>>resourceUrl:` to provide the tail of the URL.
+
+```
+ComponentWithExternalResource >> renderContentOn: html
+ html image resourceUrl: 'styles/logo-plain.png'
+```
+
+
+
+To tell Seaside about the part of the URL that you left out in your rendering code you have to go to the application configuration page (at [http://localhost:8080/config](http://localhost:8080/config)) and specify the _Resource Base URL_ in the server settings. Just enter `http://www.seaside.st` as shown in Figure *@fig:baseUrl@*. Seaside will automatically prepend this string to all URLs specified using `resourceUrl:>>resourceUrl:`. This reduces your code size and can be very useful if you want to move the resource location during deployment.
+
+% +resource-base-url|width=60%+
+
+![Including an external picture into your components. % width=950&anchor=fig:baseUrl](figures/resourcebase.png)
+
+Be careful where you put the slash. Normally directories in URLs end with a slash, that's why we specified the resource base URL ending with a slash. Thus, you should avoid putting a slash at the beginning of the URL fragments you pass to `resourceUrl:`.
+
+
+#### Serving a generated image
+
+
+Another interesting way to serve a picture is to use a dynamically generated picture from within your image (see Figure *@fig:form@*). It is possible to use `WAImageTag>>form:` to pass a Pharo `Form` directly to the image brush.
+
+```
+ComponentWithForm >> renderContentOn: html
+ html image form: aForm
+```
+
+
+That works reasonably well for simple graphics, however most visual things in Pharo are made using morphs. Luckily it is simple to convert a morph to a form:
+
+```
+ComponentWithForm >> renderContentOn: html
html image form: (EllipseMorph new
color: Color orange;
extent: 200 @ 100;
borderWidth: 3;
- imageForm)
```
You can also use `WAImageTag>>document:` as follows:
```
html image document: EllipseMorph new
```
% +resource-form-morph|width=70%+
![Displaying Pharo graphical object..](figures/form-morph.png width=70&label=fig:form)
Have a look at the example implemented in the class `WAScreenshot`. It demonstrates a much more sophisticated use of `WAImageTag>>form:` and presents the Pharo desktop as part of a web application. Furthermore it allows basic interactions with your windows from the web browser.
### Including CSS and Javascript
So far, we've been including style information for our components by implementing the `style` method on our components. This is great for dynamic development, but there are a number of problems with this approach:
- Seaside is generating a style sheet file each time your component is rendered. This takes time to generate.
- Each generated stylesheet has the session key embedded in its URL, and so is seen as a unique file by your browser, and so loaded again.
- As you integrate more components in your page, each is generating its own stylesheet, so you can end up with many resources to be downloaded for each page.
Once your application's look and feel has begun to stabilise, you will want to think about using static stylesheets. These are typically included by using `link` tags in the `head` section of the XHTML document. This presents us with a problem: by the time your component gets sent `renderContentOn:`, the canvas has already generated the `head` section.
Fortunately, Seaside provides a hook method called `WAComponent>>updateRoot:` which is sent to all components which are reachable directly or indirectly through children or a `call:` message -- which means basically to all visible components. This message is sent during the generation of the body of the `head` tag and can be extended to add elements to this tag. The argument to `updateRoot:` is an instance of `WAHtmlRoot` which supports the access to document elements such as `
`, ``, `` and `` with their corresponding messages \(`WAHtmlRoot>>title`, `WAHtmlRoot>>meta`, `WAHtmlRoot>>javascript` and `WAHtmlRoot>>stylesheet`\). It also allows you to add attributes to the `` or `` tags using the messages `WAHtmlRoot>>headAttributes`, `WAHtmlRoot>>bodyAttributes`.
In particular, `WAHtmlRoot` offers the possibility to add new styles or script using the messages `WAHtmlRoot>>addScript:` and `WAHtmlRoot>>addStyles:`.
The object returned by both `stylesheet` and `javascript` understands `url:` which allows you to specify the URL of the stylesheet or JavaScript file. Suppose we have a stylesheet being served from [http://seaside.st/styles/main.css](http://seaside.st/styles/main.css). We could adopt this style in our document by extending `updateRoot:` as follows:
```
WAComponent subclass: #ComponentWithStyle
- instanceVariableNames: ''
- classVariableNames: ''
- package: 'Serving-Files'
```
```
ComponentWithStyle >> updateRoot: anHtmlRoot
+ imageForm)
+```
+
+
+You can also use `WAImageTag>>document:` as follows:
+
+```
+html image document: EllipseMorph new
+```
+
+
+![Displaying Pharo graphical object. % width=70&anchor=fig:form ](figures/form-morph.png)
+
+
+Have a look at the example implemented in the class `WAScreenshot`. It demonstrates a much more sophisticated use of `WAImageTag>>form:` and presents the Pharo desktop as part of a web application. Furthermore, it allows basic interactions with your windows from the web browser.
+
+### Including CSS and Javascript
+
+
+So far, we've been including style information for our components by implementing the `style` method on our components. This is great for dynamic development, but there are a number of problems with this approach:
+
+- Seaside generates a style sheet file each time your component is rendered. This takes time to generate.
+- Each generated stylesheet has the session key embedded in its URL, and so is seen as a unique file by your browser, and so loaded again.
+- As you integrate more components in your page, each generates its own stylesheet, so you can end up with many resources to be downloaded for each page.
+
+
+Once your application's look and feel has begun to stabilize, you will want to think about using static stylesheets. These are typically included by using `link` tags in the `head` section of the XHTML document. This presents us with a problem: by the time your component gets sent `renderContentOn:`, the canvas has already generated the `head` section.
+
+Fortunately, Seaside provides a hook method called `WAComponent>>updateRoot:` which is sent to all components which are reachable directly or indirectly through children or a `call:` message -- which means basically to all visible components. This message is sent during the generation of the body of the `head` tag and can be extended to add elements to this tag. The argument to `updateRoot:` is an instance of `WAHtmlRoot` which supports the access to document elements such as ``, ``, `` and `` with their corresponding messages (`WAHtmlRoot>>title`, `WAHtmlRoot>>meta`, `WAHtmlRoot>>javascript` and `WAHtmlRoot>>stylesheet`). It also allows you to add attributes to the `` or `` tags using the messages `WAHtmlRoot>>headAttributes`, `WAHtmlRoot>>bodyAttributes`.
+
+In particular, `WAHtmlRoot` offers the possibility to add new styles or script using the messages `WAHtmlRoot>>addScript:` and `WAHtmlRoot>>addStyles:`.
+
+The object returned by both `stylesheet` and `javascript` understands `url:` which allows you to specify the URL of the stylesheet or JavaScript file. Suppose we have a stylesheet being served from [http://seaside.st/styles/main.css](http://seaside.st/styles/main.css). We could adopt this style in our document by extending `updateRoot:` as follows:
+
+
+```
+WAComponent << #ComponentWithStyle
+ package: 'Serving-Files'
+```
+
+
+```
+ComponentWithStyle >> updateRoot: anHtmlRoot
super updateRoot: anHtmlRoot.
- anHtmlRoot stylesheet url: 'http://seaside.st/styles/main.css'
```
```
ComponentWithStyle >> renderContentOn: html
+ anHtmlRoot stylesheet url: 'http://seaside.st/styles/main.css'
+```
+
+
+```
+ComponentWithStyle >> renderContentOn: html
html heading level: 1; with: 'Seaside'.
- html text: 'This component uses the Seaside style.'
```
Running the example should give you the following *@fig:withStyle@*:
% +withStyle|width=80%+
![Application with enabled style sheet.](figures/withStyle.png width=80&label=fig:withStyle)
Now we will show how you can replace the stylesheet using the FileLibrary.
### Working with File Libraries
Seaside includes a library for serving files called _FileLibrary_. This solution is handy for rapid application development and is suitable for deployed applications which only make use of a small number of small files. It has the advantage that all of the resources are contained in your Smalltalk image and can be versioned with your favorite Smalltalk version management tools. However this also means that these resources are **not** reachable where most of your operating system's tools are accustomed to find things.
FileLibrary has the primary advantage that it is a portable way to serve static contents directly from Seaside without the need to setup a standalone web server. See Chapter to read about Apache configuration for static file serving.
#### Creating a File Library
Setting up a file library is easy. Here are the steps you need to follow.
1. Put your static files in a directory. The location of the directory is not significant. From within the directory, the files can reference each other using their file names.
1. Create a file library by subclassing `WAFileLibrary`. For the rest of this text we assume its name is `MyFileLibrary`.
1. Add files to your file library. There are three ways to add files to your file library:
- Programmatically.
- Via the web interface.
- By editing your `MyFileLibrary` directly in your image.
**Adding files programmatically.** You can add files programmatically by using the class side methods `addAllFilesIn:` and `addFileAt:` in `MyFileLibrary`. For example:
```
MyFileLibrary addAllFilesIn: '/path/to/directory'
-MyFileLibrary addFileAt: '/path/to/background.png'
```
**Adding files via the config interface.** Open the config application at [http://localhost:8080/config](http://localhost:8080/config) and click the \`\`configure'' link for file libraries as shown in Figure *@ref:configureFiles@*. This shows which file libraries are available.
% +configureFiles|width=70%+
![Configuring file libraries through the web interface: clicking on files - configure.](figures/configureFiles.png width=80&label=ref:configureFiles)
Click the configure link for `MyFileLibrary` as shown in *@ref:configureMyFileLibrary@* right.
% +configureMyFileLibrary|width=70%+
![File libraries.](figures/configureMyFileLibrary.png width=80&label=ref:configureMyFileLibrary)
There you can add a file by uploading it \(select the file, then click the _Add_ button as shown by *@ref:addingMyFileLibrary@*\).
% +addingMyFileLibrary|width=70%+
![File libraries.](figures/AddedToMyFileLibrary.png width=80&label=ref:addingMyFileLibrary)
!!important When you add a file to a file library, Seaside creates a method with the file contents. If you find that there is an unusually long wait after pressing the _Add_ button, make sure that the system \(Squeak/Pharo\) isn't waiting for you to type your initials to confirm that you want to create a new method.
**Adding a file by editing the class.** File libraries are just objects and \`\`files'' in the file library are just methods so you can always add and modify FileLibrary entries using your normal class browser but be sure to follow the method naming convention mentioned above. You'll probably find it pretty inconvenient to edit images within the browser though.
Adding a file to a file library either programmatically or using the configuration interface defines a corresponding method in the file library class, with the file name determining the name of the method. The dot is removed and the first letter of the suffix is capitalized. For example, the file main.css becomes the method `MyFileLibrary>>mainCss`. This puts certain limitations on the allowed file names. For example, the main part of the file name may not be all digits.
Once your files have been imported into the file library they are maintained independently from the files on your computer's file system. If you modify your files you will have to re-add them to the file library.
Once your files are stored in a FileLibrary they will be available to be served through Seaside.
#### Referencing FileLibrary files by URL
How you use a file library depends on what you want to do with the files in it. As you've seen in the previous sections, using image, music, style sheets and JavaScript files requires knowing their URL. You can find the URL of any document in your file library by sending the class `WAFileLibrary class>>urlOf:`. For example, if you had added the file `picture.jpg` to your library and you want to display it in a component you would write something like:
```
MyClass>>renderContentOn: html
- html image url: (MyFileLibrary urlOf: #pictureJpg)
```
The URL returned by `urlOf:` is relative to the current server. It does not contain the [http://servername.com/](http://servername.com/) - the so-called \`\`method_ and \`\`host_ - portion of the URL. Note that WAFileLibrary implements a class method called `/`, so the expression `MyFileLibrary / #pictureJpeg` is equivalent to `MyFileLibrary urlOf: #pictureJpeg`.
Once you know the URL of the FileLibrary resources you can use them to include style sheets and JavaScript in your components as we have already discussed.
### Example of FileLibrary in Use
We've gone on long enough without a working hands-on example. To illustrate how to use a file library, we will show how to add some resources to the WebCounter application we defined in the first chapter of this book \([http://localhost:8080/webcounter](http://localhost:8080/webcounter)\) or can also use the version that comes with Seaside \([http://localhost:8080/examples/counter](http://localhost:8080/examples/counter)\). First we create a new subclass of `WAFileLibrary` named `CounterLibrary` as follows:
```
WAFileLibrary subclass: #CounterLibrary
- instanceVariableNames: ''
- classVariableNames: ''
- package: 'Test'
```
% +WACounterFileLibraryEmpty|width=70%+
First as you can see in Figure *@ref:counterLibraryEmpty@* the counter library is empty.
![An empty CounterLibrary.](figures/WACounterFileLibraryEmpty.png width=80&label=ref:counterLibraryEmpty)
% +AddedCounterLibrary|width=70%+
![Adding files to the CounterLibrary.](figures/WACounterFileLibraryAdded.png width=80&label=ref:counterLibraryAdded)
We follow the steps presented in the previous section and associate two resources to our library \(see Figure *@ref:counterLibraryAdded@*\). One is an icon named `seaside.png` and the other is a CSS file named `seaside.css` -- you can download the ones from the Seaside website we mentioned before:
seaside.png
[http://www.seaside.st/styles/logo-plain.png](http://www.seaside.st/styles/logo-plain.png) \(rename once downloaded\).
seaside.css
[http://seaside.st/styles/main.css](http://seaside.st/styles/main.css)
!!important Pay attention that the file name of your resources does not contain non-alphabetic characters since it may cause problems.
Now we change the method `renderContentOn:` -- this shows how we access resources using the `urlOf:`.
```
WebCounter >> renderContentOn: html
+ html text: 'This component uses the Seaside style.'
+```
+
+
+Running the example should give you the following Figure *@fig:withStyle@*:
+
+![Application with enabled style sheet. %width=80&anchor=fig:withStyle](figures/withStyle.png)
+
+Now we will show how you can replace the stylesheet using the FileLibrary.
+
+### Working with File Libraries
+
+
+Seaside includes a library for serving files called _FileLibrary_. This solution is handy for rapid application development and is suitable for deployed applications which only make use of a small number of small files. It has the advantage that all of the resources are contained in your Smalltalk image and can be versioned with your favorite Smalltalk version management tools. However this also means that these resources are **not** reachable where most of your operating system's tools are accustomed to find things.
+
+FileLibrary has the primary advantage that it is a portable way to serve static contents directly from Seaside without the need to setup a standalone web server. See Chapter to read about Apache configuration for static file serving.
+
+
+#### Creating a File Library
+
+
+Setting up a file library is easy. Here are the steps you need to follow.
+
+1. Put your static files in a directory. The location of the directory is not significant. From within the directory, the files can reference each other using their file names.
+1. Create a file library by subclassing `WAFileLibrary`. For the rest of this text we assume its name is `MyFileLibrary`.
+1. Add files to your file library. There are three ways to add files to your file library:
+ - Programmatically.
+ - Via the web interface.
+ - By editing your `MyFileLibrary` directly in your image.
+
+
+**Adding files programmatically.** You can add files programmatically by using the class side methods `addAllFilesIn:` and `addFileAt:` in `MyFileLibrary`. For example:
+
+```
+MyFileLibrary addAllFilesIn: '/path/to/directory'
+MyFileLibrary addFileAt: '/path/to/background.png'
+```
+
+
+
+**Adding files via the config interface.** Open the config application at [http://localhost:8080/config](http://localhost:8080/config) and click the ''configure'' link for file libraries as shown in Figure *@ref:configureFiles@*. This shows which file libraries are available.
+
+
+![Configuring file libraries through the web interface: clicking on files - configure. %width=80&anchor=ref:configureFiles](figures/configureFiles.png )
+
+Click the configure link for `MyFileLibrary` as shown in *@ref:configureMyFileLibrary@* right.
+
+
+![File libraries. % width=80&anchor=ref:configureMyFileLibrary](figures/configureMyFileLibrary.png)
+
+
+There you can add a file by uploading it (select the file, then click the _Add_ button as shown by *@ref:addingMyFileLibrary@*).
+
+![File libraries. % width=80&anchor=ref:addingMyFileLibrary](figures/AddedToMyFileLibrary.png)
+
+
+!!important When you add a file to a file library, Seaside creates a method with the file contents. If you find that there is an unusually long wait after pressing the _Add_ button, make sure that the system (Squeak/Pharo) isn't waiting for you to type your initials to confirm that you want to create a new method.
+
+**Adding a file by editing the class.** File libraries are just objects and ''files'' in the file library are just methods so you can always add and modify FileLibrary entries using your normal class browser but be sure to follow the method naming convention mentioned above. You'll probably find it pretty inconvenient to edit images within the browser though.
+
+Adding a file to a file library either programmatically or using the configuration interface defines a corresponding method in the file library class, with the file name determining the name of the method. The dot is removed and the first letter of the suffix is capitalized. For example, the file main.css becomes the method `MyFileLibrary>>mainCss`. This puts certain limitations on the allowed file names. For example, the main part of the file name may not be all digits.
+
+Once your files have been imported into the file library they are maintained independently from the files on your computer's file system. If you modify your files you will have to re-add them to the file library.
+
+Once your files are stored in a FileLibrary they will be available to be served through Seaside.
+
+
+#### Referencing FileLibrary files by URL
+
+
+How you use a file library depends on what you want to do with the files in it. As you've seen in the previous sections, using image, music, style sheets and JavaScript files requires knowing their URL. You can find the URL of any document in your file library by sending the class `WAFileLibrary class>>urlOf:`. For example, if you had added the file `picture.jpg` to your library and you want to display it in a component you would write something like:
+
+```
+MyClass>>renderContentOn: html
+ html image url: (MyFileLibrary urlOf: #pictureJpg)
+```
+
+
+
+The URL returned by `urlOf:` is relative to the current server. It does not contain the [http://servername.com/](http://servername.com/) - the so-called ''method_ and ''host_ - portion of the URL. Note that WAFileLibrary implements a class method called `/`, so the expression `MyFileLibrary / #pictureJpeg` is equivalent to `MyFileLibrary urlOf: #pictureJpeg`.
+
+Once you know the URL of the FileLibrary resources you can use them to include style sheets and JavaScript in your components as we have already discussed.
+
+
+
+### Example of FileLibrary in Use
+
+
+We've gone on long enough without a working hands-on example. To illustrate how to use a file library, we will show how to add some resources to the WebCounter application we defined in the first chapter of this book ([http://localhost:8080/webcounter](http://localhost:8080/webcounter)) or can also use the version that comes with Seaside ([http://localhost:8080/examples/counter](http://localhost:8080/examples/counter)). First we create a new subclass of `WAFileLibrary` named `CounterLibrary` as follows:
+
+```
+WAFileLibrary << #CounterLibrary
+ package: 'Test'
+```
+
+
+
+First as you can see in Figure *@ref:counterLibraryEmpty@* the counter library is empty.
+
+![An empty CounterLibrary. % width=80&anchor=ref:counterLibraryEmpty](figures/WACounterFileLibraryEmpty.png)
+
+
+![Adding files to the CounterLibrary. %width=80&anchor=ref:counterLibraryAdded](figures/WACounterFileLibraryAdded.png )
+
+
+We follow the steps presented in the previous section and associate two resources to our library (see Figure *@ref:counterLibraryAdded@*). One is an icon named `seaside.png` and the other is a CSS file named `seaside.css` -- you can download the ones from the Seaside website we mentioned before:
+
+
+
+seaside.png
+[http://www.seaside.st/styles/logo-plain.png](http://www.seaside.st/styles/logo-plain.png) (rename once downloaded).
+
+seaside.css
+[http://seaside.st/styles/main.css](http://seaside.st/styles/main.css)
+
+!!important Pay attention that the file name of your resources does not contain non-alphabetic characters since it may cause problems.
+
+Now we change the method `renderContentOn:` -- this shows how we access resources using the `urlOf:`.
+
+```
+WebCounter >> renderContentOn: html
html image url: (CounterLibrary urlOf: #seasidePng).
html heading: count.
html anchor
@@ -27,9 +243,27 @@ MyFileLibrary addFileAt: '/path/to/background.png'
```
**Adding files via the
html space.
html anchor
callback: [ self decrease ];
- with: '--'
```
Next we implement `updateRoot:` so that our component contains a link to our style sheet:
```
WebCounter >> updateRoot: anHtmlRoot
+ with: '--'
+```
+
+
+Next we implement `updateRoot:` so that our component contains a link to our style sheet:
+
+```
+WebCounter >> updateRoot: anHtmlRoot
super updateRoot: anHtmlRoot.
- anHtmlRoot stylesheet url: (CounterLibrary urlOf: #seasideCss)
```
This causes the look of our application to change. It now uses the CSS file we added to our file library as shown by *@ref:counterNoCss@*.
% +counterNoCss|width=20%+
![Counter with the updateRoot: method defined.](figures/counterNoCss.png width=80&label=ref:counterNoCss)
Have a look at the XHTML source generated by Seaside by using your browser's View Source option. You will see that the links are added to the head section of the HTML document as shown below:
```
...
+ anHtmlRoot stylesheet url: (CounterLibrary urlOf: #seasideCss)
+```
+
+
+This causes the look of our application to change. It now uses the CSS file we added to our file library as shown by Figure *@ref:counterNoCss@*.
+
+![Counter with the updateRoot: method defined. %width=80&anchor=ref:counterNoCss](figures/counterNoCss.png )
+
+Have a look at the XHTML source generated by Seaside by using your browser's View Source option. You will see that the links are added to the head section of the HTML document as shown below:
+
+```
+...
@@ -37,13 +271,163 @@ MyFileLibrary addFileAt: '/path/to/background.png'
```
**Adding files via the
` element that contains the help text, and changing the onClick of the header to apply our new cool effect to the new element. We also need some new CSS to help us out with this.
```
ToDoListView >> renderHeadingOn: html
+ with: self model title.
+```
+
+
+We create a query using `html jQuery this` that selects the heading DOM element. Next we send effect to get a `JQEffect` instance. Then finally we send `JQEffect>>highlight` which highligths the background color.
+
+Altering the highlight color is left as an exercise for the reader.
+
+Now for something a little more fun - let’s add some help test that appears when you click on the heading; and it won’t just "appear", it will slide open at a rate that we determine.
+
+We do this by rendering a new `
` element that contains the help text, and changing the onClick of the header to apply our new cool effect to the new element. We also need some new CSS to help us out with this.
+
+```
+ToDoListView >> renderHeadingOn: html
| helpId |
helpId := html nextId.
(html heading)
@@ -94,7 +642,13 @@ html anchor
id: helpId;
class: 'help';
style: 'display: none';
- with: 'The ToDo app enhanced with jQuery.'
```
```
ToDoListView >> style
+ with: 'The ToDo app enhanced with jQuery.'
+```
+
+
+
+```
+ToDoListView >> style
^ '
.help {
padding: 1em;
@@ -127,4 +681,12 @@ html anchor
}
li.done {
color: #264409;
- }'
```
### Summary
This chapter showed how Seaside can interact with Javascript.
It opens a large spectrum of possibilities.
\ No newline at end of file
+ }'
+```
+
+
+### Summary
+
+
+This chapter showed how Seaside can interact with Javascript.
+It opens a large spectrum of possibilities.
diff --git a/Chapters/18-WebSockets/websockets.md b/Chapters/18-WebSockets/websockets.md
index b3d44d0..77615b5 100644
--- a/Chapters/18-WebSockets/websockets.md
+++ b/Chapters/18-WebSockets/websockets.md
@@ -1,9 +1,76 @@
-## WebSockets
@cha:websockets
DRAFT
### Concepts
### Architecture
### Studying a real case
[https://github.com/TelescopeSt/TelescopeCytoscape](https://github.com/TelescopeSt/TelescopeCytoscape)
This project allow one to create a model of visualization \(nodes and their
contents, layouts, interactions, and update mechanism\) then to render it
with the CytoscapeJs visualization framework.
The Seaside part is really small. We just use Seaside to render an empty
div and initialize a cytoscape visualization inside. We could probably
do without Seaside but we did this project for a Seaside application.
\(And we use the existing callbacks mechanism\).
During the rendering we open a web socket and we generate the initial
cytoscape visualization inside the empty div generated by Seaside.
Then when the user interact with the visualization, it communicates the
interactions via the web socket to the Pharo server and if it should
impact the visualization, commands to do so are sent via the websocket
to the client.
In this project the main part for the websocket management are:
- TLCytoscapeComponent : The Seaside component registering the
visualization
\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeComponent.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeComponent.class.st)\)
- TLCytoscapeWebSocketDelegate : The class managing the websocket server
side
\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st)\)
- CYSFileLibrary>>cytoscapeTelescopeJs : The javascript managing the
socket client side
\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape-Libraries/CYSFileLibrary.class.st#L539](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape-Libraries/CYSFileLibrary.class.st#L539)\)
### The Component Part
```
TLCytoscapeComponent >> visuDivId [
+## WebSockets
+@cha:websockets
+
+DRAFT
+
+### Concepts
+
+
+### Architecture
+
+
+### Studying a real case
+
+
+[https://github.com/TelescopeSt/TelescopeCytoscape](https://github.com/TelescopeSt/TelescopeCytoscape)
+
+This project allows one to create a model of visualization \(nodes and their
+contents, layouts, interactions, and update mechanism\) then to render it
+with the CytoscapeJs visualization framework.
+
+The Seaside part is really small. We just use Seaside to render an empty
+div and initialize a cytoscape visualization inside. We could probably
+do without Seaside but we did this project for a Seaside application.
+\(And we use the existing callbacks mechanism\).
+
+During the rendering,s we open a web socket and we generate the initial
+cytoscape visualization inside the empty div generated by Seaside.
+
+Then when the user interact with the visualization, it communicates the
+interactions via the web socket to the Pharo server and if it should
+impact the visualization, commands to do so are sent via the websocket
+to the client.
+
+In this project the main part for the websocket management are:
+
+- TLCytoscapeComponent : The Seaside component registering the
+
+visualization
+\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeComponent.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeComponent.class.st)\)
+- TLCytoscapeWebSocketDelegate : The class managing the websocket server
+
+side
+\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st)\)
+- CYSFileLibrary>>cytoscapeTelescopeJs : The javascript managing the
+
+socket client side
+\([https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape-Libraries/CYSFileLibrary.class.st#L539](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape-Libraries/CYSFileLibrary.class.st#L539)\)
+
+
+### The Component Part
+
+
+```
+TLCytoscapeComponent >> visuDivId [
visuDivId ifNil: [ visuDivId:= self class nextId ].
^ visuDivId
-]
```
```
TLCytoscapeComponent >> visuDivId: anObject [
+]
+```
+
+
+```
+TLCytoscapeComponent >> visuDivId: anObject [
visuDivId := anObject
-]
```
```
TLCytoscapeComponent >> renderContentOn: html [
+]
+```
+
+
+
+
+
+
+```
+TLCytoscapeComponent >> renderContentOn: html [
| visuId div callback |
visuId := self visuDivId.
div := html div
@@ -26,25 +93,59 @@
callbackUrl:
{html actionUrl asString.
(div storeCallback: callback)}
-]
```
```
TLCytoscapeComponent >> renderOptionalButtonsOn: html [
+]
+```
+
+
+```
+TLCytoscapeComponent >> renderOptionalButtonsOn: html [
html div
class: 'fitButton';
with: [ self renderResetButtonOn: html.
self exportStrategy renderDownloadButtonForVisu: self visuDivId on: html ]
-]
```
```
TLCytoscapeComponent >> renderResetButtonOn: html [
+]
+```
+
+
+```
+TLCytoscapeComponent >> renderResetButtonOn: html [
html anchor
onClick: 'telescope.visuWithId(' , self visuDivId asString , ').fit();';
with: 'Reset'
-]
```
### Websocket server side
The class managing the websocket server
side \(from [https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st)\)
```
ZnWebSocketDelegate subclass: #TLCytoscapeWebSocketDelegate,
+]
+```
+
+
+
+### Websocket server side
+
+
+The class managing the websocket server
+side \(from [https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st](https://github.com/TelescopeSt/TelescopeCytoscape/blob/development/src/Telescope-Cytoscape/TLCytoscapeWebSocketDelegate.class.st)\)
+
+```
+ZnWebSocketDelegate subclass: #TLCytoscapeWebSocketDelegate,
instVars: 'visualizationByIdDictionary websocketByVisu'
- classInstVars: 'singleton development serverPort clientPort'
```
```
TLCytoscapeWebSocketDelegate class >> registerVisualization: aTLVisualization underId: aDivId withCallBack: aCallBack callbackUrl: callbackUrl [
+ classInstVars: 'singleton development serverPort clientPort'
+```
+
+
+
+
+```
+TLCytoscapeWebSocketDelegate class >> registerVisualization: aTLVisualization underId: aDivId withCallBack: aCallBack callbackUrl: callbackUrl [
self ensureServerIsRunning.
self singleton delegate
registerVisualization: aTLVisualization
underId: aDivId
withCallBack: aCallBack
callbackUrl: callbackUrl
-]
```
```
initialize [
+]
+```
+
+
+```
+initialize [
super initialize.
self visualizationByIdDictionary: Dictionary new.
self websocketByVisu: Dictionary new.
@@ -56,4 +157,7 @@
do: [ self freeResourcesFor: webSocket ] ]
on: PrimitiveFailed
do: [ self class restart ] ]
- ]
```
\ No newline at end of file
+ ]
+```
+
+