HEALTH ASSESSMENT (Community Health Nursing) - GNM 1st YearPriyanshu Anand
Isharyanti-2025-Cross Language Communication in Indonesian LanguageNeny Isharyanti
PATIENT ASSIGNMENTS AND NURSING CARE RESPONSIBILITIES.pptxPRADEEP 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
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
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
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