SlideShare a Scribd company logo
Javascript Web Applications Otx Alex Maccaw
download
https://ebookbell.com/product/javascript-web-applications-otx-
alex-maccaw-2408862
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Javascript Web Applications Alex Maccaw
https://ebookbell.com/product/javascript-web-applications-alex-
maccaw-42303014
Javascript Web Applications Alex Maccaw
https://ebookbell.com/product/javascript-web-applications-alex-
maccaw-43169376
Javascript Web Applications Alex Maccaw
https://ebookbell.com/product/javascript-web-applications-alex-
maccaw-42302320
Sencha Touch 10 Mobile Javascript Framework Build Web Applications For
Apple Ios And Google Android Touchscreen Devices With This First Html5
Mobile Framework 1st Edition Narasimha Rao
https://ebookbell.com/product/sencha-touch-10-mobile-javascript-
framework-build-web-applications-for-apple-ios-and-google-android-
touchscreen-devices-with-this-first-html5-mobile-framework-1st-
edition-narasimha-rao-4107484
Deno Web Development Write Test Maintain And Deploy Javascript And
Typescript Web Applications Using Deno 1st Edition Alexandre Portela
Dos Santos
https://ebookbell.com/product/deno-web-development-write-test-
maintain-and-deploy-javascript-and-typescript-web-applications-using-
deno-1st-edition-alexandre-portela-dos-santos-50781278
Web Applications With Javascript Or Java Volume 1 Constraint
Validation Enumerations Special Datatypes Gerd Wagner Mircea
Diaconescu
https://ebookbell.com/product/web-applications-with-javascript-or-
java-volume-1-constraint-validation-enumerations-special-datatypes-
gerd-wagner-mircea-diaconescu-50347562
Building Web Applications With Net Core 21 And Javascript Leveraging
Modern Javascript Frameworks Second Edition 2nd Edition Philip Japikse
https://ebookbell.com/product/building-web-applications-with-net-
core-21-and-javascript-leveraging-modern-javascript-frameworks-second-
edition-2nd-edition-philip-japikse-52948432
Web Applications With Javascript Or Java De Gruyter Textbook 1st
Edition Gerd Wagner
https://ebookbell.com/product/web-applications-with-javascript-or-
java-de-gruyter-textbook-1st-edition-gerd-wagner-33557258
Web Applications With Javascript Or Java Volume 1 Constraint
Validation Enumerations Special Datatypes De Gruyter Textbook Gerd
Wagner
https://ebookbell.com/product/web-applications-with-javascript-or-
java-volume-1-constraint-validation-enumerations-special-datatypes-de-
gruyter-textbook-gerd-wagner-33646480
Javascript Web Applications Otx Alex Maccaw
Javascript Web Applications Otx Alex Maccaw
Javascript Web Applications Otx Alex Maccaw
JavaScript Web Applications
Javascript Web Applications Otx Alex Maccaw
JavaScript Web Applications
Alex MacCaw
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
JavaScript Web Applications
by Alex MacCaw
Copyright © 2011 Alex MacCaw. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions
are also available for most titles (http://my.safaribooksonline.com). For more information, contact our
corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com.
Editor: Mary Treseler
Production Editor: Holly Bauer
Copyeditor: Marlowe Shaeffer
Proofreader: Stacie Arellano
Indexer: Fred Brown
Cover Designer: Karen Montgomery
Interior Designer: David Futato
Illustrator: Robert Romano
Printing History:
August 2011: First Edition.
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of
O’Reilly Media, Inc. JavaScript Web Applications, the image of a Long-eared owl, and related trade dress
are trademarks of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a
trademark claim, the designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and author assume
no responsibility for errors or omissions, or for damages resulting from the use of the information con-
tained herein.
ISBN: 978-1-449-30351-8
[LSI]
1313086859
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1. MVC and Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Early Days 1
Adding Structure 2
What Is MVC? 2
The Model 3
The View 4
The Controller 5
Toward Modularity, Creating Classes 6
Adding Functions to Classes 7
Adding Methods to Our Class Library 8
Class Inheritance Using Prototype 10
Adding Inheritance to Our Class Library 11
Function Invocation 12
Controlling Scope in Our Class Library 14
Adding Private Functions 16
Class Libraries 16
2. Events and Observing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Listening to Events 19
Event Ordering 20
Canceling Events 21
The Event Object 21
Event Libraries 23
Context Change 24
Delegating Events 24
Custom Events 25
Custom Events and jQuery Plug-Ins 25
Non-DOM Events 27
v
3. Models and Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
MVC and Namespacing 31
Building an ORM 32
Prototypal Inheritance 33
Adding ORM Properties 34
Persisting Records 35
Adding ID Support 36
Addressing References 37
Loading in Data 38
Including Data Inline 39
Loading Data with Ajax 39
JSONP 43
Security with Cross-Domain Requests 43
Populating Our ORM 44
Storing Data Locally 44
Adding Local Storage to Our ORM 46
Submitting New Records to the Server 47
4. Controllers and State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Module Pattern 50
Global Import 50
Global Export 50
Adding a Bit of Context 51
Abstracting into a Library 52
Loading Controllers After the Document 53
Accessing Views 55
Delegating Events 56
State Machines 58
Routing 60
Using the URL’s Hash 60
Detecting Hash Changes 61
Ajax Crawling 62
Using the HTML5 History API 63
5. Views and Templating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Dynamically Rendering Views 65
Templates 66
Template Helpers 68
Template Storage 69
Binding 70
Binding Up Models 71
vi | Table of Contents
6. Dependency Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
CommonJS 74
Declaring a Module 74
Modules and the Browser 75
Module Loaders 76
Yabble 76
RequireJS 77
Wrapping Up Modules 78
Module Alternatives 79
LABjs 80
FUBCs 80
7. Working with Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Browser Support 81
Getting Information About Files 81
File Inputs 82
Drag and Drop 83
Dragging 84
Dropping 85
Cancel Default Drag/Drop 86
Copy and Paste 87
Copying 87
Pasting 88
Reading Files 89
Blobs and Slices 90
Custom Browse Buttons 91
Uploading Files 91
Ajax Progress 93
jQuery Drag and Drop Uploader 95
Creating a Drop Area 95
Uploading the File 95
8. The Real-Time Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Real Time’s History 97
WebSockets 98
Node.js and Socket.IO 101
Real-Time Architecture 103
Perceived Speed 105
9. Testing and Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Unit Testing 109
Assertions 109
QUnit 110
Table of Contents | vii
Jasmine 113
Drivers 115
Headless Testing 118
Zombie 119
Ichabod 121
Distributed Testing 121
Providing Support 122
Inspectors 122
Web Inspector 123
Firebug 124
The Console 125
Console Helpers 126
Using the Debugger 127
Analyzing Network Requests 128
Profile and Timing 129
10. Deploying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Performance 133
Caching 134
Minification 136
Gzip Compression 137
Using a CDN 138
Auditors 138
Resources 139
11. The Spine Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Setup 141
Classes 142
Instantiation 142
Extending Classes 143
Context 144
Events 145
Models 145
Fetching Records 147
Model Events 147
Validation 148
Persistence 148
Controllers 150
Proxying 151
Elements 152
Delegating Events 152
Controller Events 153
Global Events 153
viii | Table of Contents
The Render Pattern 154
The Element Pattern 154
Building a Contacts Manager 156
Contact Model 157
Sidebar Controller 158
Contacts Controller 160
App Controller 163
12. The Backbone Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Models 165
Models and Attributes 166
Collections 167
Controlling a Collection’s Order 169
Views 169
Rendering Views 170
Delegating Events 170
Binding and Context 171
Controllers 172
Syncing with the Server 174
Populating Collections 175
On the Server Side 175
Custom Behavior 176
Building a To-Do List 178
13. The JavascriptMVC Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Setup 186
Classes 186
Instantiation 186
Calling Base Methods 187
Proxies 187
Static Inheritance 187
Introspection 188
A Model Example 188
Model 189
Attributes and Observables 189
Extending Models 191
Setters 191
Defaults 192
Helper Methods 192
Service Encapsulation 193
Type Conversion 196
CRUD Events 196
Using Client-Side Templates in the View 197
Table of Contents | ix
Basic Use 197
jQuery Modifiers 198
Loading from a Script Tag 198
$.View and Subtemplates 198
Deferreds 199
Packaging, Preloading, and Performance 199
$.Controller: The jQuery Plug-in Factory 200
Overview 202
Controller Instantiation 202
Event Binding 203
Templated Actions 204
Putting It All Together: An Abstract CRUD List 205
A. jQuery Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
B. CSS Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
C. CSS3 Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
x | Table of Contents
Preface
JavaScript has come a long way from its humble beginnings in 1995 as part of the
Netscape browser, to the high-performance JIT interpreters of today. Even just five
years ago developers were blown away by Ajax and the yellow fade technique; now,
complex JavaScript apps run into the hundreds of thousands of lines.
In the last year, a new breed of JavaScript applications has appeared, giving an expe-
rience people were used to on the desktop, but that was unheard of on the Web. Gone
are the slow page requests every time a user interacts with an application; instead,
JavaScript engines are now so powerful we can keep state client side, giving a much
more responsive and improved experience.
It’s not just JavaScript engines that have improved; CSS3 and HTML5 specs haven’t
finished the drafting stage, but they are already widely supported by modern browsers
such as Safari, Chrome, Firefox, and—to some extent—IE9. Beautiful interfaces can
be coded in a fraction of the time previously required, and without all that notorious
image cutting and splicing. Support for HTML5 and CSS3 is getting better every day,
but you’ll need to decide—based on your client base—whether to use these
technologies.
Moving state to the client side is no simple task. It requires a completely different
development approach to server-side applications. You need to think about structure,
templating,communicatingwiththeserver,frameworks,andmuchmore.That’swhere
this book comes in; I’ll take you through all the steps necessary to create state-of-the-
art JavaScript applications.
Who Is This Book For?
This book isn’t for JavaScript newbies, so if you’re unfamiliar with the basics of the
language, I advise you to pick up one of the many good books on the subject, such as
JavaScript: The Good Parts by Douglas Crockford (O’Reilly). This book is aimed at
developers with some JavaScript experience, perhaps using a library like jQuery, who
want to get into building more advanced JavaScript applications. Additionally, many
xi
sections of the book—especially the appendixes—will also be a useful reference for
experienced JavaScript developers.
How This Book Is Organized
Chapter 1
The chapter starts with a discussion of JavaScript’s history and covers some of the
underlying influences of its current implementation and community. We then give
you an introduction to the MVC architectural pattern, in addition to exploring
JavaScript’s constructor functions, prototypal inheritance, and how to create your
own class library.
Chapter 2
This chapter gives you a brief primer on browser events, including their history,
API, and behavior. We’ll cover how to bind to events with jQuery, use delegation,
and create custom events. We’ll also explore using non-DOM events with the
PubSub pattern.
Chapter 3
This chapter explains how to use MVC models in your application, as well as for
loading and manipulating remote data. We’ll explain why MVC and namespacing
are important and then build our own ORM library to manage model data. Next,
we’ll cover how to load in remote data using JSONP and cross-domain Ajax. Fi-
nally, you’ll learn how to persist model data using HTML5 Local Storage and sub-
mitting it to a RESTful server.
Chapter 4
This chapter demonstrates how to use a controller pattern to persist state on the
client side. We’ll discuss how to use modules to encapsulate logic and prevent
global namespace pollution, then we’ll cover how to cleanly interface controllers
with views, listening to events and manipulating the DOM. Finally, we’ll discuss
routing, first using the URL’s hash fragment, and then using the newer HTML5
History API, making sure to explain the pros and cons of both approaches.
Chapter 5
This is where we cover views and JavaScript templating. We cover the different
ways of dynamically rendering views, as well as various templating libraries and
where to actually store the templates (inline in the page, in script tags, or with
remote loading). Then, you’ll learn about data binding—connecting your model
controllers and views to dynamically synchronize model data and view data.
Chapter 6
In this chapter, we’ll get into the details of JavaScript dependency management
using CommonJS modules. You’ll learn the history and thinking behind the Com-
monJS movement, how to create CommonJS modules in the browser, and various
module loader libraries to help you with this, such as Yabble and RequireJS.
Next, we’ll discuss how to automatically wrap up modules server side, increasing
xii | Preface
performance and saving time. Finally, we’ll cover various alternatives to Com-
monJS, such as Sprockets and LABjs.
Chapter 7
Here, we’ll get into some of the benefits HTML5 gives us: the File API. We’ll cover
browser support, multiple uploads, receiving files that are dragged onto the
browser, and files from clipboard events. Next, we’ll explore reading files using
blobs and slices, and displaying the result in the browser. We’ll cover uploading
files in the background using the new XMLHttpRequest Level 2 specification, and
finally, we’ll show you how to give your users live upload progress bars and how
to integrate uploads with jQuery’s Ajax API.
Chapter 8
We’ll take a look at some of the exciting developments with real-time applications
and WebSockets. First, the chapter covers real time’s rather turbulent history and
its current support in the browsers. Then, we’ll get into the details of WebSockets
and their high-level implementation, browser support, and JavaScript API. Next,
we’ll demonstrate a simple RPC server that uses WebSockets to connect up servers
and clients. We’ll then take a look at Socket.IO and learn how real time fits into
applications’ architecture and user experience.
Chapter 9
This chapter covers testing and debugging, a crucial part of JavaScript web appli-
cation development. We’ll look at the issues surrounding cross-browser testing,
which browsers you should test in, and unit tests and testing libraries, such as
QUnit and Jasmine. Next, we’ll take a look at automated testing and continuous
integration servers, such as Selenium. We’ll then get into the debugging side of
things, exploring Firefox and WebKit’s Web Inspectors, the console, and using the
JavaScript debugger.
Chapter 10
This chapter covers another important—but often neglected—part of JavaScript
web applications: deployment. Chiefly, we’ll consider performance and how to use
caching, minification, gzip compression, and other techniques to decrease your
application’s initial load time. Finally, we’ll briefly cover how to use CDNs to serve
static content on your behalf, and how to use the browser’s built-in auditor, which
can be immensely helpful in improving your site’s performance.
Chapter 11
The next three chapters give you an introduction to some popular JavaScript li-
braries for application development. Spine is a lightweight MVC-compliant library
that uses many of the concepts covered in the book. We’ll take you through the
core parts of the library: classes, events, models, and controllers. Finally, we’ll build
anexamplecontactsmanagerapplicationthatwilldemonstratewhatwe’velearned
from the chapter.
Preface | xiii
Chapter 12
Backbone is an extremely popular library for building JavaScript applications, and
this chapter will give you a thorough introduction. We’ll take you through the core
concepts and classes of Backbone, such as models, collections, controllers, and
views. Next, we’ll explore syncing model data with the server using RESTful JSON
queries and how to respond to Backbone appropriately server side. Finally, we’ll
build an example to-do list application that will demonstrate much of the library.
Chapter 13
This chapter explores the JavaScriptMVC library, a popular jQuery-based
framework for building JavaScript web applications. You’ll learn all the basics of
JavaScriptMVC, such as classes, models, and controllers, as well as using client-
side templates to render views. The chapter ends with a practical CRUD list ex-
ample, demonstrating how easy it is to create abstract, reusable, memory-safe
widgets with JavaScriptMVC.
Appendix A
This appendix provides a brief introduction to jQuery, which is useful if you feel
you need to brush up on the library. Most of the book’s examples use jQuery, so
it’s important to be familiar with it. We’ll cover most of the core API, such as
traversing the DOM, manipulating the DOM, and event binding, triggering, and
delegating. Next, we’ll approach jQuery’s Ajax API, making GET and POST JSON
requests. We’ll then cover jQuery extensions and how to use encapsulation to
ensure you’re being a good web citizen. Finally, we’ll take a look at a practical
example: creating a Growl jQuery plug-in.
Appendix B
Appendix B covers Less, a superset of CSS that extends its syntax with variables,
mixins, operations, and nested rules. Less can really reduce the amount of CSS you
need to write—especially when it comes to CSS3 vendor–specific rules. This ap-
pendix covers Less’s major syntax enhancements and how to use the command
line’s tools and JavaScript library to compile Less files down to CSS.
Appendix C
The last appendix is a CSS3 reference. It provides a bit of background on CSS3,
explains vendor prefixes, and then takes you through the major additions to the
specification. Among other CSS3 features, this appendix covers rounded corners,
rgba colors,dropshadows,gradients,transitions,andtransformations.Itendswith
a discussion about graceful degradation using Modernizr and a practical example
of using the new box-sizing specification.
xiv | Preface
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, file extensions, and events.
Constant width
Indicates computer code in a broad sense, including commands, arrays, elements,
statements, options, switches, variables, attributes, keys, functions, types, classes,
namespaces, methods, modules, properties, parameters, values, objects, event
handlers, XML tags, HTML tags, macros, the contents of files, and the output from
commands.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter-
mined by context.
This icon signifies a tip, suggestion, or general note.
This icon indicates a warning or caution.
Accompanying Files
This book’s accompanying files are hosted on GitHub. You can view them online or
downloadaziplocally.Alltheassetsareseparatedbychapter,andanyrequiredlibraries
are also included. Most examples in this book are also available as standalone files.
Whenever a particular asset is referenced inside a chapter, it will be in the form of assets/
chapter_number/name.
Preface | xv
Code Conventions
Throughout this book we’ll use the assert() and assertEqual() functions to demon-
strate the value of variables or the result of a function call. assert() is just shorthand
for indicating that a particular variable resolves to true; it is a common pattern that’s
especially prevalent in automated testing. assert() takes two arguments: a value and
an optional message. If the value doesn’t equal true, the function will throw an error:
var assert = function(value, msg) {
if ( !value )
throw(msg || (value + " does not equal true"));
};
assertEqual() is shorthand for indicating that one variable equals another. It works
similarly to assert(), but it accepts two values. If the two values aren’t equal, the as-
sertion fails:
var assertEqual = function(val1, val2, msg) {
if (val1 !== val2)
throw(msg || (val1 + " does not equal " + val2));
};
Using the two functions is very straightforward, as you can see in the example below.
If the assertion fails, you’ll see an error message in the browser’s console:
assert( true );
// Equivalent to assertEqual()
assert( false === false );
assertEqual( 1, 1 );
I’ve slightly sugar-coated assertEqual() since, as it stands, object comparison will fail
unless the objects share the same reference in memory. The solution is a deep com-
parison, and we’ve included an example of this in assets/ch00/deep_equality.html.
jQuery Examples
A lot of the examples in this book rely on jQuery, an extremely popular JavaScript
library that simplifies events, DOM traversing, manipulation, and Ajax. I’ve decided
this for various reasons, but it’s mostly because jQuery greatly clarifies examples, and
it is closer to the JavaScript most people write in the real world.
If you haven’t used jQuery, I strongly advise you to check it out. It has an excellent API
that provides a good abstraction over the DOM. A brief jQuery primer is included in
Appendix A.
xvi | Preface
Holla
Built as a companion to this book, Holla is a JS group chat application. Holla is a good
example application because it encompasses various best practices covered in this
book. Among other things, Holla will show you how to:
• Use CSS3 and HTML5 to create beautiful interfaces
• Drag and drop to upload files
• Lay out your code using Sprockets and Less
• Use WebSockets to push data to clients
• Create a stateful JavaScript application
Clone the code from Holla’s GitHub repository and take a look. Many of the examples
in this book have been taken from Holla’s source; see Figure P-1.
Figure P-1. Holla, an example chat application
Author’s Note
I wrote this book as I traveled around the world for a year. I wrote some parts in African
huts without electricity and Internet, others in Japanese washitsus overlooking temples
Preface | xvii
and blossoming trees, and some even on remote Cambodian islands. In short, I had a
great time writing this, and I hope reading it gives you just as much pleasure.
Some people deserve their share of the blame. Thanks go to Stuart Eccles, Tim Malbon,
Ben Griffins, and Sean O’Halpin for giving me the chances and opportunity to find my
passion; and to James Adam, Paul Battley, and Jonah Fox for mentoring and putting
up with my asininities.
Thanks also to the technical reviewers, who really helped shape the book: Henrik Jor-
eteg, Justin Meyer, Lea Verou, Addy Osmani, Alex Barbara, Max Williams, and Julio
Cesar Ody.
Most importantly, thanks to my parents for their unwavering support.
Safari® Books Online
Safari Books Online is an on-demand digital library that lets you easily
search over 7,500 technology and creative reference books and videos to
find the answers you need quickly.
Withasubscription,youcanreadanypageandwatchanyvideofromourlibraryonline.
Read books on your cell phone and mobile devices. Access new titles before they are
available for print, and get exclusive access to manuscripts in development and post
feedback for the authors. Copy and paste code samples, organize your favorites, down-
load chapters, bookmark key sections, create notes, print out pages, and benefit from
tons of other time-saving features.
O’Reilly Media has uploaded this book to the Safari Books Online service. To have full
digital access to this book and others on similar topics from O’Reilly and other pub-
lishers, sign up for free at http://my.safaribooksonline.com.
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
(800) 998-9938 (in the United States or Canada)
(707) 829-0515 (international or local)
(707) 829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at:
http://www.oreilly.com/catalog/9781449303518
To comment or ask technical questions about this book, send email to:
xviii | Preface
bookquestions@oreilly.com
For more information about our books, courses, conferences, and news, see our website
at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
Preface | xix
Javascript Web Applications Otx Alex Maccaw
CHAPTER 1
MVC and Classes
Early Days
JavaScript development has changed markedly from how it looked when it was first
conceived. It’s easy to forget how far the language has come from its initial implemen-
tation in Netscape’s browser, to the powerful engines of today, such as Google’s V8.
It’s been a rocky path involving renaming, merging, and the eventual standardization
as ECMAScript. The capabilities we have today are beyond the wildest dreams of those
early innovators.
Despite its success and popularity, JavaScript is still widely misunderstood. Few people
know that it’s a powerful and dynamic object-oriented language. They’re surprised to
learn about some of its more advanced features, such as prototypal inheritance, mod-
ules, and namespaces. So, why is JavaScript so misunderstood?
Part of the reason is due to previous buggy JavaScript implementations, and part of it
is due to the name—the Java prefix suggests it’s somehow related to Java; in reality,
it’s a totally different language. However, I think the real reason is the way most de-
velopers are introduced to the language. With other languages, such as Python and
Ruby, developers usually make a concerted effort to learn the language with the help
of books, screencasts, and tutorials. Until recently, though, JavaScript wasn’t given that
endorsement. Developers would get requests to add a bit of form validation—maybe
a lightbox or a photo gallery—to existing code, often on a tight schedule. They’d use
scripts they’d find on the Internet, calling it a day with little understanding of the lan-
guage behind it. After that basic exposure, some of them might even add JavaScript to
their resumes.
Recently, JavaScript engines and browsers have become so powerful that building full-
blown applications in JavaScript is not only feasible, but increasingly popular. Appli-
cations like Gmail and Google Maps have paved the way to a completely different way
of thinking about web applications, and users are clamoring for more. Companies are
hiring full-time JavaScript developers. No longer is JavaScript a sublanguage relegated
1
to simple scripts and a bit of form validation—it is now a standalone language in its
own right, realizing its full potential.
This influx of popularity means that a lot of new JavaScript applications are being built.
Unfortunately, and perhaps due to the language’s history, many of them are construc-
ted very poorly. For some reason, when it comes to JavaScript, acknowledged patterns
and best practices fly out the window. Developers ignore architectural models like the
Model View Controller (MVC) pattern, instead blending their applications into a messy
soup of HTML and JavaScript.
This book won’t teach you much about JavaScript as a language—other books are
better suited for that, such as Douglas Crockford’s JavaScript: The Good Parts (O’Re-
illy). However, this book will show you how to structure and build complex JavaScript
applications, allowing you to create incredible web experiences.
Adding Structure
The secret to making large JavaScript applications is to not make large JavaScript ap-
plications. Instead, you should decouple your application into a series of fairly inde-
pendent components. The mistake developers often make is creating applications with
a lot of interdependency, with huge linear JavaScript files generating a slew of HTML
tags. These sorts of applications are difficult to maintain and extend, so they should be
avoided at all costs.
Paying a bit of attention to an application’s structure when you start building it can
make a big difference to the end result. Ignore any preconceived notions you have about
JavaScript and treat it like the object-oriented language that it is. Use classes, inheri-
tance, objects, and patterns the same way you would if you were building an application
in another language, such as Python or Ruby. Architecture is critical to server-side
applications, so why shouldn’t the same apply to client-side apps?
The approach this book advocates is the MVC pattern, a tried and tested way of ar-
chitecting applications that ensures they can be effectively maintained and extended.
It’s also a pattern that applies particularly well to JavaScript applications.
What Is MVC?
MVC is a design pattern that breaks an application into three parts: the data (Model),
the presentation layer (View), and the user interaction layer (Controller). In other
words, the event flow goes like this:
1. The user interacts with the application.
2. The controller’s event handlers trigger.
3. The controller requests data from the model, giving it to the view.
4. The view presents the data to the user.
2 | Chapter 1: MVC and Classes
Or, to give a real example, Figure 1-1 shows how sending a new chat message would
work with Holla.
Figure 1-1. Sending a new chat message from Holla
1. The user submits a new chat message.
2. The controller’s event handlers trigger.
3. The controller creates a new Chat Model record.
4. The controller then updates the view.
5. The user sees his new chat message in chat log.
The MVC architectural pattern can even be implemented without libraries or frame-
works. The key is to divide up the responsibilities of the MVC components into clearly
defined sections of code, keeping them decoupled. This allows for independent devel-
opment, testing, and maintenance of each component.
Let’s explore the components of MVC in detail.
The Model
The model is where all the application’s data objects are stored. For example, we might
have a User Model that contains a list of users, their attributes, and any logic associated
specifically with that model.
A model doesn’t know anything about views or controllers. The only thing a model
should contain is data and the logic associated directly with that data. Any event han-
dling code, view templates, or logic not specific to that model should be kept well clear
of it. You know an application’s MVC architecture is violated when you start seeing
view code in the models. Models should be completely decoupled from the rest of your
application.
When controllers fetch data from servers or create new records, they wrap them in
model instances. This means that our data is object oriented, and any functions or logic
defined on the model can be called directly on the data.
What Is MVC? | 3
So, rather than this:
var user = users["foo"];
destroyUser(user);
We can do something like this:
var user = User.find("foo");
user.destroy();
The first example is not namespaced or object oriented. If we have another destroy
User() function defined in our application, the two will conflict. Global variables and
functions should always be kept to an absolute minimum. In the second example, the
destroy() function is namespaced behind User instances, as are all the stored records.
This is ideal, since we’re keeping global variables to a minimum, exposing fewer areas
to potential conflicts. The code is cleaner and can take advantage of inheritance so
functions like destroy() don’t have be defined separately on every model.
Models are explored in much more depth in Chapter 3, which covers topics such as
loading in data from servers and creating object-relational mappers (ORMs).
The View
The view layer is what’s presented to the user and is what she interacts with. In a
JavaScript application, the view would be made up mostly of HTML, CSS, and Java-
Script templates. Apart from simple conditional statements in templates, the views
shouldn’t contain any logic.
In fact, like models, views should also be decoupled from the rest of the application.
Views shouldn’t know anything about controllers and models—they should be inde-
pendent. Mixing up views with logic is one of the surest paths to disaster.
That isn’t to say MVC doesn’t allow for presentational logic—as long as it’s not defined
inside views. Presentational logic resides in what are called helpers: scripts solely for
small utility functions related to the view.
The example below, which includes logic inside views, is something you shouldn’t do:
// template.html
<div>
<script>
function formatDate(date) {
/* ... */
};
</script>
${ formatDate(this.date) }
</div>
In the code above, we’re inserting the formatDate() function directly into the view,
which violates MVC, resulting in an unmaintainable mess of tag soup. By separating
out presentational logic into helpers, as with the example below, we’re avoiding that
problem and keeping our application’s structure MVC-compliant.
4 | Chapter 1: MVC and Classes
// helper.js
var helper = {};
helper.formatDate = function(){ /* ... */ };
// template.html
<div>
${ helper.formatDate(this.date) }
</div>
Inaddition,allpresentationallogicisnamespacedunderthehelper variable,preventing
conflicts and keeping the code clean and extendable.
Don’t worry too much about specifics regarding views and templates—we cover them
extensively in Chapter 5. The aim of this section is to familiarize you with how views
relate to the MVC architectural pattern.
The Controller
Controllersarethegluebetweenmodelsandviews.Controllersreceiveeventsandinput
from views, process them (perhaps involving models), and update the views accord-
ingly. The controller will add event listeners to views when the page loads, such as those
detecting when forms are submitted or buttons are clicked. Then, when the user in-
teracts with your application, the events trigger actions inside the controllers.
You don’t need any special libraries or frameworks to implement controllers; here’s an
example using plain old jQuery:
var Controller = {};
// Use a anonymous function to enscapulate scope
(Controller.users = function($){
var nameClick = function(){
/* ... */
};
// Attach event listeners on page load
$(function(){
$("#view .name").click(nameClick);
});
})(jQuery);
We’re creating a users Controller that is namespaced under the Controller variable.
Then, we’re using an anonymous function to encapsulate scope, preventing variable
pollution of the global scope. When the page loads, we’re adding a click event listener
to a view element.
As you can see, controllers don’t require a library or framework. However, to comply
with MVC’s architectural requirements, they must be separated from Models and
Views. Controllers and states are covered in more detail in Chapter 4.
What Is MVC? | 5
Toward Modularity, Creating Classes
Before we get to the nitty-gritty of MVC, we’re going to cover some preliminary con-
cepts, such as JavaScript classes and events. This will give you a solid foundation before
moving on to some of the more advanced concepts.
JavaScript object literals are fine for static classes, but it’s often useful to create classical
classes with inheritance and instances. It’s important to emphasize that JavaScript is a
prototype language, and as such doesn’t include a native class implementation. How-
ever, support can be emulated fairly easily.
Classes in JavaScript often get a bad rap, criticized for not being part of the “JavaScript
Way,” a term that means essentially nothing. jQuery is effectively neutral when it comes
to structural methodology or inheritance patterns. This can lead JavaScript developers
to believe they shouldn’t consider structure—i.e., that classes aren’t available or
shouldn’t be used. In reality, classes are just another tool, and as a pragmatist, I believe
they’re as useful in JavaScript as in any other modern language.
Rather than class definitions, JavaScript has constructor functions and the new opera-
tor. A constructor function can specify an object’s initial properties and values when it
is instantiated. Any JavaScript function can be used as a constructor. Use the new op-
erator with a constructor function to create a new instance.
The new operator changes a function’s context, as well as the behavior of the return
statement. In practice, using new and constructors is fairly similar to languages with
native class implementations:
var Person = function(name) {
this.name = name;
};
// Instantiate Person
var alice = new Person('alice');
// Check instance
assert( alice instanceof Person );
By convention, constructor functions are upper camel-cased to differentiate them from
normal functions. This is important because you don’t ever want to call a constructor
function without the new prefix.
// Don't do this!
Person('bob'); //=> undefined
The function will just return undefined, and since the context is the window (global)
object, you’ve unintentionally created a global variable, name. Always call constructor
functions using the new keyword.
When a constructor function is called with the new keyword, the context switches from
global (window) to a new and empty context specific to that instance. So, the this
6 | Chapter 1: MVC and Classes
keyword refers to the current instance. Although it might sound complicated, in prac-
tice, you can treat it like native class implementations in other languages.
By default, if you don’t return anything from a constructor function, this—the current
context—will be returned. Otherwise, you can return any nonprimitive type. For ex-
ample, we could return a function that would set up a new class, the first step in building
our own class emulation library:
var Class = function(){
var klass = function(){
this.init.apply(this, arguments);
};
klass.prototype.init = function(){};
return klass;
};
var Person = new Class;
Person.prototype.init = function(){
// Called on Person instantiation
};
// Usage:
var person = new Person;
Confusingly, due to a JavaScript 2 specification that was never implemented, class is
a reserved keyword. The common convention is instead to name class variables as
_class or klass.
Adding Functions to Classes
Adding class functions to a constructor function is the same as adding a property onto
any object in JavaScript:
Person.find = function(id){ /*...*/ };
var person = Person.find(1);
To add instance functions to a constructor function, you need to use the constructor’s
prototype:
Person.prototype.breath = function(){ /*...*/ };
var person = new Person;
person.breath();
A common pattern is to alias a class’ prototype to fn, which is a bit less verbose:
Person.fn = Person.prototype;
Person.fn.run = function(){ /*...*/ };
In fact, you’ll see this pattern throughout jQuery plug-ins, which essentially just add
functions to jQuery’s prototype, aliased to jQuery.fn.
Adding Functions to Classes | 7
Adding Methods to Our Class Library
Currently, our class library includes functionality for instantiating and initializing in-
stances. Adding properties to classes is the same as adding properties to constructor
functions.
Properties set directly on the class will be equivalent to static members:
var Person = new Class;
// Static functions are added directly on the class
Person.find = function(id){ /* ... */ };
// And now we can call them directly
var person = Person.find(1);
And properties set on the class’ prototype are also available on instances:
var Person = new Class;
// Instance functions are on the prototype
Person.prototype.save = function(){ /* ... */ };
// And now we can call them on instances
var person = new Person;
person.save();
However, in my opinion, that syntax is a little convoluted, impractical, and repetitive.
It’s difficult to see, at a glance, a list of your class’ static and instance properties. Instead,
let’s create a different way of adding properties to our classes using two functions,
extend() and include():
var Class = function(){
var klass = function(){
this.init.apply(this, arguments);
};
klass.prototype.init = function(){};
// Shortcut to access prototype
klass.fn = klass.prototype;
// Shortcut to access class
klass.fn.parent = klass;
// Adding class properties
klass.extend = function(obj){
var extended = obj.extended;
for(var i in obj){
klass[i] = obj[i];
}
if (extended) extended(klass)
};
// Adding instance properties
8 | Chapter 1: MVC and Classes
klass.include = function(obj){
var included = obj.included;
for(var i in obj){
klass.fn[i] = obj[i];
}
if (included) included(klass)
};
return klass;
};
In the improved class library above, we’re adding an extend() function to generated
classes,whichacceptsanobject.Theobject’spropertiesareiteratedthroughandcopied
directly onto the class:
var Person = new Class;
Person.extend({
find: function(id) { /* ... */ },
exists: functions(id) { /* ... */ }
});
var person = Person.find(1);
The include() function works in exactly the same way, except properties are copied
onto the class’ prototype, rather than directly onto the class. In other words, the prop-
erties are on the class’ instance, rather than statically on the class.
var Person = new Class;
Person.include({
save: function(id) { /* ... */ },
destroy: functions(id) { /* ... */ }
});
var person = new Person;
person.save();
We’re also implementing support for extended and included callbacks. If these prop-
erties are present on the passed object, they’ll be invoked:
Person.extend({
extended: function(klass) {
console.log(klass, " was extended!");
}
});
If you’ve used classes in Ruby, this should all look very familiar. The beauty of this
approach is that we’ve now got support for modules. Modules are reusable pieces of
code, and they can be used as an alternative to inheritance for sharing common prop-
erties among classes.
var ORMModule = {
save: function(){
// Shared function
Adding Methods to Our Class Library | 9
}
};
var Person = new Class;
var Asset = new Class;
Person.include(ORMModule);
Asset.include(ORMModule);
Class Inheritance Using Prototype
We’ve been using the prototype property a lot, but it hasn’t really been explained yet.
Let’s take a closer look at what it is exactly and how to use it to implement a form of
inheritance in our classes.
JavaScript is a prototype-based language and—rather than make distinctions between
classes and instances—it has the notions of a prototypical object: an object used as a
template from which to get the initial properties for a new object. Any object can be
associated as a prototype of another object, sharing its properties. In practice, you can
look at this as a form of inheritance.
When you fetch a property on an object, JavaScript will search the local object for the
property. If it isn’t found, JavaScript will start searching the object’s prototype and
continue up the prototype tree, eventually reaching Object.prototype. If the property
is found, its value is returned; otherwise, undefined will be returned.
In other words, if you start adding properties to Array.prototype, they’ll be reflected
across every JavaScript array.
To subclass a class and inherit its properties, you need to first define a constructor
function. Then, you need to assign a new instance of the parent class as the prototype
for your constructor function. It looks like this:
var Animal = function(){};
Animal.prototype.breath = function(){
console.log('breath');
};
var Dog = function(){};
// Dog inherits from Animal
Dog.prototype = new Animal;
Dog.prototype.wag = function(){
console.log('wag tail');
};
Now, we can check to see whether the inheritance works:
10 | Chapter 1: MVC and Classes
var dog = new Dog;
dog.wag();
dog.breath(); // Inherited property
Adding Inheritance to Our Class Library
Let’s add inheritance to our custom class library. We’ll pass through an optional parent
class when creating a new class:
var Class = function(parent){
var klass = function(){
this.init.apply(this, arguments);
};
// Change klass' prototype
if (parent) {
var subclass = function() { };
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
};
klass.prototype.init = function(){};
// Shortcuts
klass.fn = klass.prototype;
klass.fn.parent = klass;
klass._super = klass.__proto__;
/* include/extend code... */
return klass;
};
If a parent is passed to the Class constructor, we make sure any subclasses share the
same prototype. This little dance around creating a temporary anonymous function
prevents instances from being created when a class is inherited. The caveat here is that
only instance properties, not class properties, are inherited. There isn’t yet a cross-
browser way of setting an object’s __proto__;. Libraries like Super.js get around this
problem by copying the properties, rather than implementing proper dynamic inheri-
tance.
Now, we can perform simple inheritance by passing parent classes to Class:
var Animal = new Class;
Animal.include({
breath: function(){
console.log('breath');
}
});
var Cat = new Class(Animal)
Adding Inheritance to Our Class Library | 11
// Usage
var tommy = new Cat;
tommy.breath();
Function Invocation
Like everything else in JavaScript, functions are just objects. However, unlike other
objects, they can be invoked. The context inside the function—i.e., the value of this—
depends on where and how it’s invoked.
Apart from using brackets, there are two other ways to invoke a function: apply() and
call(). The difference between them has to do with the arguments you want to pass
to the function.
The apply() function takes two parameters: a context and an array of arguments. If the
context is null, the global context is used. For example:
function.apply(this, [1, 2, 3])
The call() function has exactly the same behavior, yet it is used differently. The first
argument is the context, while each subsequent argument is delegated to the invoca-
tion. In other words, you use multiple arguments—rather than an array like with
apply()—to pass arguments to the function.
function.call(this, 1, 2, 3);
Why would you want to change the context? This is a valid question because other
languages get on fine without allowing explicit context changes. JavaScript uses context
changes to share state, especially during event callbacks. (Personally, I feel this was a
mistake in the design of the language, as it can be confusing for beginners and introduce
bugs. However, it’s too late to change it now, so you need to learn how it works.)
jQuery takes advantage of apply() and call() throughout its API to change context—
for example, when using event handlers or iterating using each(). This can be confusing
at first, but it’s useful when you understand what’s happening:
$('.clicky').click(function(){
// 'this' refers to the element
$(this).hide();
});
$('p').each(function(){
// 'this' refers to the current iteration
$(this).remove();
});
To access the original context, a common pattern stores the value of this in a local
variable. For example:
var clicky = {
wasClicked: function(){
/* ... */
12 | Chapter 1: MVC and Classes
},
addListeners: function(){
var self = this;
$('.clicky').click(function(){
self.wasClicked()
});
}
};
clicky.addListeners();
However, we can use apply to make this much cleaner, wrapping the callback within
another anonymous function, which preserves the original context:
var proxy = function(func, thisObject){
return(function(){
return func.apply(thisObject, arguments);
});
};
var clicky = {
wasClicked: function(){
/* ... */
},
addListeners: function(){
var self = this;
$('.clicky').click(proxy(this.wasClicked, this));
}
};
So, in the above example, we specify the context to be used inside the click callback;
the context jQuery invokes the function in is ignored. In fact, jQuery’s API includes
something to do just this—you guessed it, jQuery.proxy():
$('.clicky').click($.proxy(function(){ /* ... */ }, this));
There are other useful reasons to use apply() and call(), such as delegating. We can
delegate calls from one function to another, and even alter the passed arguments:
var App {
log: function(){
if (typeof console == "undefined") return;
// Turn arguments into a proper array
var args = jQuery.makeArray(arguments);
// Insert a new argument
args.unshift("(App)");
// Delegate to the console
console.log.apply(console, args);
}
};
Function Invocation | 13
Above, we’re making an array of arguments and then adding our own. Finally, the call
is delegated to console.log(). If you’re not familiar with the arguments variable, it’s set
by the interpreter and contains an array of arguments with which the current scope was
called. It’s not a true array though—for example, it’s not mutable—so we have to
convert it to something usable with jquery.makeArray().
Controlling Scope in Our Class Library
The proxy function described in the previous section is such a useful pattern that we
should add it to our class library. We’ll add a proxy function on both classes and in-
stances, allowing us to keep the class’ scope when handing functions off to event han-
dlers and the like:
var Class = function(parent){
var klass = function(){
this.init.apply(this, arguments);
};
klass.prototype.init = function(){};
klass.fn = klass.prototype;
// Adding a proxy function
klass.proxy = function(func){
var self = this;
return(function(){
return func.apply(self, arguments);
});
}
// Add the function on instances too
klass.fn.proxy = klass.proxy;
return klass;
};
We can now use the proxy() function to wrap up functions, making sure they’re in-
voked in the right scope:
var Button = new Class;
Button.include({
init: function(element){
this.element = jQuery(element);
// Proxy the click function
this.element.click(this.proxy(this.click));
},
click: function(){ /* ... */ }
});
14 | Chapter 1: MVC and Classes
If we didn’t wrap the click() callback with a proxy, it would be called within the
context of this.element, rather than Button, causing all sorts of problems. A new spec-
ification of JavaScript—ECMAScript, 5th Edition (ES5)—has also added support for
controlling invocation scope with the bind() function. bind() is called on a function,
making sure the function is called in the context of the specified this value. For exam-
ple:
Button.include({
init: function(element){
this.element = jQuery(element);
// Bind the click function
this.element.click(this.click.bind(this));
},
click: function(){ /* ... */ }
});
This example is equivalent to our proxy() function, and it makes sure the click()
function is called with the correct context. Older browsers don’t support bind() but,
luckily, support can be shimmed easily and implemented manually if needed. A shim
basically implements a compatibility layer on legacy browsers, directly extending the
relevant object’s prototypes, allowing you to use features of ES5 today without wor-
rying about older browsers. For example, a shim that would support bind() would look
like this:
if ( !Function.prototype.bind ) {
Function.prototype.bind = function( obj ) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () {},
bound = function () {
return self.apply( this instanceof nop ? this : ( obj || {} ),
args.concat( slice.call(arguments) ) );
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
Function’s prototype is only overwritten if the feature doesn’t already exist: newer
browsers will continue to use their native implementations. Shimming is especially
useful for arrays, which have had a bunch of new features added in recent JavaScript
versions. I personally use the es5-shim project because it covers as many of the new
features in ES5 as possible.
Controlling Scope in Our Class Library | 15
Adding Private Functions
So far, any property we’ve added to our classes has been open to the world and can be
changed at any time. Let’s now explore how to add private properties to our classes.
A lot of developers end up prefixing private properties with an underscore (_). Although
these can still be changed, it makes it obvious that they’re part of a private API. I try to
steer clear of this approach because it looks rather ugly.
JavaScript does have support for immutable properties; however, this isn’t implemen-
ted across the main browsers, so we’ll have to wait before using this method. Instead,
we’ll use JavaScript anonymous functions to create a private scope, which can only be
accessed internally:
var Person = function(){};
(function(){
var findById = function(){ /* ... */ };
Person.find = function(id){
if (typeof id == "integer")
return findById(id);
};
})();
We’re wrapping all our class’ properties in an anonymous function, then creating local
variables (findById), which can only be accessed in the current scope. The Person var-
iable is defined in the global scope, so it can be accessed from anywhere.
Never define a variable without using the var operator, since it always creates a global
variable. If you need to define a global variable, do so in the global scope or as a property
on window:
(function(exports){
var foo = "bar";
// Expose variable
exports.foo = foo;
})(window);
assertEqual(foo, "bar");
Class Libraries
As with a lot of concepts in this book, it’s good to understand the theory behind classes,
but often in practice, you’ll use a library. jQuery doesn’t include class support natively,
but it can easily be added with a plug-in like HJS. HJS lets you define classes by passing
a set of properties to $.Class.create:
16 | Chapter 1: MVC and Classes
var Person = $.Class.create({
// constructor
initialize: function(name) {
this.name = name;
}
});
To inherit classes, pass their parent as an argument when creating them:
var Student = $.Class.create(Person, {
price: function() { /* ... */ }
});
var alex = new Student("Alex");
alex.pay();
To add class properties, set them directly on the class:
Person.find = function(id){ /* ... */ };
HJS’ API also includes a few utility functions, such as clone() and equal():
var alex = new Student("Alex");
var bill = alex.clone();
assert( alex.equal(bill) );
HJS isn’t your only option; Spine also has a class implementation. To use it, just include
spine.js in the page:
<script src="http://maccman.github.com/spine/spine.js"> </script>
<script>
var Person = Spine.Class.create();
Person.extend({
find: function() { /* ... */ }
});
Person.include({
init: function(atts){
this.attributes = atts || {};
}
});
var person = Person.init();
</script>
Spine’s class library has a similar API to the library we’ve been building throughout this
chapter. Use extend() to add class properties and include() to add instance properties.
To inherit from them, pass parent classes to the Spine.Class instantiator.
If you’re widening your gaze beyond jQuery, Prototype is definitely worth checking
out. It has an excellent class API that was the inspiration for a lot of other libraries.
jQuery’s John Resig has an interesting post on implementing classical inheritance with
the library. It’s well worth reading, especially if you’re interested in the nitty-gritty
behind the JavaScript prototype system.
Class Libraries | 17
Javascript Web Applications Otx Alex Maccaw
CHAPTER 2
Events and Observing
EventsareatthecoreofyourJavaScriptapplication,poweringeverythingandproviding
the first point of contact when a user interacts with your application. However, this is
where JavaScript’s unstandardized birth rears its ugly head. At the height of the browser
wars, Netscape and Microsoft purposely chose different, incompatible event models.
Although they were later standardized by the W3C, Internet Explorer kept its different
implementation until its latest release, IE9.
Luckily, we have great libraries like jQuery and Prototype that smooth over the mess,
giving you one API that will work with all the event implementations. Still, it’s worth
understanding what’s happening behind the scenes, so I’m going to cover the W3C
model here before showing examples for various popular libraries.
Listening to Events
Events revolve around a function called addEventListener(), which takes three argu-
ments: type (e.g., click), listener (i.e., callback), and useCapture (we’ll cover useCap
ture later). Using the first two arguments, we can attach a function to a DOM element,
which is invoked when that particular event, such as click, is triggered on the element:
var button = document.getElementById("createButton");
button.addEventListener("click", function(){ /* ... */ }, false);
We can remove the listener using removeEventListener(), passing the same arguments
we gave addEventListener(). If the listener function is anonymous and there’s no ref-
erence to it, it can’t be removed without destroying the element:
var div = document.getElementById("div");
var listener = function(event) { /* ... */ };
div.addEventListener("click", listener, false);
div.removeEventListener("click", listener, false);
19
As its first argument, the listener function is passed an event object, which you can use
to get information about the event, such as timestamp, coordinates, and target. It also
contains various functions to stop the event propagation and prevent the default action.
As for event types, the supported ones vary from browser to browser, but all modern
browsers have the following:
• click
• dblclick
• mousemove
• mouseover
• mouseout
• focus
• blur
• change (for form inputs)
• submit (for forms)
Check out Quirksmode, which has a full event compatibility table.
Event Ordering
Before we go any further, it’s important to discuss event ordering. If an element and
one of its ancestors have an event handler for the same event type, which one should
fire first when the event is triggered? Well, you won’t be surprised to hear that Netscape
and Microsoft had different ideas.
Netscape 4 supported event capturing, which triggers event listeners from the top-most
ancestor to the element in question—i.e., from the outside in.
Microsoft endorsed event bubbling, which triggers event listeners from the element,
propagating up through its ancestors—i.e., from the inside out.
Event bubbling makes more sense to me, and it is likely to be the model used in day-
to-day development. The W3C compromised and stipulated support for both event
models in their specification. Events conforming to the W3C model are first captured
until they reach the target element; then, they bubble up again.
You can choose the type of event handler you want to register, capturing or bubbling,
which is where the useCapture argument to addEventListener() comes into the picture.
If the last argument to addEventListener() is true, the event handler is set for the cap-
turing phase; if it is false, the event handler is set for the bubbling phase:
20 | Chapter 2: Events and Observing
// Use bubbling by passing false as the last argument
button.addEventListener("click", function(){ /* ... */ }, false);
The vast majority of the time, you’ll probably be using event bubbling. If in doubt, pass
false as the last argument to addEventListener().
Canceling Events
When the event is bubbling up, you can stop its progress with the stopPropagation()
function, located on the event object. Any handlers on ancestor elements won’t be
invoked:
button.addEventListener("click", function(e){
e.stopPropagation();
/* ... */
}, false);
Additionally, some libraries like jQuery support a stopImmediatePropagation() func-
tion, preventing any further handlers from being called at all—even if they’re on the
same element.
Browsers also give default actions to events. For example, when you click on a link, the
browser’s default action is to load a new page, or when you click on a checkbox,
the browser checks it. This default action happens after all the event propagation phases
and can be canceled during any one of those. You can prevent the default action with
the preventDefault() function on the event object. Alternatively, you can just return
false from the handler:
form.addEventListener("submit", function(e){
/* ... */
return confirm("Are you super sure?");
}, false);
If the call to confirm() returns false—i.e., the user clicks cancel in the confirmation
dialog—the event callback function will return false, canceling the event and form
submission.
The Event Object
As well as the aforementioned functions—stopPropagation() and preventDefault()—
the event object contains a lot of useful properties. Most of the properties in the W3C
specification are documented below; for more information, see the full specification.
Type of event:
bubbles
A boolean indicating whether the event bubbles up through the DOM
The Event Object | 21
Properties reflecting the environment when the event was executed:
button
A value indicating which, if any, mouse button(s) was pressed
ctrlKey
A boolean indicating whether the Ctrl key was pressed
altKey
A boolean indicating whether the Alt key was pressed
shiftKey
A boolean indicating whether the Shift key was pressed
metaKey
A boolean indicating whether the Meta key was pressed
Properties specific to keyboard events:
isChar
A boolean indicating whether the event has a key character
charCode
A unicode value of the pressed key (for keypress events only)
keyCode
A unicode value of a noncharacter key
which
A unicode value of the pressed key, regardless of whether it’s a character
Where the event happened:
pageX, pageY
The event coordinates relative to the page (i.e., viewport)
screenX, screenY
The event coordinates relative to the screen
Elements associated with the event:
currentTarget
The current DOM element within the event bubbling phase
target, originalTarget
The original DOM element
relatedTarget
The other DOM element involved in the event, if any
These properties vary in browsers, especially among those that are not W3C-compliant.
Luckily, libraries like jQuery and Prototype will smooth out any differences.
22 | Chapter 2: Events and Observing
Event Libraries
In all likelihood you’ll end up using a JavaScript library for event management; other-
wise, there are just too many browser inconsistencies. I’m going to show you how to
use jQuery’s event management API, although there are many other good choices, such
as Prototype, MooTools, and YUI. Refer to their respective APIs for more in-depth
documentation.
jQuery’s API has a bind() function for adding cross-browser event listeners. Call this
function on jQuery instances, passing in an event name and handler:
jQuery("#element").bind(eventName, handler);
For example, you can register a click handler on an element like so:
jQuery("#element").bind("click", function(event) {
// ...
});
jQuery has some shortcuts for event types like click, submit, and mouseover. It looks
like this:
$("#myDiv").click(function(){
// ...
});
It’s important to note that the element must exist before you start adding events to
it—i.e., you should do so after the page has loaded. All you need to do is listen for the
window’s load event, and then start adding listeners:
jQuery(window).bind("load", function() {
$("#signinForm").submit(checkForm);
});
However, there’s a better event to listen for than the window’s load, and that’s
DOMContentLoaded. It fires when the DOM is ready, but before the page’s images and
stylesheets have downloaded. This means the event will always fire before users can
interact with the page.
The DOMContentLoaded event isn’t supported in every browser, so jQuery abstracts
it with a ready() function that has cross-browser support:
jQuery.ready(function($){
$("#myForm").bind("submit", function(){ /* ... */ });
});
In fact, you can skip the ready() function and pass the handler straight to the jQuery
object:
jQuery(function($){
// Called when the page is ready
});
Event Libraries | 23
Context Change
One thing that’s often confusing about events is how the context changes when the
handler is invoked. When using the browser’s native addEventListener(), the context
is changed from the local one to the targeted HTML element:
new function(){
this.appName = "wem";
document.body.addEventListener("click", function(e){
// Context has changed, so appName will be undefined
alert(this.appName);
}, false);
};
To preserve the original context, wrap the handler in an anonymous function, keeping
a reference to it. We covered this pattern in Chapter 1, where we used a proxy function
to maintain the current context. It’s such a common pattern that jQuery includes a
proxy() function—just pass in the function and context in which you want it to be
invoked:
$("signinForm").submit($.proxy(function(){ /* ... */ }, this));
Delegating Events
It may have occurred to you that since events bubble up, we could just add a listener
on a parent element, checking for events on its children. This is exactly the technique
that frameworks like SproutCore use to reduce the number of event listeners in the
application:
// Delegating events on a ul list
list.addEventListener("click", function(e){
if (e.currentTarget.tagName == "li") {
/* ... */
return false;
}
}, false);
jQuery has a great way of doing this; simply pass the delegate() function a child se-
lector, event type, and handler. The alternative to this approach would be to add a
click event to every li element. However, by using delegate(), you’re reducing the
number of event listeners, improving performance:
// Don't do this! It adds a listener to every 'li' element (expensive)
$("ul li").click(function(){ /* ... */ });
// This only adds one event listener
$("ul").delegate("li", "click", /* ... */);
24 | Chapter 2: Events and Observing
Another advantage to event delegation is that any children added dynamically to the
element would still have the event listener. So, in the above example, any li elements
added to the list after the page loaded would still invoke the click handler.
Custom Events
Beyond events that are native to the browser, you can trigger and bind them to your
own custom events. Indeed, it’s a great way of architecting libraries—a pattern a lot of
jQuery plug-ins use. The W3C spec for custom events has been largely ignored by the
browser vendors; you’ll have to use libraries like jQuery or Prototype for this feature.
jQuery lets you fire custom events using the trigger() function. You can namespace
event names, but namespaces are separated by full stops and reversed. For example:
// Bind custom event
$(".class").bind("refresh.widget", function(){});
// Trigger custom event
$(".class").trigger("refresh.widget");
And to pass data to the event handler, just pass it as an extra parameter to trigger().
The data will be sent to callbacks as extra arguments:
$(".class").bind("frob.widget", function(event, dataNumber){
console.log(dataNumber);
});
$(".class").trigger("frob.widget", 5);
Like native events, custom events will propagate up the DOM tree.
Custom Events and jQuery Plug-Ins
Custom events, often used to great effect in jQuery plug-ins, are a great way to architect
any piece of logic that interacts with the DOM. If you’re unfamiliar with jQuery plug-
ins, skip ahead to Appendix B, which includes a jQuery primer.
If you’re adding a piece of functionality to your application, always consider whether
it could be abstracted and split out in a plug-in. This will help with decoupling and
could leave you with a reusable library.
For example, let’s look at a simple jQuery plug-in for tabs. We’re going to have a ul
list that will respond to click events. When the user clicks on a list item, we’ll add an
active class to it and remove the active class from the other list items:
<ul id="tabs">
<li data-tab="users">Users</li>
<li data-tab="groups">Groups</li>
</ul>
<div id="tabsContent">
Custom Events and jQuery Plug-Ins | 25
<div data-tab="users"> ... </div>
<div data-tab="groups"> ... </div>
</div>
In addition, we have a tabsContent div that contains the actual contents of the tabs.
We’ll also be adding and removing the active class from the div’s children, depending
on which tab was clicked. The actual displaying and hiding of the tabs will be done by
CSS—our plug-in just toggles the active class:
jQuery.fn.tabs = function(control){
var element = $(this);
control = $(control);
element.find("li").bind("click", function(){
// Add/remove active class from the list-item
element.find("li").removeClass("active");
$(this).addClass("active");
// Add/remove active class from tabContent
var tabName = $(this).attr("data-tab");
control.find(">[data-tab]").removeClass("active");
control.find(">[data-tab='" + tabName + "']").addClass("active");
});
// Activate first tab
element.find("li:first").addClass("active");
// Return 'this' to enable chaining
return this;
};
The plug-in is on jQuery’s prototype, so it can be called on jQuery instances:
$("ul#tabs").tabs("#tabContent");
What’s wrong with the plug-in so far? Well, we’re adding a click event handler onto all
the list items, which is our first mistake. Instead, we should be using the delegate()
function covered earlier in this chapter. Also, that click handler is massive, so it’s dif-
ficult to see what’s going on. Furthermore, if another developer wanted to extend our
plug-in, he’d probably have to rewrite it.
Let’s see how we can use custom events to clean up our code. We’ll fire a change.tabs
event when a tab is clicked, and bind several handlers to change the active class as
appropriate:
jQuery.fn.tabs = function(control){
var element = $(this);
control = $(control);
element.delegate("li", "click", function(){
// Retrieve tab name
var tabName = $(this).attr("data-tab");
// Fire custom event on tab click
element.trigger("change.tabs", tabName);
26 | Chapter 2: Events and Observing
});
// Bind to custom event
element.bind("change.tabs", function(e, tabName){
element.find("li").removeClass("active");
element.find(">[data-tab='" + tabName + "']").addClass("active");
});
element.bind("change.tabs", function(e, tabName){
control.find(">[data-tab]").removeClass("active");
control.find(">[data-tab='" + tabName + "']").addClass("active");
});
// Activate first tab
var firstName = element.find("li:first").attr("data-tab");
element.trigger("change.tabs", firstName);
return this;
};
See how much cleaner the code is with custom event handlers? It means we can split
up the tab change handlers, and it has the added advantage of making the plug-in much
easier to extend. For example, we can now programmatically change tabs by firing our
change.tabs event on the observed list:
$("#tabs").trigger("change.tabs", "users");
We could also tie up the tabs with the window’s hash, adding back button support:
$("#tabs").bind("change.tabs", function(e, tabName){
window.location.hash = tabName;
});
$(window).bind("hashchange", function(){
var tabName = window.location.hash.slice(1);
$("#tabs").trigger("change.tabs", tabName);
});
The fact that we’re using custom events gives other developers a lot of scope when
extending our work.
Non-DOM Events
Event-based programming is very powerful because it decouples your application’s
architecture, leading to better self-containment and maintainability. Events aren’t re-
stricted to the DOM though, so you can easily write your own event handler library.
The pattern is called Publish/Subscribe, and it’s a good one to be familiar with.
Publish/Subscribe, or Pub/Sub, is a messaging pattern with two actors, publishers, and
subscribers. Publishers publish messages to a particular channel, and subscribers sub-
scribe to channels, receiving notifications when new messages are published. The key
Non-DOM Events | 27
here is that publishers and subscribers are completely decoupled—they have no idea
of each other’s existence. The only thing the two share is the channel name.
The decoupling of publishers and subscribers allows your application to grow without
introducing a lot of interdependency and coupling, improving the ease of maintenance,
as well as adding extra features.
So, how do you actually go about using Pub/Sub in an application? All you need to do
is record handlers associated with an event name and then have a way of invoking them.
Here’s an example PubSub object, which we can use for adding and triggering event
listeners:
var PubSub = {
subscribe: function(ev, callback) {
// Create _callbacks object, unless it already exists
var calls = this._callbacks || (this._callbacks = {});
// Create an array for the given event key, unless it exists, then
// append the callback to the array
(this._callbacks[ev] || (this._callbacks[ev] = [])).push(callback);
return this;
},
publish: function() {
// Turn arguments object into a real array
var args = Array.prototype.slice.call(arguments, 0);
// Extract the first argument, the event name
var ev = args.shift();
// Return if there isn't a _callbacks object, or
// if it doesn't contain an array for the given event
var list, calls, i, l;
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
// Invoke the callbacks
for (i = 0, l = list.length; i < l; i++)
list[i].apply(this, args);
return this;
}
};
// Example usage
PubSub.subscribe("wem", function(){
alert("Wem!");
});
PubSub.publish("wem");
You can namespace events by using a separator, such as a colon (:).
PubSub.subscribe("user:create", function(){ /* ... */ });
28 | Chapter 2: Events and Observing
Other documents randomly have
different content
Auf dem Altenteil
Eine Silvester-
Stimmung
I.
ie hatten den Senioren der Familie alle Ehre angetan, wie
sich das denn auch wohl so von Rechts wegen gebührte;
aber der Lärm wurde den weißhaarigen Herrschaften
allmählich doch ein wenig zu arg. Die alte Dame, die immer noch um
ein paar Jahre jünger war als der alte Herr, hatte dem letzteren ein
ihm schon längst wohlbekanntes kopfschüttelnd Lächeln gezeigt,
welches weiter nichts bedeutete als:
„Kind, Kind, bedenke den Morgen und deinen Rheumatismus! Es hat
alles seine Zeit, und ich glaube, die unsrige ist jetzt vorhanden.“
Der alte Herr hatte zuerst ganz erstaunt aufgesehen und sein Weib
an: Nicht mehr bis Mitternacht, und in das neue Jahr hinein? Ei, ei,
ei — hm!
„Hm,“ sagte der alte Herr, in dem fröhlichen Kreise erhitzter
Gesichter umherblickend; „es hat freilich alles seine Zeit; aber es ist
sonderbar, und, liebe Kinder, es kommt einem ganz kurios vor, wenn
auch dieses — zum erstenmal Zeit wird!“
Dabei hatte er sich aber bereits etwas mühsam aus seinem Sessel
erhoben. Den Kopf schüttelte er auch; jedoch ohne dabei zu lächeln
wie seine Frau.
„Du hast recht, Anna; es ist unsere Zeit gekommen, und so wünsche
ich, wünschen wir euch jungem Volk —“
Von einem Gewissen war bei diesem „jungen Volk“ natürlich nicht
die Rede. Dazu waren sie sämtlich (auch die Ältesten unter ihnen)
noch viel zu jung, und viel zu vergnügt und viel zu aufgeregt durch
die uralten, ewig jungen Stimmungen der letzten Stunden des
scheidenden Jahres. Ein Gewühl von blonden und braunen Köpfchen
und Köpfen, von Händen und Händchen erhob sich um die beiden
Greise; und alle Verführungskünste, deren die Menschheit in ihrer
Erscheinung als Familie in der Silvesternacht fähig ist, waren zur
Anwendung gebracht worden.
Einmal noch schadete es sicherlich gewiß nicht!... Großpapa und
Großmama hatten noch nie so munter ausgesehen!... Es ging ja
niemand zu Bett vor Mitternacht, selbst die Jüngsten nicht!...
„Nun, Mutter! Einmal noch? Was meinst du?“ Kleine weiße Händchen
— weiße beringte Hände hatten ihre Verführungskünste nicht ohne
Erfolg versucht; nun legte sich statt anderer Antwort auf die Frage
des alten Herrn wieder eine Hand auf die seinige. Das war aber
keine weiche, keine weiße, keine kräftige mehr; aber eine starke und
treue war es auch; vielleicht wohl die stärkste und treueste.
„Die Großmutter hat recht! Es hat alles seine Zeit, und die unsrige ist
gekommen. Junges Volk, wir werden zu Bette geschickt von ihr, der
Madame Zeit, während die Jüngsten aufbleiben dürfen. Der Kopf
summt uns zu sehr morgen früh, wenn wir uns dagegen sperren und
wehren; und es ist zwar hübsch von Großmama, wenn sie nur von
Rheumatismus spricht; aber das rechte Wort ist es eigentlich nicht.
Sie hätte ganz dreist Gicht sagen können, gerade so gut wie der
Herr Schwiegersohn und Doctor medicinae da hinter seinem
Punschglase, wenn er jetzt ein Gewissen hätte. Liebe Kinder, wir sind
beide über siebenzig Jahre alt, und —“
„Oh!...“
„Und wir sind sehr glücklich und behaglich. Sehr wohl ist uns zumute
und so wünschen wir euch allen zum erstenmal vor Ablauf des alten
Jahres ein glückliches neues.... Bitte, lieber Sohn, ich weiß, was du
sagen willst; aber wende dich damit an die Mama, die wird dich
versichern, daß deine Frau, unsere liebe Sophie da, heute über
dreißig Jahre sicherlich gleichfalls viel verständiger sein wird, als du.
Wende dich an deine Mutter, mein Schmeichelkätzchen Marie. Sie
hat immer gemeint, du seiest ganz ihr Vorbild, also wirst du wohl
wissen, was in vierzig Jahren in der Neujahrsnacht deine Meinung
sein wird, wenn die unverständige Jugend dir deinen Mann da
verführen will. Schieben Sie die Kinder nicht so heran, lieber
Schwiegersohn, sie machen der Großmama nur das Herz schwer. Es
ist Zeit geworden für uns; — — — ein fröhliches, segensreiches Jahr
ihr — alle!...“
„Alle!“ jubelten sie, und die Gläser hatten geklungen, und die Kinder,
die Enkel hatten sich zugedrängt und ihre kleinen Becher
hingehalten, ohne daß man sie dazu zu schieben brauchte. Sie
hatten sehr gejubelt; und die Tonwellen der Gläser und der Stimmen
waren verklungen.
„Nun seid weiter vergnügt; aber die Kinder laßt ihr mir morgen
ausschlafen. Begleitung nehmen wir nicht mit, die Trepp’ hinauf. Wir
finden unseren Weg schon allein, nicht wahr, Walter?“ sagte die alte
Dame, die Großmutter des Hauses.
II.
ie entschlüpften, wie man entschlüpft, wenn man das
siebenzigste Lebensjahr hinter sich hat. Langsam stiegen
die beiden die teppichbelegte Treppe in ihre Stube hinauf,
der Greis gestützt auf den Arm der Greisin; und dann waren sie
allein miteinander, noch einmal allein miteinander in der
Neujahrsnacht.... Umgesehen hatten sie sich nicht auf der Treppe
und einen leisen Schritt, einen Kinderschritt, der ihnen nachglitt, den
hatten sie überhört. Ein so scharfes Ohr, wie vor Jahren, hatte keins
von den zwei Alten mehr; aber diesen Schritt, diesen Geister-
Kinderschritt würde auch wohl jedes andere jüngere Ohr überhört
haben. —
Auf dem Altenteil! Das kann eines der bittersten Worte sein, die das
Schicksal den Menschen in dieser Welt zuruft; aber auch eines der
behaglichsten. Für diese beiden Alten war es nach langer schwerer,
mühseliger Arbeit ein behagliches geworden. Sie fanden ihre
Gemächer durch ein verschleiertes Lampenlicht erhellt, ihre beiden
Lehnstühle an den warmen Ofen gerückt und:
„Mit dem Schlage Zwölf komme ich doch und poche an eurer
Kammertür und spreche meinen Wunsch durchs Schlüsselloch. Ihr
braucht aber nicht darauf zu hören; ich schicke ihn euch auch in den
Schlaf hinein!“ hatte das jüngste und am jüngsten verheiratete
Töchterlein als letztes Wort im Festsaale da unten gesagt.
„O mein Gott, da sitzt ihr noch?“ rief dieselbe junge Frau unter dem
Glockenklang und dem Neujahrschoral von den Türmen, unter dem
plötzlich aufklingenden Gassenjubel und dem Jubel der Kinder und
Enkel in dem Saale des Hauses. „Das ist doch ganz wider die
Abrede, und heute übers Jahr werden wir euch da unten bei uns
fester halten, ihr Lieben, Bösen, Besten!... Ein glückliches neues
Jahr, Großpapa! ein glückliches neues Jahr, Großmama!“
Da stand ein niedrig lehnenloses Sesselchen mit einem verblaßten
gestickten Blumenstrauß darauf neben den zwei Stühlen der Greise.
Die junge Frau, nachdem sie den Vater und die Mutter mit ihren
Küssen fast erstickt hatte, saß nieder auf dem kleinen Stuhl und
hatte keine Ahnung davon, wer eben vor ihr darauf gesessen und
die Mutter und den Vater gegen die Abrede und gegen ihren eigenen
festen Vorsatz wach gehalten hatte über die Mitternachtsstunde
hinaus und aus dem alten Jahr in das neue hinein! Mit leise
bebender Hand strich die alte Frau die blonden Haare der Tochter
aus dem lebensfreudigen, glühenden, erhitzten Gesichte. Die
blonden Locken, die sich eben vor ihr ringelnd bewegt hatten, waren
schon vor vierzig Jahren zu Staub und Asche geworden: die junge
Frau wußte nichts von ihnen, oder doch nur gerüchtweise. Lange vor
ihrer Geburt war das erste, das älteste Kind gestorben, zwölf Jahre
alt. Ein halbverwischtes Pastellbildchen, das über der Kommode der
Mutter, der Großmutter des Hauses, hing, war alles, was von ihm
übrig geblieben war in der Welt.
Alles?
III.
in leiser Schritt, ein unhörbarer Schritt; — ein Geister-
Kinderschritt in der Silvesternacht!... Wir haben gesagt,
daß die beiden Greise vor einer Stunde die Treppe zu ihren
Gemächern hinaufgestiegen und ihn, wie wir übrigen alle, nicht
vernahmen. Ganz war es doch nicht so.
Als der alte Herr der alten Dame mit immer noch zierlicher
Höflichkeit die Tür öffnete, um sie zuerst über die Schwelle treten zu
lassen, hatte die Frau einen Augenblick gezögert und zurückgesehen
und gehorcht.
Der alte Herr glaubte, sie horche noch einmal auf den fröhlichen
Lärm, auf das heitere Stimmengewirr der Neujahrsnacht dort unten
im Festsaal des Hauses.
„Sie sind gottlob recht heiter,“ meinte er, „wüßte auch nicht, weshalb
nicht. Und auch wir, — Mutter! — nicht wahr, Alte?... Wie spät ist es
denn eigentlich? Elf Uhr! Noch früh am Tage, wenngleich wirklich ein
wenig spät im Jahre.“
„Ja, Walter!“ hatte die Greisin erwidert, aber nur, um doch eine
Antwort zu geben. „Ich hörte eigentlich nicht auf dich; ich dachte an
unser Ännchen,“ fügte sie hinzu, als sich die Tür hinter ihnen
geschlossen hatte und sie in der letzten Stunde des ablaufenden
Jahres mit sich allein waren.
IV.
as junge Volk! Längst hat es drei Viertel des Hauses nach
seinem Geschmack und Bedürfnis eingerichtet und mit
vollem Rechte des Lebens. An das Reich der beiden Alten
hat keine Hand gerührt; außer dann und wann eine Kinderhand,
deren volles Recht des Lebens es freilich ist und immerdar sein wird,
in der Großväter und der Großmütter Hausrat, Schubladen und
Schränken zu wühlen und zu kramen und sich die vom Anfang der
Welt an dazugehörigen erstaunungswürdigen, lustigen und traurigen
Geschichten erzählen zu lassen.
Es war einmal!... oh, noch einmal von dem, was war!... Und so war
es gekommen, daß die jüngste Tochter des Hauses die Eltern um
Mitternacht noch wach fand unter den Glocken, die das neue Jahr
einläuteten. Eine Kinderhand aber war es wiederum gewesen, die an
den Schleiern der Vergangenheit gezupft hatte: „Es war einmal! Ich
bin da! — Mama, du sagst in dieser Stunde nicht: Man hat doch
keinen Augenblick Ruhe vor dir, Kind! — Ich bin da; und nun laßt
mich sitzen auf meinem Stuhl, laßt uns erzählen: Es war einmal!...
laßt uns erzählen von dem, was einmal war!“...
Und sie hatten davon erzählt, die beiden Greise nämlich. Das Kind
hatte nur drein gesprochen.
„Sie wäre gewiß auch eine stattliche Frau und eine gute geworden,“
sagte die alte Dame. „Ich meine, am meisten hätte sie wohl der
Theodore geglichen, wenn wir sie behalten hätten, das liebe Kind.
Sie haben alle da unten, — unsere meine ich, Papa! — ein hübsches
lustiges Lachen; aber ich kann nichts dafür, ich muß es sagen: wie
das Kind, unser Ännchen, ist doch keins so glücklich in seinem
Lachen gewesen. Die andern kennen wir ja auch nun schon lange
mit ihren Sorgen und ihren Nöten und ihren unnützen Ärgernissen.
Keins von ihnen lacht und kreischt und kichert so wie mein Ännchen
es tat. Hätten wir die Enkel nicht, so würde das Haus wohl
manchmal still genug sein; — selbst dir, Großpapa.“
Da war das Lachen, das vor so langen, langen Jahren zuerst das
Haus hell und heiter gemacht hatte! Auch der alte Herr, der
Großpapa, dem das Haus nie ruhig genug sein konnte, kannte es
ganz genau.
„Also, ihr wißt es doch noch, wie es war, als wir drei allein waren,
und dein Haar noch nicht so weiß, Vater; und auch deines nicht so
hübsch grau, mein Mütterchen, und ich euer liebes, einziges
Mädchen! Hier sitze ich auf meinem Stuhl und behalte mein Recht,
allen meinen Schwestern und Brüdern und allen meinen Nichten und
Neffen zum Trotz. Ich bin die Älteste! Wer auch nach mir gekommen
ist, wie viele auch gesessen haben auf diesem Schemelchen — mir
gehört es, mir habt ihr es hierher gestellt; das ist mein Sitz am
Herde! Wer kann mir meinen Platz nehmen in eurer Seele? wer in
dem Hause, das ihr gebaut habt und in dem ihr mich einmal euer
Glück nanntet?!“
„Du hast recht, Mutter,“ sagte der alte Herr; „ich weiß eigentlich
nicht, wie wir gerade jetzt darauf kommen; aber das Kind hat immer
zu mir, — zu uns gehört. Nur weil wir es wußten, haben wir nicht
immer dran gedacht. So geht es aber mit allem Wissenswürdigen in
der Welt.“
„Mein Ännchen!“ seufzte einfach die Greisin; doch die blonden
Locken wurden wie mutwillig von neuem geschüttelt, und wieder
legte sich der kleine Finger schalkhaft auf den Mund: „Ja, ich war
immer da, wenn ihr auch nicht an mich zu denken glaubtet: an
manchem schwülen Sommertage, in mancher kalten, dunkeln,
trostlosen Winternacht. An manchem Feste in der lichtstrahlenden
Winternacht, an manchem sonnigen, seufzervollen Frühlingsmorgen.
Jetzt haben die andern da unten im Saale euere Sorgen, Freuden
und Arbeiten. Ihr aber habt Zeit für mich. Eure andern, die nach mir
gekommen sind, haben mir wohl mein altes Spielzeug verkramt und
zerbrochen; aber mein Plätzchen im Hause haben sie mir nicht
nehmen können. Ich habe es ihnen nur geliehen, einem nach dem
andern; doch mein Eigentum ist es und bleibt es; nicht wahr, Papa
und Mama?! Ihr habt zwar unter den andern gottlob nun auch
wieder ein Ännchen — ein Enkelkind mit meinem Namen — aber das
tut nichts, wir vertragen uns schon um diesen kleinen Stuhl und um
— euch!... Es war wohl ein kleiner Sarg, in den ihr mich legen
mußtet; aber — ich bin immer über meine Jahre klug gewesen. Ich
habe es wohl oft heimlich erlauscht, wenn ihr das über mich sagtet.
Damals wußte ich freilich nicht recht, was ihr damit sagen wolltet,
und ob es eigentlich ein Lob für mich sei; jetzt aber weiß ich es. Ei
ja, ich bin sehr klug für meine Jahre gewesen! nun lacht nur, wie ihr
damals geweint habt, als ich von euch weggeführt wurde und nicht
über die Schulter zurücksehen durfte. Seht ihr wohl, da lächelt ihr
wenigstens schon. Die Jahre sind nun hingegangen; lange, lange
Jahre! Heute abend habt ihr euch vorgenommen, noch einmal jung
zu sein mit euren Kindern und Enkeln. Es ist euch auch wohl
gelungen, doch nicht ganz. Ganz jung seid ihr erst jetzt wieder, da
ich mich zu euch gesetzt habe, ich — euere Älteste und euere
Jüngste. Nimm meinen Krauskopf wieder zwischen deine Hände,
Mutter, laß mich wieder auf deinem Knie sitzen, Väterchen; draußen
schneit es sehr, und der Nordwind bläst, und es ist spät in der
Nacht; ihr aber schickt mich diesmal noch nicht zu Bett; — wir
wollen jetzt einander noch nicht zu Bette schicken; wir wollen noch
einmal ein Weilchen sitzen und erzählen von d e m , w a s e i n m a l
w a r .“
V.
ie hatten nur noch fünf Minuten in ihren Großväterstühlen
neben dem Ofen sitzen wollen, um sich von dem Feste,
dem Händedrücken, all den Küssen und guten Wünschen
zu dem neuen kommenden Jahre ein wenig zu erholen, wie es den
ältesten Leuten in der Familie geziemt in der Silvesternacht, während
die Jugend um die lichterglänzende Festtafel weiter jubelt und lärmt,
nach der Uhr sieht und den Sekundenzeiger mit lachendem Auge
verfolgt bis heran an den neuen ernsten Grenzstein ihrer Erdenzeit.
Und sie, die bereits Greise waren, hatten nicht nach der Uhr
gesehen; sie hatten gar nicht einmal daran gedacht. Die Sekunden
der letzten Stunden des Jahres waren ihnen dahingeglitten, wie die
vielen, langen arbeitsvollen, inhaltreichen Jahre ihres Daseins selber
bis in dieses jüngste und das eben vor der Tür stehende hinein.
„Du fragst wohl, Vater, wie wir gerade jetzt darauf kommen, und
sagst, daß du an das Kind lange nicht gedacht hast,“ sagte die alte
Dame. „Es ist freilich lange her, daß wir ihren kleinen Sarg dort in
dem Saale, wo sie jetzt gottlob so lustig sind, aufstellen mußten. Wie
wunderlich es doch ist, daß ich gerade jetzt darauf komme, was für
eine schöne Sommernacht es war, in welcher sie starb! Horch jetzt
nur, wie der Wind den Schnee gegen die Fenster treibt. Wir haben
die andern alle behalten und wir haben an unseren Kindeskindern
Freude; aber an unsere Älteste habe ich doch immer gedacht. Was
würde aus den Kindern werden, wenn ihre Mütter nicht immer an sie
dächten. Selbst die Gestorbenen können ohne ihre Mutter nicht
auskommen. — Horch, wie sie es da unten treiben! eigentlich ist es
recht unrecht von ihnen, daß sie auch die Jüngsten so lange aus
dem Bette zurückhalten, und ich werde ihnen morgen früh auch
jedenfalls meine Meinung darüber sagen. — Als s i e in ihrem Fieber
lag, saß ich auch und zerrang mir die Hände und fragte mich Tag
und Nacht, was ich hätte anders machen können, damit das
Schreckliche nicht so zu kommen brauchte. Du warst wohl
vernünftiger, wenn du aus deinem Kontor heraufkamst und mir
zuredetest, Geduld zu haben. Wie konnte ich wohl verständig sein
und Geduld haben? Und man sucht doch immer so, wie man einem
andern die Schuld geben kann, und wäre man das auch selber!“
„Ich meine, Mutter, wir geben das auf, uns den Kopf darüber zu
zerbrechen, und noch dazu so spät in der Nacht, im Jahr und in den
Jahren,“ sprach der alte Herr, wiederum sehr vernünftig; und dann
sprachen sie bis zu dem ersten Glockenschlage der Mitternacht
nichts mehr miteinander. Dagegen aber füllte sich ihre Stube immer
mehr mit den Bildern und den Klängen der Vergangenheit. Und der
liebliche Spuk der Silvesternacht hatte nicht das geringste vom
Phantasten an sich. Das älteste Kind des Hauses war noch einmal im
vollen blühenden Leben Herrin im Reich und fand all sein altes
verkramtes Spielzeug wieder, wie — die zwei weißhaarigen Greise.
Sie paßten wieder ganz zueinander, die Eltern und das Kind: der
dunkle, geheimnisvolle Vorhang der Zukunft hatte sich bewegt, und
es war eine Kinderhand, die sich aus den schwarzen Falten weiß und
zierlich hervorstreckte und winkte. Sie aber, die Fröhlichen da unten
im Festsaale des Hauses, hatten dem Vater und der Mutter, dem
Großvater und der Großmutter — den beiden Alten ein glückliches,
ein segensreiches neues Jahr gewünscht und hatten zwischen
Becherklang und lustigem Lachen ihren Wunsch wehmütig ernst
gemeint, wie sich das gebührte.
„Wie gut der Papa und die Mama heute abend aussahen,“ meinten
sie. „Es ist doch eine Freude, wie frisch sie sich erhalten und wie sie
noch an allem teilnehmen. Aber verständig war es doch, daß sie
nicht über ihre Zeit bei uns sitzen blieben. Morgen früh hätten wir
uns doch Vorwürfe gemacht, wenn wir sie noch länger gequält
hätten, das Vergnügen nicht durch ihr Weggehen zu stören.... Jetzt
aber auf die Uhr gesehen! in fünf Minuten wird es Zwölf schlagen; —
ein bißchen leise, Kinder, daß w i r d i e a l t e n L e u t e n i c h t
w e c k e n ! “...
Zwölf Uhr und — ein neues Jahr! Alle guten Geister haben einen
leisen Schritt und gehen auf weichen Sohlen; so schlich sich die
jüngste Tochter des Hauses weg aus dem jubelnden Kreis, glitt die
Treppe hinauf und horchte an der Tür der „alten Leute“, die durch
den Becherklang, die lauten Glückwünsche und alles, was sonst noch
in die Stunde gehört, nicht gestört werden sollten in ihrer Ruhe auf
dem Altenteil.
„O mein Gott, da sitzt ihr noch? Das ist doch ganz wider die Abrede!
Sie meinen alle da unten, daß ihr längst in den Federn liegt und
euch behaglich in das neue Jahr hinübergeträumt habt.“
„Das letztere haben wir auch getan, mein Kind,“ sagte der alte Herr
nachdenklich lächelnd.
„Oh, und nun müßte ich sie alle — alle die übrigen auch noch
heraufrufen, daß sie euch ihre Meinung sagen. Sie werden es mit
Recht sehr übel nehmen, wenn ich’s nicht auf der Stelle tue, Mama!“
„Laß es lieber, mein Herz,“ meinte die alte Dame, leise die blonden
Flechten vor ihr, die noch nicht Staub und Asche geworden waren,
streichelnd. „Es würde den Vater doch zu sehr aufregen, und wir
gehen nun wirklich gleich zu Bett. Wir haben vorher nur noch ein
wenig an allerlei gedacht, was vor eurer — vor deiner Zeit war.“
„Ach ich bin so glücklich!“ rief die junge Frau. „Wir sind so vergnügt
da unten an unserem Tische, und ihr hier in euerer lieben, alten,
guten Stube seht so jung aus und so hell aus den Augen, wie das
Jüngste von uns — euern andern! Oh, und mein Franz ist so drollig;
der Mensch ist mir fast ein wenig zu ausgelassen, oh — und also
noch einmal: ein fröhliches, glückliches, gesegnetes neues Jahr euch
vor allen und — uns andern auch!“
„Ja, ja!“ sagten die a l t e n L e u t e leise zu gleicher Zeit und
nickten freundlich ihre Zustimmung zu dem guten Wunsch.
*** END OF THE PROJECT GUTENBERG EBOOK DER JUNKER VON
DENOW; EIN GEHEIMNIS; EIN BESUCH; AUF DEM ALTENTEIL:
ERZÄHLUNGEN ***
Updated editions will replace the previous one—the old editions will
be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.
START: FULL LICENSE
THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only be
used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright law
in the United States and you are located in the United States, we do
not claim a right to prevent you from copying, distributing,
performing, displaying or creating derivative works based on the
work as long as all references to Project Gutenberg are removed. Of
course, we hope that you will support the Project Gutenberg™
mission of promoting free access to electronic works by freely
sharing Project Gutenberg™ works in compliance with the terms of
this agreement for keeping the Project Gutenberg™ name associated
with the work. You can easily comply with the terms of this
agreement by keeping this work in the same format with its attached
full Project Gutenberg™ License when you share it without charge
with others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.
1.E. Unless you have removed all references to Project Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg” appears,
or with which the phrase “Project Gutenberg” is associated) is
accessed, displayed, performed, viewed, copied or distributed:
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this eBook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is derived
from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is posted
with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute this
electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the Project
Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™ works
unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or providing
access to or distributing Project Gutenberg™ electronic works
provided that:
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You provide a full refund of any money paid by a user who
notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full refund of
any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™
electronic work or group of works on different terms than are set
forth in this agreement, you must obtain permission in writing from
the Project Gutenberg Literary Archive Foundation, the manager of
the Project Gutenberg™ trademark. Contact the Foundation as set
forth in Section 3 below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on, transcribe
and proofread works not protected by U.S. copyright law in creating
the Project Gutenberg™ collection. Despite these efforts, Project
Gutenberg™ electronic works, and the medium on which they may
be stored, may contain “Defects,” such as, but not limited to,
incomplete, inaccurate or corrupt data, transcription errors, a
copyright or other intellectual property infringement, a defective or
damaged disk or other medium, a computer virus, or computer
codes that damage or cannot be read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for
the “Right of Replacement or Refund” described in paragraph 1.F.3,
the Project Gutenberg Literary Archive Foundation, the owner of the
Project Gutenberg™ trademark, and any other party distributing a
Project Gutenberg™ electronic work under this agreement, disclaim
all liability to you for damages, costs and expenses, including legal
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR
NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR
BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK
OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL
NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT,
CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF
YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you
discover a defect in this electronic work within 90 days of receiving
it, you can receive a refund of the money (if any) you paid for it by
sending a written explanation to the person you received the work
from. If you received the work on a physical medium, you must
return the medium with your written explanation. The person or
entity that provided you with the defective work may elect to provide
a replacement copy in lieu of a refund. If you received the work
electronically, the person or entity providing it to you may choose to
give you a second opportunity to receive the work electronically in
lieu of a refund. If the second copy is also defective, you may
demand a refund in writing without further opportunities to fix the
problem.
1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.
1.F.5. Some states do not allow disclaimers of certain implied
warranties or the exclusion or limitation of certain types of damages.
If any disclaimer or limitation set forth in this agreement violates the
law of the state applicable to this agreement, the agreement shall be
interpreted to make the maximum disclaimer or limitation permitted
by the applicable state law. The invalidity or unenforceability of any
provision of this agreement shall not void the remaining provisions.
1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation,
the trademark owner, any agent or employee of the Foundation,
anyone providing copies of Project Gutenberg™ electronic works in
accordance with this agreement, and any volunteers associated with
the production, promotion and distribution of Project Gutenberg™
electronic works, harmless from all liability, costs and expenses,
including legal fees, that arise directly or indirectly from any of the
following which you do or cause to occur: (a) distribution of this or
any Project Gutenberg™ work, (b) alteration, modification, or
additions or deletions to any Project Gutenberg™ work, and (c) any
Defect you cause.
Section 2. Information about the Mission
of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new computers.
It exists because of the efforts of hundreds of volunteers and
donations from people in all walks of life.
Volunteers and financial support to provide volunteers with the
assistance they need are critical to reaching Project Gutenberg™’s
goals and ensuring that the Project Gutenberg™ collection will
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.
Section 3. Information about the Project
Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.
The Foundation’s business office is located at 809 North 1500 West,
Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.
The Foundation is committed to complying with the laws regulating
charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.
While we cannot and do not solicit contributions from states where
we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.
International donations are gratefully accepted, but we cannot make
any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.
Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.
Section 5. General Information About
Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
This website includes information about Project Gutenberg™,
including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

Similar to Javascript Web Applications Otx Alex Maccaw (20)

PDF
Programming Ios 4 Fundamentals Of Iphone Ipad And Ipod Touch Development 1st ...
jungieaugi
 
PDF
Openstack Operations Guide 1st Edition Tom Fifield Diane Fleming
molaxmeizu
 
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
abucdaroga
 
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
eljantnezar
 
PDF
Even faster web sites 1st Edition Steve Souders
huapepotts09
 
PDF
Learning Rails 3 Rails from the Outside In 1st Edition Simon St. Laurent
tobarpaolico
 
PDF
Learning Java 4th Edition Patrick Niemeyer Daniel Leuck
zachryqypi73
 
PDF
Java Network Programming Third Edition 3rd Edition Elliotte Rusty Harold
dxvpbvqlbt970
 
PDF
Programming Coldfusion Mx 2nd Edition Rob Brooksbilson
kurohaost
 
PDF
Javascript The Definitive Guideactivate Your Web Pages 6th Ed Flanagan
reknesluima
 
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
lbsnmhb824
 
PDF
Client Server Web Apps with JavaScript and Java 1st Edition Casimir Saternos
tomeooakesrq
 
PDF
Learning Web App Development 1st Edition Semmy Purewal
molaxmeizu
 
PDF
Programming Windows Azure Programming The Microsoft Cloud 1st Edition Sriram ...
ydavefsen
 
PDF
Using Docker Developing And Deploying Software With Containers 1st Edition Ad...
graankloen
 
PDF
Programming Flex 2 Chafic Kazoun Joey Lott
mogilciprawq
 
PDF
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
maneskortyjt
 
PDF
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
rgexprbo904
 
PDF
Learning React Native Building Native Mobile Apps With Javascript 2nd Edition...
blvgtqnh252
 
PDF
Sustainable Web Development With Ruby On Rails Practical Tips For Building We...
ntxygopq606
 
Programming Ios 4 Fundamentals Of Iphone Ipad And Ipod Touch Development 1st ...
jungieaugi
 
Openstack Operations Guide 1st Edition Tom Fifield Diane Fleming
molaxmeizu
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
abucdaroga
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
eljantnezar
 
Even faster web sites 1st Edition Steve Souders
huapepotts09
 
Learning Rails 3 Rails from the Outside In 1st Edition Simon St. Laurent
tobarpaolico
 
Learning Java 4th Edition Patrick Niemeyer Daniel Leuck
zachryqypi73
 
Java Network Programming Third Edition 3rd Edition Elliotte Rusty Harold
dxvpbvqlbt970
 
Programming Coldfusion Mx 2nd Edition Rob Brooksbilson
kurohaost
 
Javascript The Definitive Guideactivate Your Web Pages 6th Ed Flanagan
reknesluima
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
lbsnmhb824
 
Client Server Web Apps with JavaScript and Java 1st Edition Casimir Saternos
tomeooakesrq
 
Learning Web App Development 1st Edition Semmy Purewal
molaxmeizu
 
Programming Windows Azure Programming The Microsoft Cloud 1st Edition Sriram ...
ydavefsen
 
Using Docker Developing And Deploying Software With Containers 1st Edition Ad...
graankloen
 
Programming Flex 2 Chafic Kazoun Joey Lott
mogilciprawq
 
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
maneskortyjt
 
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
rgexprbo904
 
Learning React Native Building Native Mobile Apps With Javascript 2nd Edition...
blvgtqnh252
 
Sustainable Web Development With Ruby On Rails Practical Tips For Building We...
ntxygopq606
 

Recently uploaded (20)

PPTX
2025 Winter SWAYAM NPTEL & A Student.pptx
Utsav Yagnik
 
PPTX
Soil and agriculture microbiology .pptx
Keerthana Ramesh
 
PDF
ARAL-Orientation_Morning-Session_Day-11.pdf
JoelVilloso1
 
PPTX
How to Convert an Opportunity into a Quotation in Odoo 18 CRM
Celine George
 
PDF
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 - GLOBAL SUCCESS - CẢ NĂM - NĂM 2024 (VOCABULARY, ...
Nguyen Thanh Tu Collection
 
PPT
Talk on Critical Theory, Part One, Philosophy of Social Sciences
Soraj Hongladarom
 
PPT
Talk on Critical Theory, Part II, Philosophy of Social Sciences
Soraj Hongladarom
 
PPTX
Unit 2 COMMERCIAL BANKING, Corporate banking.pptx
AnubalaSuresh1
 
PDF
ARAL_Orientation_Day-2-Sessions_ARAL-Readung ARAL-Mathematics ARAL-Sciencev2.pdf
JoelVilloso1
 
PDF
CEREBRAL PALSY: NURSING MANAGEMENT .pdf
PRADEEP ABOTHU
 
PDF
The Constitution Review Committee (CRC) has released an updated schedule for ...
nservice241
 
PDF
CONCURSO DE POESIA “POETUFAS – PASSOS SUAVES PELO VERSO.pdf
Colégio Santa Teresinha
 
PPTX
ASRB NET 2023 PREVIOUS YEAR QUESTION PAPER GENETICS AND PLANT BREEDING BY SAT...
Krashi Coaching
 
PDF
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
PDF
Chapter-V-DED-Entrepreneurship: Institutions Facilitating Entrepreneurship
Dayanand Huded
 
PPTX
Cultivation practice of Litchi in Nepal.pptx
UmeshTimilsina1
 
PPSX
HEALTH ASSESSMENT (Community Health Nursing) - GNM 1st Year
Priyanshu Anand
 
PDF
Isharyanti-2025-Cross Language Communication in Indonesian Language
Neny Isharyanti
 
PPTX
PATIENT ASSIGNMENTS AND NURSING CARE RESPONSIBILITIES.pptx
PRADEEP ABOTHU
 
PDF
The-Ever-Evolving-World-of-Science (1).pdf/7TH CLASS CURIOSITY /1ST CHAPTER/B...
Sandeep Swamy
 
2025 Winter SWAYAM NPTEL & A Student.pptx
Utsav Yagnik
 
Soil and agriculture microbiology .pptx
Keerthana Ramesh
 
ARAL-Orientation_Morning-Session_Day-11.pdf
JoelVilloso1
 
How to Convert an Opportunity into a Quotation in Odoo 18 CRM
Celine George
 
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 - GLOBAL SUCCESS - CẢ NĂM - NĂM 2024 (VOCABULARY, ...
Nguyen Thanh Tu Collection
 
Talk on Critical Theory, Part One, Philosophy of Social Sciences
Soraj Hongladarom
 
Talk on Critical Theory, Part II, Philosophy of Social Sciences
Soraj Hongladarom
 
Unit 2 COMMERCIAL BANKING, Corporate banking.pptx
AnubalaSuresh1
 
ARAL_Orientation_Day-2-Sessions_ARAL-Readung ARAL-Mathematics ARAL-Sciencev2.pdf
JoelVilloso1
 
CEREBRAL PALSY: NURSING MANAGEMENT .pdf
PRADEEP ABOTHU
 
The Constitution Review Committee (CRC) has released an updated schedule for ...
nservice241
 
CONCURSO DE POESIA “POETUFAS – PASSOS SUAVES PELO VERSO.pdf
Colégio Santa Teresinha
 
ASRB NET 2023 PREVIOUS YEAR QUESTION PAPER GENETICS AND PLANT BREEDING BY SAT...
Krashi Coaching
 
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
Chapter-V-DED-Entrepreneurship: Institutions Facilitating Entrepreneurship
Dayanand Huded
 
Cultivation practice of Litchi in Nepal.pptx
UmeshTimilsina1
 
HEALTH ASSESSMENT (Community Health Nursing) - GNM 1st Year
Priyanshu Anand
 
Isharyanti-2025-Cross Language Communication in Indonesian Language
Neny Isharyanti
 
PATIENT ASSIGNMENTS AND NURSING CARE RESPONSIBILITIES.pptx
PRADEEP ABOTHU
 
The-Ever-Evolving-World-of-Science (1).pdf/7TH CLASS CURIOSITY /1ST CHAPTER/B...
Sandeep Swamy
 
Ad

Javascript Web Applications Otx Alex Maccaw

  • 1. Javascript Web Applications Otx Alex Maccaw download https://ebookbell.com/product/javascript-web-applications-otx- alex-maccaw-2408862 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Javascript Web Applications Alex Maccaw https://ebookbell.com/product/javascript-web-applications-alex- maccaw-42303014 Javascript Web Applications Alex Maccaw https://ebookbell.com/product/javascript-web-applications-alex- maccaw-43169376 Javascript Web Applications Alex Maccaw https://ebookbell.com/product/javascript-web-applications-alex- maccaw-42302320 Sencha Touch 10 Mobile Javascript Framework Build Web Applications For Apple Ios And Google Android Touchscreen Devices With This First Html5 Mobile Framework 1st Edition Narasimha Rao https://ebookbell.com/product/sencha-touch-10-mobile-javascript- framework-build-web-applications-for-apple-ios-and-google-android- touchscreen-devices-with-this-first-html5-mobile-framework-1st- edition-narasimha-rao-4107484
  • 3. Deno Web Development Write Test Maintain And Deploy Javascript And Typescript Web Applications Using Deno 1st Edition Alexandre Portela Dos Santos https://ebookbell.com/product/deno-web-development-write-test- maintain-and-deploy-javascript-and-typescript-web-applications-using- deno-1st-edition-alexandre-portela-dos-santos-50781278 Web Applications With Javascript Or Java Volume 1 Constraint Validation Enumerations Special Datatypes Gerd Wagner Mircea Diaconescu https://ebookbell.com/product/web-applications-with-javascript-or- java-volume-1-constraint-validation-enumerations-special-datatypes- gerd-wagner-mircea-diaconescu-50347562 Building Web Applications With Net Core 21 And Javascript Leveraging Modern Javascript Frameworks Second Edition 2nd Edition Philip Japikse https://ebookbell.com/product/building-web-applications-with-net- core-21-and-javascript-leveraging-modern-javascript-frameworks-second- edition-2nd-edition-philip-japikse-52948432 Web Applications With Javascript Or Java De Gruyter Textbook 1st Edition Gerd Wagner https://ebookbell.com/product/web-applications-with-javascript-or- java-de-gruyter-textbook-1st-edition-gerd-wagner-33557258 Web Applications With Javascript Or Java Volume 1 Constraint Validation Enumerations Special Datatypes De Gruyter Textbook Gerd Wagner https://ebookbell.com/product/web-applications-with-javascript-or- java-volume-1-constraint-validation-enumerations-special-datatypes-de- gruyter-textbook-gerd-wagner-33646480
  • 9. JavaScript Web Applications Alex MacCaw Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
  • 10. JavaScript Web Applications by Alex MacCaw Copyright © 2011 Alex MacCaw. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or [email protected]. Editor: Mary Treseler Production Editor: Holly Bauer Copyeditor: Marlowe Shaeffer Proofreader: Stacie Arellano Indexer: Fred Brown Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrator: Robert Romano Printing History: August 2011: First Edition. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. JavaScript Web Applications, the image of a Long-eared owl, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting from the use of the information con- tained herein. ISBN: 978-1-449-30351-8 [LSI] 1313086859
  • 11. Table of Contents Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 1. MVC and Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Early Days 1 Adding Structure 2 What Is MVC? 2 The Model 3 The View 4 The Controller 5 Toward Modularity, Creating Classes 6 Adding Functions to Classes 7 Adding Methods to Our Class Library 8 Class Inheritance Using Prototype 10 Adding Inheritance to Our Class Library 11 Function Invocation 12 Controlling Scope in Our Class Library 14 Adding Private Functions 16 Class Libraries 16 2. Events and Observing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Listening to Events 19 Event Ordering 20 Canceling Events 21 The Event Object 21 Event Libraries 23 Context Change 24 Delegating Events 24 Custom Events 25 Custom Events and jQuery Plug-Ins 25 Non-DOM Events 27 v
  • 12. 3. Models and Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 MVC and Namespacing 31 Building an ORM 32 Prototypal Inheritance 33 Adding ORM Properties 34 Persisting Records 35 Adding ID Support 36 Addressing References 37 Loading in Data 38 Including Data Inline 39 Loading Data with Ajax 39 JSONP 43 Security with Cross-Domain Requests 43 Populating Our ORM 44 Storing Data Locally 44 Adding Local Storage to Our ORM 46 Submitting New Records to the Server 47 4. Controllers and State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Module Pattern 50 Global Import 50 Global Export 50 Adding a Bit of Context 51 Abstracting into a Library 52 Loading Controllers After the Document 53 Accessing Views 55 Delegating Events 56 State Machines 58 Routing 60 Using the URL’s Hash 60 Detecting Hash Changes 61 Ajax Crawling 62 Using the HTML5 History API 63 5. Views and Templating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Dynamically Rendering Views 65 Templates 66 Template Helpers 68 Template Storage 69 Binding 70 Binding Up Models 71 vi | Table of Contents
  • 13. 6. Dependency Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 CommonJS 74 Declaring a Module 74 Modules and the Browser 75 Module Loaders 76 Yabble 76 RequireJS 77 Wrapping Up Modules 78 Module Alternatives 79 LABjs 80 FUBCs 80 7. Working with Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Browser Support 81 Getting Information About Files 81 File Inputs 82 Drag and Drop 83 Dragging 84 Dropping 85 Cancel Default Drag/Drop 86 Copy and Paste 87 Copying 87 Pasting 88 Reading Files 89 Blobs and Slices 90 Custom Browse Buttons 91 Uploading Files 91 Ajax Progress 93 jQuery Drag and Drop Uploader 95 Creating a Drop Area 95 Uploading the File 95 8. The Real-Time Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Real Time’s History 97 WebSockets 98 Node.js and Socket.IO 101 Real-Time Architecture 103 Perceived Speed 105 9. Testing and Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Unit Testing 109 Assertions 109 QUnit 110 Table of Contents | vii
  • 14. Jasmine 113 Drivers 115 Headless Testing 118 Zombie 119 Ichabod 121 Distributed Testing 121 Providing Support 122 Inspectors 122 Web Inspector 123 Firebug 124 The Console 125 Console Helpers 126 Using the Debugger 127 Analyzing Network Requests 128 Profile and Timing 129 10. Deploying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Performance 133 Caching 134 Minification 136 Gzip Compression 137 Using a CDN 138 Auditors 138 Resources 139 11. The Spine Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Setup 141 Classes 142 Instantiation 142 Extending Classes 143 Context 144 Events 145 Models 145 Fetching Records 147 Model Events 147 Validation 148 Persistence 148 Controllers 150 Proxying 151 Elements 152 Delegating Events 152 Controller Events 153 Global Events 153 viii | Table of Contents
  • 15. The Render Pattern 154 The Element Pattern 154 Building a Contacts Manager 156 Contact Model 157 Sidebar Controller 158 Contacts Controller 160 App Controller 163 12. The Backbone Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Models 165 Models and Attributes 166 Collections 167 Controlling a Collection’s Order 169 Views 169 Rendering Views 170 Delegating Events 170 Binding and Context 171 Controllers 172 Syncing with the Server 174 Populating Collections 175 On the Server Side 175 Custom Behavior 176 Building a To-Do List 178 13. The JavascriptMVC Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Setup 186 Classes 186 Instantiation 186 Calling Base Methods 187 Proxies 187 Static Inheritance 187 Introspection 188 A Model Example 188 Model 189 Attributes and Observables 189 Extending Models 191 Setters 191 Defaults 192 Helper Methods 192 Service Encapsulation 193 Type Conversion 196 CRUD Events 196 Using Client-Side Templates in the View 197 Table of Contents | ix
  • 16. Basic Use 197 jQuery Modifiers 198 Loading from a Script Tag 198 $.View and Subtemplates 198 Deferreds 199 Packaging, Preloading, and Performance 199 $.Controller: The jQuery Plug-in Factory 200 Overview 202 Controller Instantiation 202 Event Binding 203 Templated Actions 204 Putting It All Together: An Abstract CRUD List 205 A. jQuery Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 B. CSS Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 C. CSS3 Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 x | Table of Contents
  • 17. Preface JavaScript has come a long way from its humble beginnings in 1995 as part of the Netscape browser, to the high-performance JIT interpreters of today. Even just five years ago developers were blown away by Ajax and the yellow fade technique; now, complex JavaScript apps run into the hundreds of thousands of lines. In the last year, a new breed of JavaScript applications has appeared, giving an expe- rience people were used to on the desktop, but that was unheard of on the Web. Gone are the slow page requests every time a user interacts with an application; instead, JavaScript engines are now so powerful we can keep state client side, giving a much more responsive and improved experience. It’s not just JavaScript engines that have improved; CSS3 and HTML5 specs haven’t finished the drafting stage, but they are already widely supported by modern browsers such as Safari, Chrome, Firefox, and—to some extent—IE9. Beautiful interfaces can be coded in a fraction of the time previously required, and without all that notorious image cutting and splicing. Support for HTML5 and CSS3 is getting better every day, but you’ll need to decide—based on your client base—whether to use these technologies. Moving state to the client side is no simple task. It requires a completely different development approach to server-side applications. You need to think about structure, templating,communicatingwiththeserver,frameworks,andmuchmore.That’swhere this book comes in; I’ll take you through all the steps necessary to create state-of-the- art JavaScript applications. Who Is This Book For? This book isn’t for JavaScript newbies, so if you’re unfamiliar with the basics of the language, I advise you to pick up one of the many good books on the subject, such as JavaScript: The Good Parts by Douglas Crockford (O’Reilly). This book is aimed at developers with some JavaScript experience, perhaps using a library like jQuery, who want to get into building more advanced JavaScript applications. Additionally, many xi
  • 18. sections of the book—especially the appendixes—will also be a useful reference for experienced JavaScript developers. How This Book Is Organized Chapter 1 The chapter starts with a discussion of JavaScript’s history and covers some of the underlying influences of its current implementation and community. We then give you an introduction to the MVC architectural pattern, in addition to exploring JavaScript’s constructor functions, prototypal inheritance, and how to create your own class library. Chapter 2 This chapter gives you a brief primer on browser events, including their history, API, and behavior. We’ll cover how to bind to events with jQuery, use delegation, and create custom events. We’ll also explore using non-DOM events with the PubSub pattern. Chapter 3 This chapter explains how to use MVC models in your application, as well as for loading and manipulating remote data. We’ll explain why MVC and namespacing are important and then build our own ORM library to manage model data. Next, we’ll cover how to load in remote data using JSONP and cross-domain Ajax. Fi- nally, you’ll learn how to persist model data using HTML5 Local Storage and sub- mitting it to a RESTful server. Chapter 4 This chapter demonstrates how to use a controller pattern to persist state on the client side. We’ll discuss how to use modules to encapsulate logic and prevent global namespace pollution, then we’ll cover how to cleanly interface controllers with views, listening to events and manipulating the DOM. Finally, we’ll discuss routing, first using the URL’s hash fragment, and then using the newer HTML5 History API, making sure to explain the pros and cons of both approaches. Chapter 5 This is where we cover views and JavaScript templating. We cover the different ways of dynamically rendering views, as well as various templating libraries and where to actually store the templates (inline in the page, in script tags, or with remote loading). Then, you’ll learn about data binding—connecting your model controllers and views to dynamically synchronize model data and view data. Chapter 6 In this chapter, we’ll get into the details of JavaScript dependency management using CommonJS modules. You’ll learn the history and thinking behind the Com- monJS movement, how to create CommonJS modules in the browser, and various module loader libraries to help you with this, such as Yabble and RequireJS. Next, we’ll discuss how to automatically wrap up modules server side, increasing xii | Preface
  • 19. performance and saving time. Finally, we’ll cover various alternatives to Com- monJS, such as Sprockets and LABjs. Chapter 7 Here, we’ll get into some of the benefits HTML5 gives us: the File API. We’ll cover browser support, multiple uploads, receiving files that are dragged onto the browser, and files from clipboard events. Next, we’ll explore reading files using blobs and slices, and displaying the result in the browser. We’ll cover uploading files in the background using the new XMLHttpRequest Level 2 specification, and finally, we’ll show you how to give your users live upload progress bars and how to integrate uploads with jQuery’s Ajax API. Chapter 8 We’ll take a look at some of the exciting developments with real-time applications and WebSockets. First, the chapter covers real time’s rather turbulent history and its current support in the browsers. Then, we’ll get into the details of WebSockets and their high-level implementation, browser support, and JavaScript API. Next, we’ll demonstrate a simple RPC server that uses WebSockets to connect up servers and clients. We’ll then take a look at Socket.IO and learn how real time fits into applications’ architecture and user experience. Chapter 9 This chapter covers testing and debugging, a crucial part of JavaScript web appli- cation development. We’ll look at the issues surrounding cross-browser testing, which browsers you should test in, and unit tests and testing libraries, such as QUnit and Jasmine. Next, we’ll take a look at automated testing and continuous integration servers, such as Selenium. We’ll then get into the debugging side of things, exploring Firefox and WebKit’s Web Inspectors, the console, and using the JavaScript debugger. Chapter 10 This chapter covers another important—but often neglected—part of JavaScript web applications: deployment. Chiefly, we’ll consider performance and how to use caching, minification, gzip compression, and other techniques to decrease your application’s initial load time. Finally, we’ll briefly cover how to use CDNs to serve static content on your behalf, and how to use the browser’s built-in auditor, which can be immensely helpful in improving your site’s performance. Chapter 11 The next three chapters give you an introduction to some popular JavaScript li- braries for application development. Spine is a lightweight MVC-compliant library that uses many of the concepts covered in the book. We’ll take you through the core parts of the library: classes, events, models, and controllers. Finally, we’ll build anexamplecontactsmanagerapplicationthatwilldemonstratewhatwe’velearned from the chapter. Preface | xiii
  • 20. Chapter 12 Backbone is an extremely popular library for building JavaScript applications, and this chapter will give you a thorough introduction. We’ll take you through the core concepts and classes of Backbone, such as models, collections, controllers, and views. Next, we’ll explore syncing model data with the server using RESTful JSON queries and how to respond to Backbone appropriately server side. Finally, we’ll build an example to-do list application that will demonstrate much of the library. Chapter 13 This chapter explores the JavaScriptMVC library, a popular jQuery-based framework for building JavaScript web applications. You’ll learn all the basics of JavaScriptMVC, such as classes, models, and controllers, as well as using client- side templates to render views. The chapter ends with a practical CRUD list ex- ample, demonstrating how easy it is to create abstract, reusable, memory-safe widgets with JavaScriptMVC. Appendix A This appendix provides a brief introduction to jQuery, which is useful if you feel you need to brush up on the library. Most of the book’s examples use jQuery, so it’s important to be familiar with it. We’ll cover most of the core API, such as traversing the DOM, manipulating the DOM, and event binding, triggering, and delegating. Next, we’ll approach jQuery’s Ajax API, making GET and POST JSON requests. We’ll then cover jQuery extensions and how to use encapsulation to ensure you’re being a good web citizen. Finally, we’ll take a look at a practical example: creating a Growl jQuery plug-in. Appendix B Appendix B covers Less, a superset of CSS that extends its syntax with variables, mixins, operations, and nested rules. Less can really reduce the amount of CSS you need to write—especially when it comes to CSS3 vendor–specific rules. This ap- pendix covers Less’s major syntax enhancements and how to use the command line’s tools and JavaScript library to compile Less files down to CSS. Appendix C The last appendix is a CSS3 reference. It provides a bit of background on CSS3, explains vendor prefixes, and then takes you through the major additions to the specification. Among other CSS3 features, this appendix covers rounded corners, rgba colors,dropshadows,gradients,transitions,andtransformations.Itendswith a discussion about graceful degradation using Modernizr and a practical example of using the new box-sizing specification. xiv | Preface
  • 21. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, file extensions, and events. Constant width Indicates computer code in a broad sense, including commands, arrays, elements, statements, options, switches, variables, attributes, keys, functions, types, classes, namespaces, methods, modules, properties, parameters, values, objects, event handlers, XML tags, HTML tags, macros, the contents of files, and the output from commands. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter- mined by context. This icon signifies a tip, suggestion, or general note. This icon indicates a warning or caution. Accompanying Files This book’s accompanying files are hosted on GitHub. You can view them online or downloadaziplocally.Alltheassetsareseparatedbychapter,andanyrequiredlibraries are also included. Most examples in this book are also available as standalone files. Whenever a particular asset is referenced inside a chapter, it will be in the form of assets/ chapter_number/name. Preface | xv
  • 22. Code Conventions Throughout this book we’ll use the assert() and assertEqual() functions to demon- strate the value of variables or the result of a function call. assert() is just shorthand for indicating that a particular variable resolves to true; it is a common pattern that’s especially prevalent in automated testing. assert() takes two arguments: a value and an optional message. If the value doesn’t equal true, the function will throw an error: var assert = function(value, msg) { if ( !value ) throw(msg || (value + " does not equal true")); }; assertEqual() is shorthand for indicating that one variable equals another. It works similarly to assert(), but it accepts two values. If the two values aren’t equal, the as- sertion fails: var assertEqual = function(val1, val2, msg) { if (val1 !== val2) throw(msg || (val1 + " does not equal " + val2)); }; Using the two functions is very straightforward, as you can see in the example below. If the assertion fails, you’ll see an error message in the browser’s console: assert( true ); // Equivalent to assertEqual() assert( false === false ); assertEqual( 1, 1 ); I’ve slightly sugar-coated assertEqual() since, as it stands, object comparison will fail unless the objects share the same reference in memory. The solution is a deep com- parison, and we’ve included an example of this in assets/ch00/deep_equality.html. jQuery Examples A lot of the examples in this book rely on jQuery, an extremely popular JavaScript library that simplifies events, DOM traversing, manipulation, and Ajax. I’ve decided this for various reasons, but it’s mostly because jQuery greatly clarifies examples, and it is closer to the JavaScript most people write in the real world. If you haven’t used jQuery, I strongly advise you to check it out. It has an excellent API that provides a good abstraction over the DOM. A brief jQuery primer is included in Appendix A. xvi | Preface
  • 23. Holla Built as a companion to this book, Holla is a JS group chat application. Holla is a good example application because it encompasses various best practices covered in this book. Among other things, Holla will show you how to: • Use CSS3 and HTML5 to create beautiful interfaces • Drag and drop to upload files • Lay out your code using Sprockets and Less • Use WebSockets to push data to clients • Create a stateful JavaScript application Clone the code from Holla’s GitHub repository and take a look. Many of the examples in this book have been taken from Holla’s source; see Figure P-1. Figure P-1. Holla, an example chat application Author’s Note I wrote this book as I traveled around the world for a year. I wrote some parts in African huts without electricity and Internet, others in Japanese washitsus overlooking temples Preface | xvii
  • 24. and blossoming trees, and some even on remote Cambodian islands. In short, I had a great time writing this, and I hope reading it gives you just as much pleasure. Some people deserve their share of the blame. Thanks go to Stuart Eccles, Tim Malbon, Ben Griffins, and Sean O’Halpin for giving me the chances and opportunity to find my passion; and to James Adam, Paul Battley, and Jonah Fox for mentoring and putting up with my asininities. Thanks also to the technical reviewers, who really helped shape the book: Henrik Jor- eteg, Justin Meyer, Lea Verou, Addy Osmani, Alex Barbara, Max Williams, and Julio Cesar Ody. Most importantly, thanks to my parents for their unwavering support. Safari® Books Online Safari Books Online is an on-demand digital library that lets you easily search over 7,500 technology and creative reference books and videos to find the answers you need quickly. Withasubscription,youcanreadanypageandwatchanyvideofromourlibraryonline. Read books on your cell phone and mobile devices. Access new titles before they are available for print, and get exclusive access to manuscripts in development and post feedback for the authors. Copy and paste code samples, organize your favorites, down- load chapters, bookmark key sections, create notes, print out pages, and benefit from tons of other time-saving features. O’Reilly Media has uploaded this book to the Safari Books Online service. To have full digital access to this book and others on similar topics from O’Reilly and other pub- lishers, sign up for free at http://my.safaribooksonline.com. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 (800) 998-9938 (in the United States or Canada) (707) 829-0515 (international or local) (707) 829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at: http://www.oreilly.com/catalog/9781449303518 To comment or ask technical questions about this book, send email to: xviii | Preface
  • 25. [email protected] For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Preface | xix
  • 27. CHAPTER 1 MVC and Classes Early Days JavaScript development has changed markedly from how it looked when it was first conceived. It’s easy to forget how far the language has come from its initial implemen- tation in Netscape’s browser, to the powerful engines of today, such as Google’s V8. It’s been a rocky path involving renaming, merging, and the eventual standardization as ECMAScript. The capabilities we have today are beyond the wildest dreams of those early innovators. Despite its success and popularity, JavaScript is still widely misunderstood. Few people know that it’s a powerful and dynamic object-oriented language. They’re surprised to learn about some of its more advanced features, such as prototypal inheritance, mod- ules, and namespaces. So, why is JavaScript so misunderstood? Part of the reason is due to previous buggy JavaScript implementations, and part of it is due to the name—the Java prefix suggests it’s somehow related to Java; in reality, it’s a totally different language. However, I think the real reason is the way most de- velopers are introduced to the language. With other languages, such as Python and Ruby, developers usually make a concerted effort to learn the language with the help of books, screencasts, and tutorials. Until recently, though, JavaScript wasn’t given that endorsement. Developers would get requests to add a bit of form validation—maybe a lightbox or a photo gallery—to existing code, often on a tight schedule. They’d use scripts they’d find on the Internet, calling it a day with little understanding of the lan- guage behind it. After that basic exposure, some of them might even add JavaScript to their resumes. Recently, JavaScript engines and browsers have become so powerful that building full- blown applications in JavaScript is not only feasible, but increasingly popular. Appli- cations like Gmail and Google Maps have paved the way to a completely different way of thinking about web applications, and users are clamoring for more. Companies are hiring full-time JavaScript developers. No longer is JavaScript a sublanguage relegated 1
  • 28. to simple scripts and a bit of form validation—it is now a standalone language in its own right, realizing its full potential. This influx of popularity means that a lot of new JavaScript applications are being built. Unfortunately, and perhaps due to the language’s history, many of them are construc- ted very poorly. For some reason, when it comes to JavaScript, acknowledged patterns and best practices fly out the window. Developers ignore architectural models like the Model View Controller (MVC) pattern, instead blending their applications into a messy soup of HTML and JavaScript. This book won’t teach you much about JavaScript as a language—other books are better suited for that, such as Douglas Crockford’s JavaScript: The Good Parts (O’Re- illy). However, this book will show you how to structure and build complex JavaScript applications, allowing you to create incredible web experiences. Adding Structure The secret to making large JavaScript applications is to not make large JavaScript ap- plications. Instead, you should decouple your application into a series of fairly inde- pendent components. The mistake developers often make is creating applications with a lot of interdependency, with huge linear JavaScript files generating a slew of HTML tags. These sorts of applications are difficult to maintain and extend, so they should be avoided at all costs. Paying a bit of attention to an application’s structure when you start building it can make a big difference to the end result. Ignore any preconceived notions you have about JavaScript and treat it like the object-oriented language that it is. Use classes, inheri- tance, objects, and patterns the same way you would if you were building an application in another language, such as Python or Ruby. Architecture is critical to server-side applications, so why shouldn’t the same apply to client-side apps? The approach this book advocates is the MVC pattern, a tried and tested way of ar- chitecting applications that ensures they can be effectively maintained and extended. It’s also a pattern that applies particularly well to JavaScript applications. What Is MVC? MVC is a design pattern that breaks an application into three parts: the data (Model), the presentation layer (View), and the user interaction layer (Controller). In other words, the event flow goes like this: 1. The user interacts with the application. 2. The controller’s event handlers trigger. 3. The controller requests data from the model, giving it to the view. 4. The view presents the data to the user. 2 | Chapter 1: MVC and Classes
  • 29. Or, to give a real example, Figure 1-1 shows how sending a new chat message would work with Holla. Figure 1-1. Sending a new chat message from Holla 1. The user submits a new chat message. 2. The controller’s event handlers trigger. 3. The controller creates a new Chat Model record. 4. The controller then updates the view. 5. The user sees his new chat message in chat log. The MVC architectural pattern can even be implemented without libraries or frame- works. The key is to divide up the responsibilities of the MVC components into clearly defined sections of code, keeping them decoupled. This allows for independent devel- opment, testing, and maintenance of each component. Let’s explore the components of MVC in detail. The Model The model is where all the application’s data objects are stored. For example, we might have a User Model that contains a list of users, their attributes, and any logic associated specifically with that model. A model doesn’t know anything about views or controllers. The only thing a model should contain is data and the logic associated directly with that data. Any event han- dling code, view templates, or logic not specific to that model should be kept well clear of it. You know an application’s MVC architecture is violated when you start seeing view code in the models. Models should be completely decoupled from the rest of your application. When controllers fetch data from servers or create new records, they wrap them in model instances. This means that our data is object oriented, and any functions or logic defined on the model can be called directly on the data. What Is MVC? | 3
  • 30. So, rather than this: var user = users["foo"]; destroyUser(user); We can do something like this: var user = User.find("foo"); user.destroy(); The first example is not namespaced or object oriented. If we have another destroy User() function defined in our application, the two will conflict. Global variables and functions should always be kept to an absolute minimum. In the second example, the destroy() function is namespaced behind User instances, as are all the stored records. This is ideal, since we’re keeping global variables to a minimum, exposing fewer areas to potential conflicts. The code is cleaner and can take advantage of inheritance so functions like destroy() don’t have be defined separately on every model. Models are explored in much more depth in Chapter 3, which covers topics such as loading in data from servers and creating object-relational mappers (ORMs). The View The view layer is what’s presented to the user and is what she interacts with. In a JavaScript application, the view would be made up mostly of HTML, CSS, and Java- Script templates. Apart from simple conditional statements in templates, the views shouldn’t contain any logic. In fact, like models, views should also be decoupled from the rest of the application. Views shouldn’t know anything about controllers and models—they should be inde- pendent. Mixing up views with logic is one of the surest paths to disaster. That isn’t to say MVC doesn’t allow for presentational logic—as long as it’s not defined inside views. Presentational logic resides in what are called helpers: scripts solely for small utility functions related to the view. The example below, which includes logic inside views, is something you shouldn’t do: // template.html <div> <script> function formatDate(date) { /* ... */ }; </script> ${ formatDate(this.date) } </div> In the code above, we’re inserting the formatDate() function directly into the view, which violates MVC, resulting in an unmaintainable mess of tag soup. By separating out presentational logic into helpers, as with the example below, we’re avoiding that problem and keeping our application’s structure MVC-compliant. 4 | Chapter 1: MVC and Classes
  • 31. // helper.js var helper = {}; helper.formatDate = function(){ /* ... */ }; // template.html <div> ${ helper.formatDate(this.date) } </div> Inaddition,allpresentationallogicisnamespacedunderthehelper variable,preventing conflicts and keeping the code clean and extendable. Don’t worry too much about specifics regarding views and templates—we cover them extensively in Chapter 5. The aim of this section is to familiarize you with how views relate to the MVC architectural pattern. The Controller Controllersarethegluebetweenmodelsandviews.Controllersreceiveeventsandinput from views, process them (perhaps involving models), and update the views accord- ingly. The controller will add event listeners to views when the page loads, such as those detecting when forms are submitted or buttons are clicked. Then, when the user in- teracts with your application, the events trigger actions inside the controllers. You don’t need any special libraries or frameworks to implement controllers; here’s an example using plain old jQuery: var Controller = {}; // Use a anonymous function to enscapulate scope (Controller.users = function($){ var nameClick = function(){ /* ... */ }; // Attach event listeners on page load $(function(){ $("#view .name").click(nameClick); }); })(jQuery); We’re creating a users Controller that is namespaced under the Controller variable. Then, we’re using an anonymous function to encapsulate scope, preventing variable pollution of the global scope. When the page loads, we’re adding a click event listener to a view element. As you can see, controllers don’t require a library or framework. However, to comply with MVC’s architectural requirements, they must be separated from Models and Views. Controllers and states are covered in more detail in Chapter 4. What Is MVC? | 5
  • 32. Toward Modularity, Creating Classes Before we get to the nitty-gritty of MVC, we’re going to cover some preliminary con- cepts, such as JavaScript classes and events. This will give you a solid foundation before moving on to some of the more advanced concepts. JavaScript object literals are fine for static classes, but it’s often useful to create classical classes with inheritance and instances. It’s important to emphasize that JavaScript is a prototype language, and as such doesn’t include a native class implementation. How- ever, support can be emulated fairly easily. Classes in JavaScript often get a bad rap, criticized for not being part of the “JavaScript Way,” a term that means essentially nothing. jQuery is effectively neutral when it comes to structural methodology or inheritance patterns. This can lead JavaScript developers to believe they shouldn’t consider structure—i.e., that classes aren’t available or shouldn’t be used. In reality, classes are just another tool, and as a pragmatist, I believe they’re as useful in JavaScript as in any other modern language. Rather than class definitions, JavaScript has constructor functions and the new opera- tor. A constructor function can specify an object’s initial properties and values when it is instantiated. Any JavaScript function can be used as a constructor. Use the new op- erator with a constructor function to create a new instance. The new operator changes a function’s context, as well as the behavior of the return statement. In practice, using new and constructors is fairly similar to languages with native class implementations: var Person = function(name) { this.name = name; }; // Instantiate Person var alice = new Person('alice'); // Check instance assert( alice instanceof Person ); By convention, constructor functions are upper camel-cased to differentiate them from normal functions. This is important because you don’t ever want to call a constructor function without the new prefix. // Don't do this! Person('bob'); //=> undefined The function will just return undefined, and since the context is the window (global) object, you’ve unintentionally created a global variable, name. Always call constructor functions using the new keyword. When a constructor function is called with the new keyword, the context switches from global (window) to a new and empty context specific to that instance. So, the this 6 | Chapter 1: MVC and Classes
  • 33. keyword refers to the current instance. Although it might sound complicated, in prac- tice, you can treat it like native class implementations in other languages. By default, if you don’t return anything from a constructor function, this—the current context—will be returned. Otherwise, you can return any nonprimitive type. For ex- ample, we could return a function that would set up a new class, the first step in building our own class emulation library: var Class = function(){ var klass = function(){ this.init.apply(this, arguments); }; klass.prototype.init = function(){}; return klass; }; var Person = new Class; Person.prototype.init = function(){ // Called on Person instantiation }; // Usage: var person = new Person; Confusingly, due to a JavaScript 2 specification that was never implemented, class is a reserved keyword. The common convention is instead to name class variables as _class or klass. Adding Functions to Classes Adding class functions to a constructor function is the same as adding a property onto any object in JavaScript: Person.find = function(id){ /*...*/ }; var person = Person.find(1); To add instance functions to a constructor function, you need to use the constructor’s prototype: Person.prototype.breath = function(){ /*...*/ }; var person = new Person; person.breath(); A common pattern is to alias a class’ prototype to fn, which is a bit less verbose: Person.fn = Person.prototype; Person.fn.run = function(){ /*...*/ }; In fact, you’ll see this pattern throughout jQuery plug-ins, which essentially just add functions to jQuery’s prototype, aliased to jQuery.fn. Adding Functions to Classes | 7
  • 34. Adding Methods to Our Class Library Currently, our class library includes functionality for instantiating and initializing in- stances. Adding properties to classes is the same as adding properties to constructor functions. Properties set directly on the class will be equivalent to static members: var Person = new Class; // Static functions are added directly on the class Person.find = function(id){ /* ... */ }; // And now we can call them directly var person = Person.find(1); And properties set on the class’ prototype are also available on instances: var Person = new Class; // Instance functions are on the prototype Person.prototype.save = function(){ /* ... */ }; // And now we can call them on instances var person = new Person; person.save(); However, in my opinion, that syntax is a little convoluted, impractical, and repetitive. It’s difficult to see, at a glance, a list of your class’ static and instance properties. Instead, let’s create a different way of adding properties to our classes using two functions, extend() and include(): var Class = function(){ var klass = function(){ this.init.apply(this, arguments); }; klass.prototype.init = function(){}; // Shortcut to access prototype klass.fn = klass.prototype; // Shortcut to access class klass.fn.parent = klass; // Adding class properties klass.extend = function(obj){ var extended = obj.extended; for(var i in obj){ klass[i] = obj[i]; } if (extended) extended(klass) }; // Adding instance properties 8 | Chapter 1: MVC and Classes
  • 35. klass.include = function(obj){ var included = obj.included; for(var i in obj){ klass.fn[i] = obj[i]; } if (included) included(klass) }; return klass; }; In the improved class library above, we’re adding an extend() function to generated classes,whichacceptsanobject.Theobject’spropertiesareiteratedthroughandcopied directly onto the class: var Person = new Class; Person.extend({ find: function(id) { /* ... */ }, exists: functions(id) { /* ... */ } }); var person = Person.find(1); The include() function works in exactly the same way, except properties are copied onto the class’ prototype, rather than directly onto the class. In other words, the prop- erties are on the class’ instance, rather than statically on the class. var Person = new Class; Person.include({ save: function(id) { /* ... */ }, destroy: functions(id) { /* ... */ } }); var person = new Person; person.save(); We’re also implementing support for extended and included callbacks. If these prop- erties are present on the passed object, they’ll be invoked: Person.extend({ extended: function(klass) { console.log(klass, " was extended!"); } }); If you’ve used classes in Ruby, this should all look very familiar. The beauty of this approach is that we’ve now got support for modules. Modules are reusable pieces of code, and they can be used as an alternative to inheritance for sharing common prop- erties among classes. var ORMModule = { save: function(){ // Shared function Adding Methods to Our Class Library | 9
  • 36. } }; var Person = new Class; var Asset = new Class; Person.include(ORMModule); Asset.include(ORMModule); Class Inheritance Using Prototype We’ve been using the prototype property a lot, but it hasn’t really been explained yet. Let’s take a closer look at what it is exactly and how to use it to implement a form of inheritance in our classes. JavaScript is a prototype-based language and—rather than make distinctions between classes and instances—it has the notions of a prototypical object: an object used as a template from which to get the initial properties for a new object. Any object can be associated as a prototype of another object, sharing its properties. In practice, you can look at this as a form of inheritance. When you fetch a property on an object, JavaScript will search the local object for the property. If it isn’t found, JavaScript will start searching the object’s prototype and continue up the prototype tree, eventually reaching Object.prototype. If the property is found, its value is returned; otherwise, undefined will be returned. In other words, if you start adding properties to Array.prototype, they’ll be reflected across every JavaScript array. To subclass a class and inherit its properties, you need to first define a constructor function. Then, you need to assign a new instance of the parent class as the prototype for your constructor function. It looks like this: var Animal = function(){}; Animal.prototype.breath = function(){ console.log('breath'); }; var Dog = function(){}; // Dog inherits from Animal Dog.prototype = new Animal; Dog.prototype.wag = function(){ console.log('wag tail'); }; Now, we can check to see whether the inheritance works: 10 | Chapter 1: MVC and Classes
  • 37. var dog = new Dog; dog.wag(); dog.breath(); // Inherited property Adding Inheritance to Our Class Library Let’s add inheritance to our custom class library. We’ll pass through an optional parent class when creating a new class: var Class = function(parent){ var klass = function(){ this.init.apply(this, arguments); }; // Change klass' prototype if (parent) { var subclass = function() { }; subclass.prototype = parent.prototype; klass.prototype = new subclass; }; klass.prototype.init = function(){}; // Shortcuts klass.fn = klass.prototype; klass.fn.parent = klass; klass._super = klass.__proto__; /* include/extend code... */ return klass; }; If a parent is passed to the Class constructor, we make sure any subclasses share the same prototype. This little dance around creating a temporary anonymous function prevents instances from being created when a class is inherited. The caveat here is that only instance properties, not class properties, are inherited. There isn’t yet a cross- browser way of setting an object’s __proto__;. Libraries like Super.js get around this problem by copying the properties, rather than implementing proper dynamic inheri- tance. Now, we can perform simple inheritance by passing parent classes to Class: var Animal = new Class; Animal.include({ breath: function(){ console.log('breath'); } }); var Cat = new Class(Animal) Adding Inheritance to Our Class Library | 11
  • 38. // Usage var tommy = new Cat; tommy.breath(); Function Invocation Like everything else in JavaScript, functions are just objects. However, unlike other objects, they can be invoked. The context inside the function—i.e., the value of this— depends on where and how it’s invoked. Apart from using brackets, there are two other ways to invoke a function: apply() and call(). The difference between them has to do with the arguments you want to pass to the function. The apply() function takes two parameters: a context and an array of arguments. If the context is null, the global context is used. For example: function.apply(this, [1, 2, 3]) The call() function has exactly the same behavior, yet it is used differently. The first argument is the context, while each subsequent argument is delegated to the invoca- tion. In other words, you use multiple arguments—rather than an array like with apply()—to pass arguments to the function. function.call(this, 1, 2, 3); Why would you want to change the context? This is a valid question because other languages get on fine without allowing explicit context changes. JavaScript uses context changes to share state, especially during event callbacks. (Personally, I feel this was a mistake in the design of the language, as it can be confusing for beginners and introduce bugs. However, it’s too late to change it now, so you need to learn how it works.) jQuery takes advantage of apply() and call() throughout its API to change context— for example, when using event handlers or iterating using each(). This can be confusing at first, but it’s useful when you understand what’s happening: $('.clicky').click(function(){ // 'this' refers to the element $(this).hide(); }); $('p').each(function(){ // 'this' refers to the current iteration $(this).remove(); }); To access the original context, a common pattern stores the value of this in a local variable. For example: var clicky = { wasClicked: function(){ /* ... */ 12 | Chapter 1: MVC and Classes
  • 39. }, addListeners: function(){ var self = this; $('.clicky').click(function(){ self.wasClicked() }); } }; clicky.addListeners(); However, we can use apply to make this much cleaner, wrapping the callback within another anonymous function, which preserves the original context: var proxy = function(func, thisObject){ return(function(){ return func.apply(thisObject, arguments); }); }; var clicky = { wasClicked: function(){ /* ... */ }, addListeners: function(){ var self = this; $('.clicky').click(proxy(this.wasClicked, this)); } }; So, in the above example, we specify the context to be used inside the click callback; the context jQuery invokes the function in is ignored. In fact, jQuery’s API includes something to do just this—you guessed it, jQuery.proxy(): $('.clicky').click($.proxy(function(){ /* ... */ }, this)); There are other useful reasons to use apply() and call(), such as delegating. We can delegate calls from one function to another, and even alter the passed arguments: var App { log: function(){ if (typeof console == "undefined") return; // Turn arguments into a proper array var args = jQuery.makeArray(arguments); // Insert a new argument args.unshift("(App)"); // Delegate to the console console.log.apply(console, args); } }; Function Invocation | 13
  • 40. Above, we’re making an array of arguments and then adding our own. Finally, the call is delegated to console.log(). If you’re not familiar with the arguments variable, it’s set by the interpreter and contains an array of arguments with which the current scope was called. It’s not a true array though—for example, it’s not mutable—so we have to convert it to something usable with jquery.makeArray(). Controlling Scope in Our Class Library The proxy function described in the previous section is such a useful pattern that we should add it to our class library. We’ll add a proxy function on both classes and in- stances, allowing us to keep the class’ scope when handing functions off to event han- dlers and the like: var Class = function(parent){ var klass = function(){ this.init.apply(this, arguments); }; klass.prototype.init = function(){}; klass.fn = klass.prototype; // Adding a proxy function klass.proxy = function(func){ var self = this; return(function(){ return func.apply(self, arguments); }); } // Add the function on instances too klass.fn.proxy = klass.proxy; return klass; }; We can now use the proxy() function to wrap up functions, making sure they’re in- voked in the right scope: var Button = new Class; Button.include({ init: function(element){ this.element = jQuery(element); // Proxy the click function this.element.click(this.proxy(this.click)); }, click: function(){ /* ... */ } }); 14 | Chapter 1: MVC and Classes
  • 41. If we didn’t wrap the click() callback with a proxy, it would be called within the context of this.element, rather than Button, causing all sorts of problems. A new spec- ification of JavaScript—ECMAScript, 5th Edition (ES5)—has also added support for controlling invocation scope with the bind() function. bind() is called on a function, making sure the function is called in the context of the specified this value. For exam- ple: Button.include({ init: function(element){ this.element = jQuery(element); // Bind the click function this.element.click(this.click.bind(this)); }, click: function(){ /* ... */ } }); This example is equivalent to our proxy() function, and it makes sure the click() function is called with the correct context. Older browsers don’t support bind() but, luckily, support can be shimmed easily and implemented manually if needed. A shim basically implements a compatibility layer on legacy browsers, directly extending the relevant object’s prototypes, allowing you to use features of ES5 today without wor- rying about older browsers. For example, a shim that would support bind() would look like this: if ( !Function.prototype.bind ) { Function.prototype.bind = function( obj ) { var slice = [].slice, args = slice.call(arguments, 1), self = this, nop = function () {}, bound = function () { return self.apply( this instanceof nop ? this : ( obj || {} ), args.concat( slice.call(arguments) ) ); }; nop.prototype = self.prototype; bound.prototype = new nop(); return bound; }; } Function’s prototype is only overwritten if the feature doesn’t already exist: newer browsers will continue to use their native implementations. Shimming is especially useful for arrays, which have had a bunch of new features added in recent JavaScript versions. I personally use the es5-shim project because it covers as many of the new features in ES5 as possible. Controlling Scope in Our Class Library | 15
  • 42. Adding Private Functions So far, any property we’ve added to our classes has been open to the world and can be changed at any time. Let’s now explore how to add private properties to our classes. A lot of developers end up prefixing private properties with an underscore (_). Although these can still be changed, it makes it obvious that they’re part of a private API. I try to steer clear of this approach because it looks rather ugly. JavaScript does have support for immutable properties; however, this isn’t implemen- ted across the main browsers, so we’ll have to wait before using this method. Instead, we’ll use JavaScript anonymous functions to create a private scope, which can only be accessed internally: var Person = function(){}; (function(){ var findById = function(){ /* ... */ }; Person.find = function(id){ if (typeof id == "integer") return findById(id); }; })(); We’re wrapping all our class’ properties in an anonymous function, then creating local variables (findById), which can only be accessed in the current scope. The Person var- iable is defined in the global scope, so it can be accessed from anywhere. Never define a variable without using the var operator, since it always creates a global variable. If you need to define a global variable, do so in the global scope or as a property on window: (function(exports){ var foo = "bar"; // Expose variable exports.foo = foo; })(window); assertEqual(foo, "bar"); Class Libraries As with a lot of concepts in this book, it’s good to understand the theory behind classes, but often in practice, you’ll use a library. jQuery doesn’t include class support natively, but it can easily be added with a plug-in like HJS. HJS lets you define classes by passing a set of properties to $.Class.create: 16 | Chapter 1: MVC and Classes
  • 43. var Person = $.Class.create({ // constructor initialize: function(name) { this.name = name; } }); To inherit classes, pass their parent as an argument when creating them: var Student = $.Class.create(Person, { price: function() { /* ... */ } }); var alex = new Student("Alex"); alex.pay(); To add class properties, set them directly on the class: Person.find = function(id){ /* ... */ }; HJS’ API also includes a few utility functions, such as clone() and equal(): var alex = new Student("Alex"); var bill = alex.clone(); assert( alex.equal(bill) ); HJS isn’t your only option; Spine also has a class implementation. To use it, just include spine.js in the page: <script src="http://maccman.github.com/spine/spine.js"> </script> <script> var Person = Spine.Class.create(); Person.extend({ find: function() { /* ... */ } }); Person.include({ init: function(atts){ this.attributes = atts || {}; } }); var person = Person.init(); </script> Spine’s class library has a similar API to the library we’ve been building throughout this chapter. Use extend() to add class properties and include() to add instance properties. To inherit from them, pass parent classes to the Spine.Class instantiator. If you’re widening your gaze beyond jQuery, Prototype is definitely worth checking out. It has an excellent class API that was the inspiration for a lot of other libraries. jQuery’s John Resig has an interesting post on implementing classical inheritance with the library. It’s well worth reading, especially if you’re interested in the nitty-gritty behind the JavaScript prototype system. Class Libraries | 17
  • 45. CHAPTER 2 Events and Observing EventsareatthecoreofyourJavaScriptapplication,poweringeverythingandproviding the first point of contact when a user interacts with your application. However, this is where JavaScript’s unstandardized birth rears its ugly head. At the height of the browser wars, Netscape and Microsoft purposely chose different, incompatible event models. Although they were later standardized by the W3C, Internet Explorer kept its different implementation until its latest release, IE9. Luckily, we have great libraries like jQuery and Prototype that smooth over the mess, giving you one API that will work with all the event implementations. Still, it’s worth understanding what’s happening behind the scenes, so I’m going to cover the W3C model here before showing examples for various popular libraries. Listening to Events Events revolve around a function called addEventListener(), which takes three argu- ments: type (e.g., click), listener (i.e., callback), and useCapture (we’ll cover useCap ture later). Using the first two arguments, we can attach a function to a DOM element, which is invoked when that particular event, such as click, is triggered on the element: var button = document.getElementById("createButton"); button.addEventListener("click", function(){ /* ... */ }, false); We can remove the listener using removeEventListener(), passing the same arguments we gave addEventListener(). If the listener function is anonymous and there’s no ref- erence to it, it can’t be removed without destroying the element: var div = document.getElementById("div"); var listener = function(event) { /* ... */ }; div.addEventListener("click", listener, false); div.removeEventListener("click", listener, false); 19
  • 46. As its first argument, the listener function is passed an event object, which you can use to get information about the event, such as timestamp, coordinates, and target. It also contains various functions to stop the event propagation and prevent the default action. As for event types, the supported ones vary from browser to browser, but all modern browsers have the following: • click • dblclick • mousemove • mouseover • mouseout • focus • blur • change (for form inputs) • submit (for forms) Check out Quirksmode, which has a full event compatibility table. Event Ordering Before we go any further, it’s important to discuss event ordering. If an element and one of its ancestors have an event handler for the same event type, which one should fire first when the event is triggered? Well, you won’t be surprised to hear that Netscape and Microsoft had different ideas. Netscape 4 supported event capturing, which triggers event listeners from the top-most ancestor to the element in question—i.e., from the outside in. Microsoft endorsed event bubbling, which triggers event listeners from the element, propagating up through its ancestors—i.e., from the inside out. Event bubbling makes more sense to me, and it is likely to be the model used in day- to-day development. The W3C compromised and stipulated support for both event models in their specification. Events conforming to the W3C model are first captured until they reach the target element; then, they bubble up again. You can choose the type of event handler you want to register, capturing or bubbling, which is where the useCapture argument to addEventListener() comes into the picture. If the last argument to addEventListener() is true, the event handler is set for the cap- turing phase; if it is false, the event handler is set for the bubbling phase: 20 | Chapter 2: Events and Observing
  • 47. // Use bubbling by passing false as the last argument button.addEventListener("click", function(){ /* ... */ }, false); The vast majority of the time, you’ll probably be using event bubbling. If in doubt, pass false as the last argument to addEventListener(). Canceling Events When the event is bubbling up, you can stop its progress with the stopPropagation() function, located on the event object. Any handlers on ancestor elements won’t be invoked: button.addEventListener("click", function(e){ e.stopPropagation(); /* ... */ }, false); Additionally, some libraries like jQuery support a stopImmediatePropagation() func- tion, preventing any further handlers from being called at all—even if they’re on the same element. Browsers also give default actions to events. For example, when you click on a link, the browser’s default action is to load a new page, or when you click on a checkbox, the browser checks it. This default action happens after all the event propagation phases and can be canceled during any one of those. You can prevent the default action with the preventDefault() function on the event object. Alternatively, you can just return false from the handler: form.addEventListener("submit", function(e){ /* ... */ return confirm("Are you super sure?"); }, false); If the call to confirm() returns false—i.e., the user clicks cancel in the confirmation dialog—the event callback function will return false, canceling the event and form submission. The Event Object As well as the aforementioned functions—stopPropagation() and preventDefault()— the event object contains a lot of useful properties. Most of the properties in the W3C specification are documented below; for more information, see the full specification. Type of event: bubbles A boolean indicating whether the event bubbles up through the DOM The Event Object | 21
  • 48. Properties reflecting the environment when the event was executed: button A value indicating which, if any, mouse button(s) was pressed ctrlKey A boolean indicating whether the Ctrl key was pressed altKey A boolean indicating whether the Alt key was pressed shiftKey A boolean indicating whether the Shift key was pressed metaKey A boolean indicating whether the Meta key was pressed Properties specific to keyboard events: isChar A boolean indicating whether the event has a key character charCode A unicode value of the pressed key (for keypress events only) keyCode A unicode value of a noncharacter key which A unicode value of the pressed key, regardless of whether it’s a character Where the event happened: pageX, pageY The event coordinates relative to the page (i.e., viewport) screenX, screenY The event coordinates relative to the screen Elements associated with the event: currentTarget The current DOM element within the event bubbling phase target, originalTarget The original DOM element relatedTarget The other DOM element involved in the event, if any These properties vary in browsers, especially among those that are not W3C-compliant. Luckily, libraries like jQuery and Prototype will smooth out any differences. 22 | Chapter 2: Events and Observing
  • 49. Event Libraries In all likelihood you’ll end up using a JavaScript library for event management; other- wise, there are just too many browser inconsistencies. I’m going to show you how to use jQuery’s event management API, although there are many other good choices, such as Prototype, MooTools, and YUI. Refer to their respective APIs for more in-depth documentation. jQuery’s API has a bind() function for adding cross-browser event listeners. Call this function on jQuery instances, passing in an event name and handler: jQuery("#element").bind(eventName, handler); For example, you can register a click handler on an element like so: jQuery("#element").bind("click", function(event) { // ... }); jQuery has some shortcuts for event types like click, submit, and mouseover. It looks like this: $("#myDiv").click(function(){ // ... }); It’s important to note that the element must exist before you start adding events to it—i.e., you should do so after the page has loaded. All you need to do is listen for the window’s load event, and then start adding listeners: jQuery(window).bind("load", function() { $("#signinForm").submit(checkForm); }); However, there’s a better event to listen for than the window’s load, and that’s DOMContentLoaded. It fires when the DOM is ready, but before the page’s images and stylesheets have downloaded. This means the event will always fire before users can interact with the page. The DOMContentLoaded event isn’t supported in every browser, so jQuery abstracts it with a ready() function that has cross-browser support: jQuery.ready(function($){ $("#myForm").bind("submit", function(){ /* ... */ }); }); In fact, you can skip the ready() function and pass the handler straight to the jQuery object: jQuery(function($){ // Called when the page is ready }); Event Libraries | 23
  • 50. Context Change One thing that’s often confusing about events is how the context changes when the handler is invoked. When using the browser’s native addEventListener(), the context is changed from the local one to the targeted HTML element: new function(){ this.appName = "wem"; document.body.addEventListener("click", function(e){ // Context has changed, so appName will be undefined alert(this.appName); }, false); }; To preserve the original context, wrap the handler in an anonymous function, keeping a reference to it. We covered this pattern in Chapter 1, where we used a proxy function to maintain the current context. It’s such a common pattern that jQuery includes a proxy() function—just pass in the function and context in which you want it to be invoked: $("signinForm").submit($.proxy(function(){ /* ... */ }, this)); Delegating Events It may have occurred to you that since events bubble up, we could just add a listener on a parent element, checking for events on its children. This is exactly the technique that frameworks like SproutCore use to reduce the number of event listeners in the application: // Delegating events on a ul list list.addEventListener("click", function(e){ if (e.currentTarget.tagName == "li") { /* ... */ return false; } }, false); jQuery has a great way of doing this; simply pass the delegate() function a child se- lector, event type, and handler. The alternative to this approach would be to add a click event to every li element. However, by using delegate(), you’re reducing the number of event listeners, improving performance: // Don't do this! It adds a listener to every 'li' element (expensive) $("ul li").click(function(){ /* ... */ }); // This only adds one event listener $("ul").delegate("li", "click", /* ... */); 24 | Chapter 2: Events and Observing
  • 51. Another advantage to event delegation is that any children added dynamically to the element would still have the event listener. So, in the above example, any li elements added to the list after the page loaded would still invoke the click handler. Custom Events Beyond events that are native to the browser, you can trigger and bind them to your own custom events. Indeed, it’s a great way of architecting libraries—a pattern a lot of jQuery plug-ins use. The W3C spec for custom events has been largely ignored by the browser vendors; you’ll have to use libraries like jQuery or Prototype for this feature. jQuery lets you fire custom events using the trigger() function. You can namespace event names, but namespaces are separated by full stops and reversed. For example: // Bind custom event $(".class").bind("refresh.widget", function(){}); // Trigger custom event $(".class").trigger("refresh.widget"); And to pass data to the event handler, just pass it as an extra parameter to trigger(). The data will be sent to callbacks as extra arguments: $(".class").bind("frob.widget", function(event, dataNumber){ console.log(dataNumber); }); $(".class").trigger("frob.widget", 5); Like native events, custom events will propagate up the DOM tree. Custom Events and jQuery Plug-Ins Custom events, often used to great effect in jQuery plug-ins, are a great way to architect any piece of logic that interacts with the DOM. If you’re unfamiliar with jQuery plug- ins, skip ahead to Appendix B, which includes a jQuery primer. If you’re adding a piece of functionality to your application, always consider whether it could be abstracted and split out in a plug-in. This will help with decoupling and could leave you with a reusable library. For example, let’s look at a simple jQuery plug-in for tabs. We’re going to have a ul list that will respond to click events. When the user clicks on a list item, we’ll add an active class to it and remove the active class from the other list items: <ul id="tabs"> <li data-tab="users">Users</li> <li data-tab="groups">Groups</li> </ul> <div id="tabsContent"> Custom Events and jQuery Plug-Ins | 25
  • 52. <div data-tab="users"> ... </div> <div data-tab="groups"> ... </div> </div> In addition, we have a tabsContent div that contains the actual contents of the tabs. We’ll also be adding and removing the active class from the div’s children, depending on which tab was clicked. The actual displaying and hiding of the tabs will be done by CSS—our plug-in just toggles the active class: jQuery.fn.tabs = function(control){ var element = $(this); control = $(control); element.find("li").bind("click", function(){ // Add/remove active class from the list-item element.find("li").removeClass("active"); $(this).addClass("active"); // Add/remove active class from tabContent var tabName = $(this).attr("data-tab"); control.find(">[data-tab]").removeClass("active"); control.find(">[data-tab='" + tabName + "']").addClass("active"); }); // Activate first tab element.find("li:first").addClass("active"); // Return 'this' to enable chaining return this; }; The plug-in is on jQuery’s prototype, so it can be called on jQuery instances: $("ul#tabs").tabs("#tabContent"); What’s wrong with the plug-in so far? Well, we’re adding a click event handler onto all the list items, which is our first mistake. Instead, we should be using the delegate() function covered earlier in this chapter. Also, that click handler is massive, so it’s dif- ficult to see what’s going on. Furthermore, if another developer wanted to extend our plug-in, he’d probably have to rewrite it. Let’s see how we can use custom events to clean up our code. We’ll fire a change.tabs event when a tab is clicked, and bind several handlers to change the active class as appropriate: jQuery.fn.tabs = function(control){ var element = $(this); control = $(control); element.delegate("li", "click", function(){ // Retrieve tab name var tabName = $(this).attr("data-tab"); // Fire custom event on tab click element.trigger("change.tabs", tabName); 26 | Chapter 2: Events and Observing
  • 53. }); // Bind to custom event element.bind("change.tabs", function(e, tabName){ element.find("li").removeClass("active"); element.find(">[data-tab='" + tabName + "']").addClass("active"); }); element.bind("change.tabs", function(e, tabName){ control.find(">[data-tab]").removeClass("active"); control.find(">[data-tab='" + tabName + "']").addClass("active"); }); // Activate first tab var firstName = element.find("li:first").attr("data-tab"); element.trigger("change.tabs", firstName); return this; }; See how much cleaner the code is with custom event handlers? It means we can split up the tab change handlers, and it has the added advantage of making the plug-in much easier to extend. For example, we can now programmatically change tabs by firing our change.tabs event on the observed list: $("#tabs").trigger("change.tabs", "users"); We could also tie up the tabs with the window’s hash, adding back button support: $("#tabs").bind("change.tabs", function(e, tabName){ window.location.hash = tabName; }); $(window).bind("hashchange", function(){ var tabName = window.location.hash.slice(1); $("#tabs").trigger("change.tabs", tabName); }); The fact that we’re using custom events gives other developers a lot of scope when extending our work. Non-DOM Events Event-based programming is very powerful because it decouples your application’s architecture, leading to better self-containment and maintainability. Events aren’t re- stricted to the DOM though, so you can easily write your own event handler library. The pattern is called Publish/Subscribe, and it’s a good one to be familiar with. Publish/Subscribe, or Pub/Sub, is a messaging pattern with two actors, publishers, and subscribers. Publishers publish messages to a particular channel, and subscribers sub- scribe to channels, receiving notifications when new messages are published. The key Non-DOM Events | 27
  • 54. here is that publishers and subscribers are completely decoupled—they have no idea of each other’s existence. The only thing the two share is the channel name. The decoupling of publishers and subscribers allows your application to grow without introducing a lot of interdependency and coupling, improving the ease of maintenance, as well as adding extra features. So, how do you actually go about using Pub/Sub in an application? All you need to do is record handlers associated with an event name and then have a way of invoking them. Here’s an example PubSub object, which we can use for adding and triggering event listeners: var PubSub = { subscribe: function(ev, callback) { // Create _callbacks object, unless it already exists var calls = this._callbacks || (this._callbacks = {}); // Create an array for the given event key, unless it exists, then // append the callback to the array (this._callbacks[ev] || (this._callbacks[ev] = [])).push(callback); return this; }, publish: function() { // Turn arguments object into a real array var args = Array.prototype.slice.call(arguments, 0); // Extract the first argument, the event name var ev = args.shift(); // Return if there isn't a _callbacks object, or // if it doesn't contain an array for the given event var list, calls, i, l; if (!(calls = this._callbacks)) return this; if (!(list = this._callbacks[ev])) return this; // Invoke the callbacks for (i = 0, l = list.length; i < l; i++) list[i].apply(this, args); return this; } }; // Example usage PubSub.subscribe("wem", function(){ alert("Wem!"); }); PubSub.publish("wem"); You can namespace events by using a separator, such as a colon (:). PubSub.subscribe("user:create", function(){ /* ... */ }); 28 | Chapter 2: Events and Observing
  • 55. Other documents randomly have different content
  • 56. Auf dem Altenteil Eine Silvester- Stimmung
  • 57. I. ie hatten den Senioren der Familie alle Ehre angetan, wie sich das denn auch wohl so von Rechts wegen gebührte; aber der Lärm wurde den weißhaarigen Herrschaften allmählich doch ein wenig zu arg. Die alte Dame, die immer noch um ein paar Jahre jünger war als der alte Herr, hatte dem letzteren ein ihm schon längst wohlbekanntes kopfschüttelnd Lächeln gezeigt, welches weiter nichts bedeutete als: „Kind, Kind, bedenke den Morgen und deinen Rheumatismus! Es hat alles seine Zeit, und ich glaube, die unsrige ist jetzt vorhanden.“ Der alte Herr hatte zuerst ganz erstaunt aufgesehen und sein Weib an: Nicht mehr bis Mitternacht, und in das neue Jahr hinein? Ei, ei, ei — hm! „Hm,“ sagte der alte Herr, in dem fröhlichen Kreise erhitzter Gesichter umherblickend; „es hat freilich alles seine Zeit; aber es ist sonderbar, und, liebe Kinder, es kommt einem ganz kurios vor, wenn auch dieses — zum erstenmal Zeit wird!“ Dabei hatte er sich aber bereits etwas mühsam aus seinem Sessel erhoben. Den Kopf schüttelte er auch; jedoch ohne dabei zu lächeln wie seine Frau. „Du hast recht, Anna; es ist unsere Zeit gekommen, und so wünsche ich, wünschen wir euch jungem Volk —“ Von einem Gewissen war bei diesem „jungen Volk“ natürlich nicht die Rede. Dazu waren sie sämtlich (auch die Ältesten unter ihnen) noch viel zu jung, und viel zu vergnügt und viel zu aufgeregt durch
  • 58. die uralten, ewig jungen Stimmungen der letzten Stunden des scheidenden Jahres. Ein Gewühl von blonden und braunen Köpfchen und Köpfen, von Händen und Händchen erhob sich um die beiden Greise; und alle Verführungskünste, deren die Menschheit in ihrer Erscheinung als Familie in der Silvesternacht fähig ist, waren zur Anwendung gebracht worden. Einmal noch schadete es sicherlich gewiß nicht!... Großpapa und Großmama hatten noch nie so munter ausgesehen!... Es ging ja niemand zu Bett vor Mitternacht, selbst die Jüngsten nicht!... „Nun, Mutter! Einmal noch? Was meinst du?“ Kleine weiße Händchen — weiße beringte Hände hatten ihre Verführungskünste nicht ohne Erfolg versucht; nun legte sich statt anderer Antwort auf die Frage des alten Herrn wieder eine Hand auf die seinige. Das war aber keine weiche, keine weiße, keine kräftige mehr; aber eine starke und treue war es auch; vielleicht wohl die stärkste und treueste. „Die Großmutter hat recht! Es hat alles seine Zeit, und die unsrige ist gekommen. Junges Volk, wir werden zu Bette geschickt von ihr, der Madame Zeit, während die Jüngsten aufbleiben dürfen. Der Kopf summt uns zu sehr morgen früh, wenn wir uns dagegen sperren und wehren; und es ist zwar hübsch von Großmama, wenn sie nur von Rheumatismus spricht; aber das rechte Wort ist es eigentlich nicht. Sie hätte ganz dreist Gicht sagen können, gerade so gut wie der Herr Schwiegersohn und Doctor medicinae da hinter seinem Punschglase, wenn er jetzt ein Gewissen hätte. Liebe Kinder, wir sind beide über siebenzig Jahre alt, und —“ „Oh!...“ „Und wir sind sehr glücklich und behaglich. Sehr wohl ist uns zumute und so wünschen wir euch allen zum erstenmal vor Ablauf des alten Jahres ein glückliches neues.... Bitte, lieber Sohn, ich weiß, was du sagen willst; aber wende dich damit an die Mama, die wird dich versichern, daß deine Frau, unsere liebe Sophie da, heute über dreißig Jahre sicherlich gleichfalls viel verständiger sein wird, als du. Wende dich an deine Mutter, mein Schmeichelkätzchen Marie. Sie
  • 59. hat immer gemeint, du seiest ganz ihr Vorbild, also wirst du wohl wissen, was in vierzig Jahren in der Neujahrsnacht deine Meinung sein wird, wenn die unverständige Jugend dir deinen Mann da verführen will. Schieben Sie die Kinder nicht so heran, lieber Schwiegersohn, sie machen der Großmama nur das Herz schwer. Es ist Zeit geworden für uns; — — — ein fröhliches, segensreiches Jahr ihr — alle!...“ „Alle!“ jubelten sie, und die Gläser hatten geklungen, und die Kinder, die Enkel hatten sich zugedrängt und ihre kleinen Becher hingehalten, ohne daß man sie dazu zu schieben brauchte. Sie hatten sehr gejubelt; und die Tonwellen der Gläser und der Stimmen waren verklungen. „Nun seid weiter vergnügt; aber die Kinder laßt ihr mir morgen ausschlafen. Begleitung nehmen wir nicht mit, die Trepp’ hinauf. Wir finden unseren Weg schon allein, nicht wahr, Walter?“ sagte die alte Dame, die Großmutter des Hauses.
  • 60. II. ie entschlüpften, wie man entschlüpft, wenn man das siebenzigste Lebensjahr hinter sich hat. Langsam stiegen die beiden die teppichbelegte Treppe in ihre Stube hinauf, der Greis gestützt auf den Arm der Greisin; und dann waren sie allein miteinander, noch einmal allein miteinander in der Neujahrsnacht.... Umgesehen hatten sie sich nicht auf der Treppe und einen leisen Schritt, einen Kinderschritt, der ihnen nachglitt, den hatten sie überhört. Ein so scharfes Ohr, wie vor Jahren, hatte keins von den zwei Alten mehr; aber diesen Schritt, diesen Geister- Kinderschritt würde auch wohl jedes andere jüngere Ohr überhört haben. — Auf dem Altenteil! Das kann eines der bittersten Worte sein, die das Schicksal den Menschen in dieser Welt zuruft; aber auch eines der behaglichsten. Für diese beiden Alten war es nach langer schwerer, mühseliger Arbeit ein behagliches geworden. Sie fanden ihre Gemächer durch ein verschleiertes Lampenlicht erhellt, ihre beiden Lehnstühle an den warmen Ofen gerückt und: „Mit dem Schlage Zwölf komme ich doch und poche an eurer Kammertür und spreche meinen Wunsch durchs Schlüsselloch. Ihr braucht aber nicht darauf zu hören; ich schicke ihn euch auch in den Schlaf hinein!“ hatte das jüngste und am jüngsten verheiratete Töchterlein als letztes Wort im Festsaale da unten gesagt. „O mein Gott, da sitzt ihr noch?“ rief dieselbe junge Frau unter dem Glockenklang und dem Neujahrschoral von den Türmen, unter dem plötzlich aufklingenden Gassenjubel und dem Jubel der Kinder und
  • 61. Enkel in dem Saale des Hauses. „Das ist doch ganz wider die Abrede, und heute übers Jahr werden wir euch da unten bei uns fester halten, ihr Lieben, Bösen, Besten!... Ein glückliches neues Jahr, Großpapa! ein glückliches neues Jahr, Großmama!“ Da stand ein niedrig lehnenloses Sesselchen mit einem verblaßten gestickten Blumenstrauß darauf neben den zwei Stühlen der Greise. Die junge Frau, nachdem sie den Vater und die Mutter mit ihren Küssen fast erstickt hatte, saß nieder auf dem kleinen Stuhl und hatte keine Ahnung davon, wer eben vor ihr darauf gesessen und die Mutter und den Vater gegen die Abrede und gegen ihren eigenen festen Vorsatz wach gehalten hatte über die Mitternachtsstunde hinaus und aus dem alten Jahr in das neue hinein! Mit leise bebender Hand strich die alte Frau die blonden Haare der Tochter aus dem lebensfreudigen, glühenden, erhitzten Gesichte. Die blonden Locken, die sich eben vor ihr ringelnd bewegt hatten, waren schon vor vierzig Jahren zu Staub und Asche geworden: die junge Frau wußte nichts von ihnen, oder doch nur gerüchtweise. Lange vor ihrer Geburt war das erste, das älteste Kind gestorben, zwölf Jahre alt. Ein halbverwischtes Pastellbildchen, das über der Kommode der Mutter, der Großmutter des Hauses, hing, war alles, was von ihm übrig geblieben war in der Welt. Alles?
  • 62. III. in leiser Schritt, ein unhörbarer Schritt; — ein Geister- Kinderschritt in der Silvesternacht!... Wir haben gesagt, daß die beiden Greise vor einer Stunde die Treppe zu ihren Gemächern hinaufgestiegen und ihn, wie wir übrigen alle, nicht vernahmen. Ganz war es doch nicht so. Als der alte Herr der alten Dame mit immer noch zierlicher Höflichkeit die Tür öffnete, um sie zuerst über die Schwelle treten zu lassen, hatte die Frau einen Augenblick gezögert und zurückgesehen und gehorcht. Der alte Herr glaubte, sie horche noch einmal auf den fröhlichen Lärm, auf das heitere Stimmengewirr der Neujahrsnacht dort unten im Festsaal des Hauses. „Sie sind gottlob recht heiter,“ meinte er, „wüßte auch nicht, weshalb nicht. Und auch wir, — Mutter! — nicht wahr, Alte?... Wie spät ist es denn eigentlich? Elf Uhr! Noch früh am Tage, wenngleich wirklich ein wenig spät im Jahre.“ „Ja, Walter!“ hatte die Greisin erwidert, aber nur, um doch eine Antwort zu geben. „Ich hörte eigentlich nicht auf dich; ich dachte an unser Ännchen,“ fügte sie hinzu, als sich die Tür hinter ihnen geschlossen hatte und sie in der letzten Stunde des ablaufenden Jahres mit sich allein waren.
  • 63. IV. as junge Volk! Längst hat es drei Viertel des Hauses nach seinem Geschmack und Bedürfnis eingerichtet und mit vollem Rechte des Lebens. An das Reich der beiden Alten hat keine Hand gerührt; außer dann und wann eine Kinderhand, deren volles Recht des Lebens es freilich ist und immerdar sein wird, in der Großväter und der Großmütter Hausrat, Schubladen und Schränken zu wühlen und zu kramen und sich die vom Anfang der Welt an dazugehörigen erstaunungswürdigen, lustigen und traurigen Geschichten erzählen zu lassen. Es war einmal!... oh, noch einmal von dem, was war!... Und so war es gekommen, daß die jüngste Tochter des Hauses die Eltern um Mitternacht noch wach fand unter den Glocken, die das neue Jahr einläuteten. Eine Kinderhand aber war es wiederum gewesen, die an den Schleiern der Vergangenheit gezupft hatte: „Es war einmal! Ich bin da! — Mama, du sagst in dieser Stunde nicht: Man hat doch keinen Augenblick Ruhe vor dir, Kind! — Ich bin da; und nun laßt mich sitzen auf meinem Stuhl, laßt uns erzählen: Es war einmal!... laßt uns erzählen von dem, was einmal war!“... Und sie hatten davon erzählt, die beiden Greise nämlich. Das Kind hatte nur drein gesprochen. „Sie wäre gewiß auch eine stattliche Frau und eine gute geworden,“ sagte die alte Dame. „Ich meine, am meisten hätte sie wohl der Theodore geglichen, wenn wir sie behalten hätten, das liebe Kind. Sie haben alle da unten, — unsere meine ich, Papa! — ein hübsches lustiges Lachen; aber ich kann nichts dafür, ich muß es sagen: wie
  • 64. das Kind, unser Ännchen, ist doch keins so glücklich in seinem Lachen gewesen. Die andern kennen wir ja auch nun schon lange mit ihren Sorgen und ihren Nöten und ihren unnützen Ärgernissen. Keins von ihnen lacht und kreischt und kichert so wie mein Ännchen es tat. Hätten wir die Enkel nicht, so würde das Haus wohl manchmal still genug sein; — selbst dir, Großpapa.“ Da war das Lachen, das vor so langen, langen Jahren zuerst das Haus hell und heiter gemacht hatte! Auch der alte Herr, der Großpapa, dem das Haus nie ruhig genug sein konnte, kannte es ganz genau. „Also, ihr wißt es doch noch, wie es war, als wir drei allein waren, und dein Haar noch nicht so weiß, Vater; und auch deines nicht so hübsch grau, mein Mütterchen, und ich euer liebes, einziges Mädchen! Hier sitze ich auf meinem Stuhl und behalte mein Recht, allen meinen Schwestern und Brüdern und allen meinen Nichten und Neffen zum Trotz. Ich bin die Älteste! Wer auch nach mir gekommen ist, wie viele auch gesessen haben auf diesem Schemelchen — mir gehört es, mir habt ihr es hierher gestellt; das ist mein Sitz am Herde! Wer kann mir meinen Platz nehmen in eurer Seele? wer in dem Hause, das ihr gebaut habt und in dem ihr mich einmal euer Glück nanntet?!“ „Du hast recht, Mutter,“ sagte der alte Herr; „ich weiß eigentlich nicht, wie wir gerade jetzt darauf kommen; aber das Kind hat immer zu mir, — zu uns gehört. Nur weil wir es wußten, haben wir nicht immer dran gedacht. So geht es aber mit allem Wissenswürdigen in der Welt.“ „Mein Ännchen!“ seufzte einfach die Greisin; doch die blonden Locken wurden wie mutwillig von neuem geschüttelt, und wieder legte sich der kleine Finger schalkhaft auf den Mund: „Ja, ich war immer da, wenn ihr auch nicht an mich zu denken glaubtet: an manchem schwülen Sommertage, in mancher kalten, dunkeln, trostlosen Winternacht. An manchem Feste in der lichtstrahlenden Winternacht, an manchem sonnigen, seufzervollen Frühlingsmorgen. Jetzt haben die andern da unten im Saale euere Sorgen, Freuden
  • 65. und Arbeiten. Ihr aber habt Zeit für mich. Eure andern, die nach mir gekommen sind, haben mir wohl mein altes Spielzeug verkramt und zerbrochen; aber mein Plätzchen im Hause haben sie mir nicht nehmen können. Ich habe es ihnen nur geliehen, einem nach dem andern; doch mein Eigentum ist es und bleibt es; nicht wahr, Papa und Mama?! Ihr habt zwar unter den andern gottlob nun auch wieder ein Ännchen — ein Enkelkind mit meinem Namen — aber das tut nichts, wir vertragen uns schon um diesen kleinen Stuhl und um — euch!... Es war wohl ein kleiner Sarg, in den ihr mich legen mußtet; aber — ich bin immer über meine Jahre klug gewesen. Ich habe es wohl oft heimlich erlauscht, wenn ihr das über mich sagtet. Damals wußte ich freilich nicht recht, was ihr damit sagen wolltet, und ob es eigentlich ein Lob für mich sei; jetzt aber weiß ich es. Ei ja, ich bin sehr klug für meine Jahre gewesen! nun lacht nur, wie ihr damals geweint habt, als ich von euch weggeführt wurde und nicht über die Schulter zurücksehen durfte. Seht ihr wohl, da lächelt ihr wenigstens schon. Die Jahre sind nun hingegangen; lange, lange Jahre! Heute abend habt ihr euch vorgenommen, noch einmal jung zu sein mit euren Kindern und Enkeln. Es ist euch auch wohl gelungen, doch nicht ganz. Ganz jung seid ihr erst jetzt wieder, da ich mich zu euch gesetzt habe, ich — euere Älteste und euere Jüngste. Nimm meinen Krauskopf wieder zwischen deine Hände, Mutter, laß mich wieder auf deinem Knie sitzen, Väterchen; draußen schneit es sehr, und der Nordwind bläst, und es ist spät in der Nacht; ihr aber schickt mich diesmal noch nicht zu Bett; — wir wollen jetzt einander noch nicht zu Bette schicken; wir wollen noch einmal ein Weilchen sitzen und erzählen von d e m , w a s e i n m a l w a r .“
  • 66. V. ie hatten nur noch fünf Minuten in ihren Großväterstühlen neben dem Ofen sitzen wollen, um sich von dem Feste, dem Händedrücken, all den Küssen und guten Wünschen zu dem neuen kommenden Jahre ein wenig zu erholen, wie es den ältesten Leuten in der Familie geziemt in der Silvesternacht, während die Jugend um die lichterglänzende Festtafel weiter jubelt und lärmt, nach der Uhr sieht und den Sekundenzeiger mit lachendem Auge verfolgt bis heran an den neuen ernsten Grenzstein ihrer Erdenzeit. Und sie, die bereits Greise waren, hatten nicht nach der Uhr gesehen; sie hatten gar nicht einmal daran gedacht. Die Sekunden der letzten Stunden des Jahres waren ihnen dahingeglitten, wie die vielen, langen arbeitsvollen, inhaltreichen Jahre ihres Daseins selber bis in dieses jüngste und das eben vor der Tür stehende hinein. „Du fragst wohl, Vater, wie wir gerade jetzt darauf kommen, und sagst, daß du an das Kind lange nicht gedacht hast,“ sagte die alte Dame. „Es ist freilich lange her, daß wir ihren kleinen Sarg dort in dem Saale, wo sie jetzt gottlob so lustig sind, aufstellen mußten. Wie wunderlich es doch ist, daß ich gerade jetzt darauf komme, was für eine schöne Sommernacht es war, in welcher sie starb! Horch jetzt nur, wie der Wind den Schnee gegen die Fenster treibt. Wir haben die andern alle behalten und wir haben an unseren Kindeskindern Freude; aber an unsere Älteste habe ich doch immer gedacht. Was würde aus den Kindern werden, wenn ihre Mütter nicht immer an sie dächten. Selbst die Gestorbenen können ohne ihre Mutter nicht auskommen. — Horch, wie sie es da unten treiben! eigentlich ist es recht unrecht von ihnen, daß sie auch die Jüngsten so lange aus
  • 67. dem Bette zurückhalten, und ich werde ihnen morgen früh auch jedenfalls meine Meinung darüber sagen. — Als s i e in ihrem Fieber lag, saß ich auch und zerrang mir die Hände und fragte mich Tag und Nacht, was ich hätte anders machen können, damit das Schreckliche nicht so zu kommen brauchte. Du warst wohl vernünftiger, wenn du aus deinem Kontor heraufkamst und mir zuredetest, Geduld zu haben. Wie konnte ich wohl verständig sein und Geduld haben? Und man sucht doch immer so, wie man einem andern die Schuld geben kann, und wäre man das auch selber!“ „Ich meine, Mutter, wir geben das auf, uns den Kopf darüber zu zerbrechen, und noch dazu so spät in der Nacht, im Jahr und in den Jahren,“ sprach der alte Herr, wiederum sehr vernünftig; und dann sprachen sie bis zu dem ersten Glockenschlage der Mitternacht nichts mehr miteinander. Dagegen aber füllte sich ihre Stube immer mehr mit den Bildern und den Klängen der Vergangenheit. Und der liebliche Spuk der Silvesternacht hatte nicht das geringste vom Phantasten an sich. Das älteste Kind des Hauses war noch einmal im vollen blühenden Leben Herrin im Reich und fand all sein altes verkramtes Spielzeug wieder, wie — die zwei weißhaarigen Greise. Sie paßten wieder ganz zueinander, die Eltern und das Kind: der dunkle, geheimnisvolle Vorhang der Zukunft hatte sich bewegt, und es war eine Kinderhand, die sich aus den schwarzen Falten weiß und zierlich hervorstreckte und winkte. Sie aber, die Fröhlichen da unten im Festsaale des Hauses, hatten dem Vater und der Mutter, dem Großvater und der Großmutter — den beiden Alten ein glückliches, ein segensreiches neues Jahr gewünscht und hatten zwischen Becherklang und lustigem Lachen ihren Wunsch wehmütig ernst gemeint, wie sich das gebührte. „Wie gut der Papa und die Mama heute abend aussahen,“ meinten sie. „Es ist doch eine Freude, wie frisch sie sich erhalten und wie sie noch an allem teilnehmen. Aber verständig war es doch, daß sie nicht über ihre Zeit bei uns sitzen blieben. Morgen früh hätten wir uns doch Vorwürfe gemacht, wenn wir sie noch länger gequält hätten, das Vergnügen nicht durch ihr Weggehen zu stören.... Jetzt aber auf die Uhr gesehen! in fünf Minuten wird es Zwölf schlagen; —
  • 68. ein bißchen leise, Kinder, daß w i r d i e a l t e n L e u t e n i c h t w e c k e n ! “... Zwölf Uhr und — ein neues Jahr! Alle guten Geister haben einen leisen Schritt und gehen auf weichen Sohlen; so schlich sich die jüngste Tochter des Hauses weg aus dem jubelnden Kreis, glitt die Treppe hinauf und horchte an der Tür der „alten Leute“, die durch den Becherklang, die lauten Glückwünsche und alles, was sonst noch in die Stunde gehört, nicht gestört werden sollten in ihrer Ruhe auf dem Altenteil. „O mein Gott, da sitzt ihr noch? Das ist doch ganz wider die Abrede! Sie meinen alle da unten, daß ihr längst in den Federn liegt und euch behaglich in das neue Jahr hinübergeträumt habt.“ „Das letztere haben wir auch getan, mein Kind,“ sagte der alte Herr nachdenklich lächelnd. „Oh, und nun müßte ich sie alle — alle die übrigen auch noch heraufrufen, daß sie euch ihre Meinung sagen. Sie werden es mit Recht sehr übel nehmen, wenn ich’s nicht auf der Stelle tue, Mama!“ „Laß es lieber, mein Herz,“ meinte die alte Dame, leise die blonden Flechten vor ihr, die noch nicht Staub und Asche geworden waren, streichelnd. „Es würde den Vater doch zu sehr aufregen, und wir gehen nun wirklich gleich zu Bett. Wir haben vorher nur noch ein wenig an allerlei gedacht, was vor eurer — vor deiner Zeit war.“ „Ach ich bin so glücklich!“ rief die junge Frau. „Wir sind so vergnügt da unten an unserem Tische, und ihr hier in euerer lieben, alten, guten Stube seht so jung aus und so hell aus den Augen, wie das Jüngste von uns — euern andern! Oh, und mein Franz ist so drollig; der Mensch ist mir fast ein wenig zu ausgelassen, oh — und also noch einmal: ein fröhliches, glückliches, gesegnetes neues Jahr euch vor allen und — uns andern auch!“ „Ja, ja!“ sagten die a l t e n L e u t e leise zu gleicher Zeit und nickten freundlich ihre Zustimmung zu dem guten Wunsch.
  • 69. *** END OF THE PROJECT GUTENBERG EBOOK DER JUNKER VON DENOW; EIN GEHEIMNIS; EIN BESUCH; AUF DEM ALTENTEIL: ERZÄHLUNGEN *** Updated editions will replace the previous one—the old editions will be renamed. Creating the works from print editions not protected by U.S. copyright law means that no one owns a United States copyright in these works, so the Foundation (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth in the General Terms of Use part of this license, apply to copying and distributing Project Gutenberg™ electronic works to protect the PROJECT GUTENBERG™ concept and trademark. Project Gutenberg is a registered trademark, and may not be used if you charge for an eBook, except by following the terms of the trademark license, including paying royalties for use of the Project Gutenberg trademark. If you do not charge anything for copies of this eBook, complying with the trademark license is very easy. You may use this eBook for nearly any purpose such as creation of derivative works, reports, performances and research. Project Gutenberg eBooks may be modified and printed and given away—you may do practically ANYTHING in the United States with eBooks not protected by U.S. copyright law. Redistribution is subject to the trademark license, especially commercial redistribution. START: FULL LICENSE
  • 70. THE FULL PROJECT GUTENBERG LICENSE
  • 71. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg™ mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase “Project Gutenberg”), you agree to comply with all the terms of the Full Project Gutenberg™ License available with this file or online at www.gutenberg.org/license. Section 1. General Terms of Use and Redistributing Project Gutenberg™ electronic works 1.A. By reading or using any part of this Project Gutenberg™ electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg™ electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg™ electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. “Project Gutenberg” is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg™ electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg™ electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg™ electronic works. See paragraph 1.E below.
  • 72. 1.C. The Project Gutenberg Literary Archive Foundation (“the Foundation” or PGLAF), owns a compilation copyright in the collection of Project Gutenberg™ electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is unprotected by copyright law in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, displaying or creating derivative works based on the work as long as all references to Project Gutenberg are removed. Of course, we hope that you will support the Project Gutenberg™ mission of promoting free access to electronic works by freely sharing Project Gutenberg™ works in compliance with the terms of this agreement for keeping the Project Gutenberg™ name associated with the work. You can easily comply with the terms of this agreement by keeping this work in the same format with its attached full Project Gutenberg™ License when you share it without charge with others. 1.D. The copyright laws of the place where you are located also govern what you can do with this work. Copyright laws in most countries are in a constant state of change. If you are outside the United States, check the laws of your country in addition to the terms of this agreement before downloading, copying, displaying, performing, distributing or creating derivative works based on this work or any other Project Gutenberg™ work. The Foundation makes no representations concerning the copyright status of any work in any country other than the United States. 1.E. Unless you have removed all references to Project Gutenberg: 1.E.1. The following sentence, with active links to, or other immediate access to, the full Project Gutenberg™ License must appear prominently whenever any copy of a Project Gutenberg™ work (any work on which the phrase “Project Gutenberg” appears, or with which the phrase “Project Gutenberg” is associated) is accessed, displayed, performed, viewed, copied or distributed:
  • 73. This eBook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. 1.E.2. If an individual Project Gutenberg™ electronic work is derived from texts not protected by U.S. copyright law (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase “Project Gutenberg” associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg™ electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg™ License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg™ License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg™. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1
  • 74. with active links or immediate access to the full terms of the Project Gutenberg™ License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg™ work in a format other than “Plain Vanilla ASCII” or other format used in the official version posted on the official Project Gutenberg™ website (www.gutenberg.org), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original “Plain Vanilla ASCII” or other form. Any alternate format must include the full Project Gutenberg™ License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg™ works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg™ electronic works provided that: • You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg™ works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg™ trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, “Information
  • 75. about donations to the Project Gutenberg Literary Archive Foundation.” • You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg™ License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg™ works. • You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. • You comply with all other terms of this agreement for free distribution of Project Gutenberg™ works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™ electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from the Project Gutenberg Literary Archive Foundation, the manager of the Project Gutenberg™ trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread works not protected by U.S. copyright law in creating the Project Gutenberg™ collection. Despite these efforts, Project Gutenberg™ electronic works, and the medium on which they may be stored, may contain “Defects,” such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or
  • 76. damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right of Replacement or Refund” described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg™ trademark, and any other party distributing a Project Gutenberg™ electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
  • 77. INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg™ electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg™ electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg™ work, (b) alteration, modification, or additions or deletions to any Project Gutenberg™ work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg™ Project Gutenberg™ is synonymous with the free distribution of electronic works in formats readable by the widest variety of computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need are critical to reaching Project Gutenberg™’s goals and ensuring that the Project Gutenberg™ collection will
  • 78. remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg™ and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation information page at www.gutenberg.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non-profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation’s EIN or federal tax identification number is 64-6221541. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state’s laws. The Foundation’s business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up to date contact information can be found at the Foundation’s website and official page at www.gutenberg.org/contact Section 4. Information about Donations to the Project Gutenberg Literary Archive Foundation Project Gutenberg™ depends upon and cannot survive without widespread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine-readable form accessible by the widest array of equipment including outdated equipment. Many
  • 79. small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit www.gutenberg.org/donate. While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg web pages for current donation methods and addresses. Donations are accepted in a number of other ways including checks, online payments and credit card donations. To donate, please visit: www.gutenberg.org/donate. Section 5. General Information About Project Gutenberg™ electronic works Professor Michael S. Hart was the originator of the Project Gutenberg™ concept of a library of electronic works that could be freely shared with anyone. For forty years, he produced and distributed Project Gutenberg™ eBooks with only a loose network of volunteer support.
  • 80. Project Gutenberg™ eBooks are often created from several printed editions, all of which are confirmed as not protected by copyright in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our website which has the main PG search facility: www.gutenberg.org. This website includes information about Project Gutenberg™, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks.
  • 81. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com