Scriptacu-list Tutorial(Part 7)

To complete our application we will allow our users to upload a picture of the contact so that it appears on the details drop down.

Got the Picture?

OK first we need to be able to upload a picture.

We will return to our MyContactEditor and modify the #renderContentOn: method to make the form a multipart form and add a file upload field.

renderContentOn: html
html heading: 'Contact Details'.
html form
multipart;
with:
[
self renderLabel: 'First Name: ' withInput: [html textInput on: #firstName of: contact] on: html.
self renderLabel: 'Surname: ' withInput: [html textInput on: #surname of: contact] on: html.
self renderLabel: 'Date of Birth: ' withInput: [html dateInput on: #dateOfBirth of: contact] on: html.
self renderLabel: 'Telephone: ' withInput: [html textInput on: #telephoneNumber of: contact] on: html.
self renderLabel: 'Email: ' withInput: [html textInput on: #emailAddress of: contact] on: html.
self renderLabel: 'Photograph ' withInput: [html fileUpload callback: [:file | self attachPhotograph: file]] on: html.
html span class: 'button';
with: [html submitButton on: #save of: self].
html span class: 'button';
with: [html submitButton on: #cancel of: self].
]

Now we need to code the #attachPhotograph: method that the uploaded file gets passed to.

attachPhotograph: aFile
| form sizedForm fileName tempStream|
aFile ifNotNil:[
tempStream := RWBinaryOrTextStream with: aFile contents.
tempStream binary.
form := ImageReadWriter formFromStream: tempStream.
sizedForm := form scaledToSize: 100@100.
fileName := contact identifier, '-photo.gif'.
GIFReadWriter putForm: sizedForm onOverwritableFileNamed: 'FileRoot', FileDirectory slash, fileName.]

This method takes the binary input stream and uses ImageReadWriter to obtain the “form” i.e. the picture. We then resize the picture to 100px by 100px and save it as a gif name fredbloggs-photo.gif (where fredbloggs is my contact’s identifier). I save the file in the directory FileRoot which I declared as my Document Root directory for my application.

Let’s see it Then

Now the final step is to amend the #renderDetailsDiv:on: method in MyContactDetailView so that it includes the image from our document root.

renderDetailsDiv: aString on: html
html div id: aString;
style: 'display: none';
with: [
html div
style: 'clear:both';
with: [

html image
style: ‘float: left; margin-right:10px’;
altText: (‘Picture of ‘, contact fullName);
resourceUrl: ‘/’, contact identifier, ‘-photo.gif’ .
].
html render: ‘Name: ‘, contact fullName.
html break.
html render: ‘Birthday: ‘, contact dateOfBirth printString.
html break.
html render: ‘Telephone: ‘, contact telephoneNumber.
html break.
html render: ‘Email: ‘. contact emailAddress.
html break.
]

Job done! (Apart from getting a good CCS/Graphic designer to make it look super cool – If anyone wishes to contribute one I’d be more than happy to replace my rather basic one in session 3.)

If you stuck with me all the way to the end then I hope you found it worthwhile. And if your just starting out on Seaside I’d just like to encourage you to blog your progress. It really helps to crystallize your thinking and their are others out there who can add new insights as you go.

Advertisements
Explore posts in the same categories: Scriptaculous, Seaside, Smalltalk

7 Comments on “Scriptacu-list Tutorial(Part 7)”

  1. Damien Cassou Says:

    Congratulation for this very interesting tutorial. Whan do you plan to make the next one ?


  2. Thanks Damien

    I think my wife might have some jobs for me to do first ;-).

    I am going to concentrate on developing some real applications and then I might blog some of my findings


  3. Hi
    It was a great tutorial from your side. Though I am a beginner of Squeak and Seaside, I could follow most of the things and could implement as well.

    I couldn’t get onOverwritableFileNamed: but somehow managed to create it on my own 😉

    Thanks again.

    Are you planning for more tutorials? Am Looking forward for them

    Regards,
    Rajeev Lochan


  4. Hi Rajeev

    Sorry for not replying earlier. Life has been pretty hectic for me and I’ve neglected my blog a bit.

    Thanks for ploughing through – I hope your enjoying seaside.

    IIRC I think I had to create ImageReadWriter>>putForm:onOverwritableFileNamed: in order to let me easily overwrite any previously stored picture. The code looks like this…

    putForm: aForm onOverwritableFileNamed: fileName
    “Store the given form on a file of the given name.”

    | writer |
    writer := self on: (FileStream forceNewFileNamed: fileName) binary.
    Cursor write showWhile: [writer nextPutImage: aForm].
    writer close.

    …I do intend to blog some more tutorial stuff but I only get to do Seaside in my spare time at the moment. When I do get round to the next one I will put an announcement on the seaside mailing list.


  5. Michael. Your tutorial is quite good. Thank you for it.

    I’d like to share a slight variant for step 7. I thought it would be cool to *not* write a photo to disk. Instead, to just save the photo to an instance of MyContact and then later render the image directly from it. This is more like what I would do with my apps that I write because I think it is easier to let the database manage the photos so you don’t have to come up with file names and also the image data stays tightly coupled with your business object.

    For “MyContact” I added two instance variables named “photo” and “photoMimeType”. I created getters and setters for these.

    MyContactEditor>>attachPhotograph looks like this:

    attachPhotograph: aFile
    aFile
    ifNotNil: [contact photo: aFile contents.
    contact photoMimeType: aFile contentType]

    MyContactDetailsView>>renderDetailsDiv:on: is as follows:

    renderDetailsDiv: aString on: html
    (html div)
    id: aString;
    style: ‘display: none’;
    with:
    [(html div)
    style: ‘clear:both; ‘;
    with: [self produceThumbnailIfAvailableOn: html].
    html render: ‘Name: ‘ , contact fullName.
    html break.
    html render: ‘Birthday: ‘ , contact dateOfBirth printString.
    html break.
    html render: ‘Telephone: ‘ , contact telephoneNumber.
    html break.
    html render: ‘Email: ‘ , contact emailAddress.
    html break]

    A new helper message is created and referred to in the above. It is MyContactDetailsView>>produceThumbnailIfAvailableOn: and looks like this:

    produceThumbnailIfAvailableOn: html
    ^ contact photo notNil & contact photoMimeType notNil
    ifTrue: [html image document: contact photo mimeType: contact photoMimeType;
    style: ‘float: left; margin-right:10px; width:30px; ‘;
    altText: ‘Picture of ‘ , contact fullName]

  6. Hooscow Says:

    I just tried this, and found that the fileUpload callback never gets called in:

    html fileUpload callback: [:file | self attachPhotograph: file]

    I set a breakpoint (self halt) in attachPhotograph and found that the method is never called.

    So,…no photo for me.

  7. Hooscow Says:

    Sorry. Never mind.

    I had forgotten the multipart message.

    html form multipart;

    The callback works. The photo shows up. Bravo!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: