The best way to learn how to use the WebCore is by example. See the documentation for more information.

The requested URL is always shown first; if a page uses one or more WebCore templates, those are shown afterwards.

00 <?php
01   include_once ('software/webcore_init.php');
02   $Page->title->subject = 'Features';
03   $Page->location->append ('WebCore', './');
04   $Page->location->append ('Features');
05   $Page->start_display ();
06 ?>
07 <div class="main-box">
08   <div class="columns text-flow">
09     <div>
10       <p>Before getting too deep into individual features, take a look at <a href="why.php">Why
11       earthli WebCore?</a> It describes the philosophy behind this framework. Once you've
12       got that under your belt, read on to see just how much the WebCore offers.</p>
13       <p>When you program with the WebCore, the different stages of preparing a web
14       page are clearly defined and well-supported.</p>
15       <ul>
16         <li>First, you decide which data you want to show in a page. Use <a href="#searching">searches</a>,
17           <a href="#lists">lists</a> or directly <a href="#database">query</a> to request
18           your objects from the <a href="#environment">application</a>.</li>
19         <li>The request is filtered through the current <a href="#users">login</a>,
20         which has certain <a href="#security">permissions</a> in the given <a href="#folders">context</a>.</li>
21         <li>Lists of objects and individual objects are <a href="#rendering">rendered</a>,
22         each object using <a href="#icons">icons</a> and <a href="#munger">formatting</a>
23         to return a consistent, compliant page to the <a href="#browser">browser</a>.</li>
24       </ul>
25       <h2>Your content</h2>
26       <h3><a id="users"></a>Users</h3>
27       <p>Pretty much any marginally-interactive website needs to address the concept
28       of logging in. As soon as you have stuff that some people can do and others can't,
29       you're going to need a solid <em>user concept</em>.</p>
30       <p>The WebCore provides a pretty deep implementation of users, including auto-registered
31       anonymous users. All users, registered and anonymous, are treated equally;
32       anonymous users are uniquely identified by IP address and can be restricted with
33       permissions just like normal users.</p>
34       <p>The user itself has a bunch of properties like name, home page, etc. already
35       implemented. And, last but certainly not least, a pretty smooth avatar
36       implementation lets your users customize their online appearance. WebCore
37       applications can easily use this icon in different places to make users stand
38       out.</p>
39       <p>Users can be shared across applications and handled with the same login; an
40       application can also define its own users. See <a href="#sharing">sharing</a>
41       for more information.</p>
42       <p>Logging in, logging out, applying user and content permissions: it's all
43       taken care of for you. See <a href="#security">security</a> for more information
44       about how it works.</p>
45       <h3 id="folders">Folders</h3>
46       <p>Almost any website you can think of is separated into sections. If you're
47       listing movies and movie reviews, you might break them up into genre. Photo
48       albums are broken up by year or destination. Some areas might be private or
49       allowed only for certain users.</p>
50       <p>Any earthli WebCore application can have as many folders as you like, nested
51       as deeply as you like. While you can define keywords and categories for free
52       searching and association, it's still nice to be able to apply at least a
53       rudimentary hierarchy to your data.</p>
54       <p>Folders are also the framework in which you define your application's <a href="#security">security</a>.
55       Subfolders automatically inherit permissions from their parent folder.</p>
56       <h3 id="comments">Comments</h3>
57       <p>As soon as you start to mix online content with online users, you've got <em>opinions</em>.
58       You can't have a community unless your users can talk to each other. The earthli
59       WebCore provides a general solution to comments that integrate into any
60       application.</p>
61       <p>Comments can be nested (so they answer each other) and presented in pages (so
62       you don't have to serve enormous pages). There are a bunch of view options, like
63       threaded or flat viewing.</p>
64       <h3 id="attachments">Attachments</h3>
65       <p>As with comments, its not long before you realize that text isn't the only
66       type of content your site has. You need a generic way to get binary content onto
67       your site and keep it organized. If you've got an article with 3 pictures, it
68       would be nice if those pictures were deleted if you deleted the article. Storage
69       space isn't free, right?</p>
70       <p>Attachments can be made for any object in a WebCore application: folders,
71       users, comments, even your custom application objects. Image attachments are
72       automatically detected and stored with a thumbnail (if you want one); other file
73       types get a type-specific icon. Since zip-file handling is integrated, a zip
74       attachment displays its file contents when viewed.</p>
75       <p>Once you've attached a file, you can easily show it in your text as a
76       thumbnail or full image. Check out <a href="text_formatting.php#paths">paths</a>
77       to find out more.</p>
78       <h3 id="history">History</h3>
79       <p class="quote-block">"Who changed what when?"</p>
80       <p>When you're a publisher (and on the web, we're all publishers!), you've got
81       to be concerned with auditing or tracking the <em>history</em> of the stuff you've
82       got on your website. It's important to a user to know when an item was created
83       and when it was last updated. When you're running a site, you want to know who
84       made changes to it.</p>
85       <p>Your site users are usually just concerned with when an item was last updated,
86       but you may want to know everything that's ever happened to it. Has it ever been
87       deleted? Why was it brought back? When?
88       <p>The earthli WebCore uses 'auditable' objects, which track their entire
89       histories as a series of 'actions' that occurred to a website object, like an
90       article, a comment, a folder or even a user. Pretty much everything is trackable.</p>
91       <h3 id="searching">Searching</h3>
92       <p>You've got all of your stuff in a database and users are making comments and
93       stories all the time. Now they want to find something. Well, you've got a nice <a href="#folders">folder</a>
94       hierarchy to help them out, right? The earthli WebCore offers much more powerful
95       searching than that.</p>
96       <ul>
97         <li>All objects in a WebCore application (your own objects, comments, users, etc.)
98         can be searched.</li>
99         <li>Constrain and sort by almost any field in an object.</li>
100         <li>Full-text search on any combination of text fields.</li>
101         <li>A powerful API makes adding new fields a snap. User-friendly forms and
102         search results are automatically generated for you.</li>
103       </ul>
104       <p>The WebCore's search engine runs on top of the <a href="#database">database</a>
105       layer. It takes care of displaying the search form and applying search
106       parameters to the query.</p>
107       <p>You can save searches and retrieve their results again later. So, you can do
108       cool things like
109       <span class="quote-inline">
110       "find all recipes made by Bob in the last week"
111       </span>
112       and always be able to check out what Bob's been up to.</p>
113       <p>You can also leave parameters open when you save the search, and let the
114       WebCore fill it in from the context. So, if you're on Alice's home page and you
115       run the search from above, you'd see all the recipes Alice made in the last week.</p>
116       <p>The WebCore uses searches to define your default interface, showing the lists
117       of different types of objects available. Users can redefine and add to these to
118       customize the interface to suit them. Searches work hand-in-hand with <a href="#lists">lists</a>
119       to help you get the most out of a WebCore application.</p>
120       <h3 id="lists">Lists</h3>
121       <p>With <a href="#searching">searches</a> you ask the database a question. The
122       database returns a list of objects as an answer. Now you want to do something
123       with them: print, email, delete, etc. You can select one of more items from a
124       search result and act on it directly, but what if one search result can't
125       contain everything you want?</p>
126       <p>That's where <em>lists</em> come in. You can take any or all of the objects
127       from a search result and move them to a list. Then you can run another search
128       and add some more objects to that list. You can delete objects from a list. When
129       your list is ready, print it, email it or just leave it. It'll be there when you
130       come back.</p>
131       <p>Searches define views on the database, but lists just store a fixed set of
132       objects that isn't necessarily based on a single query. </p>
133       <ul>
134         <li>You can make a list of stories you'd like to read and delete them from the
135         list as you finish them.</li>
136         <li>You can make a list of your all-time favorite funny comments or your
137         favorite pictures.</li>
138         <li>You can make lists of anything, just like you can search anything, so you
139         can make a list of users to be your "buddy list".</li>
140         <li>You can do a lot with the objects in a list: print, delete, purge, email,
141         even edit them! You can gather a whole bunch of objects and edit them all in one
142         big batch: a huge time-saver!
143         <li>Use temporary lists as you browse and search your way through an application.
144         When you're done with your research, delete the list.</li>
145         <li>Unlike searches, List contents don't change unless you change them.</li>
146       </ul>
147       <p>You don't need to do anything special to make lists work with your own
148       application objects. If your objects are searchable, they're listable.</p>
149       <h3 id="drafts">Drafts</h3>
150       <p>People will be using your application from everywhere. If your application
151       objects have a lot of text, users may not always be ready to publish their work
152       right away. You want to be able to save to the server, but keep other users away
153       from it until you're done.</p>
154       <p>The WebCore offers just that with <em>drafts</em>. If you define an object as
155       draftable, the form for it is automatically generated with a 'Save as draft'
156       button. Come back to the site later, <a href="#searching">search</a> for your
157       draft and keep working. When you're ready, you <a href="#publishing">publish</a>
158       it.</p>
159       <h2>Making it work</h2>
160       <h3 id="environment">Environment</h3>
161       <p>The WebCore gathers disparate PHP variables and functions that are really
162       useful when building web pages into a sensible object-oriented API.</p>
163       <ul>
164         <li>The <em>environment</em> provides url information, redirecting, exception
165         handling, basic date/time services and more.</li>
166         <li>The <em>page</em> handles rendering and global configuration.</li>
167         <li><em>Applications</em> manage your data objects and create global objects
168         like text-formatters, mailers and more.</li>
169         <li>A global <em>profiler</em> lets you time different parts of your code to see
170         what's slowing you down.</li>
171         <li>A global <em>logger</em> supports many output options, including a separate
172         JavaScript-driven window, so you can avoid using 'echo' for debugging. The
173         WebCore uses this log heavily and will show you what's going on when something
174         goes wrong.</li>
175       </ul>
176       <p>There are other classes and functions for file-handling, zip files and
177       different exception handlers. When an error occurs, all associated information
178       is automatically gathered and can be sent by the user via email.</p>
179       <h3 id="security">Security</h3>
180       <p>You can't escape it. As soon as you have an interactive system, you've got to
181       consider who gets to do what. Even if you don't spend a second actually thinking
182       about it, you've implicitly decided that everyone gets to do everything.</p>
183       <p>Most web sites probably don't want that.</p>
184       <p>Everything you do in an earthli WebCore application is based on a logged-in-user
185       (see <a href="#users">users</a> for more information). Even if no actual user
186       has logged in, the system assumes the rights of an anonymous user. The user in
187       the application answers the question
188       <span class="quote-inline">
189       "Is this operation allowed here?"
190       </span>
191       </p>
192       <p>If you look more carefully at that question, you see it's got two important
193       parts: <em>operation</em> and <em>location</em> ('here').
194       <ul>
195         <li>Operations are 'view', 'edit', 'delete' and so on -- the usual suspects.</li>
196         <li>Each object <em>type</em> (comments, folders, users, etc.) can be controlled
197         individually.</li>
198         <li>Objects can also add their own specialized privileges to this list. (e.g. <a href="./#projects">Projects</a>
199         defines 'Can assign' for job objects.)</li>
200         <li>Folders define the permissions that are used for all objects in that folder.
201         They inherit permissions from their parent by default.</li>
202       </ul>
203       <p>You will, of course, still need a super-user who's rights can't be limited by
204       folder permissions. That's where user permissions come in. User permissions
205       override folder permissions by either always granting or always denying a
206       privilege. They also define privileges that are not folder-dependent (like login
207       or offline privileges).</p>
208       <ul>
209         <li>You can make your super-user by defining a user that grants all rights.</li>
210         <li>You can automatically ban a user by denying all rights.</li>
211         <li>'default' rights for registered and anonymous users are set using the same
212         system.</li>
213       </ul>
214       <p>You can also define user groups to apply folder permissions to lists of users.
215       That way, you say that your folder allows certain privileges for the group 'Editors'
216       and others for the group 'Moderators'. You can control who gets to do what by
217       changing membership in those groups.</p>
218       <h3 id="database">Database</h3>
219       <p>Dynamic websites are built with databases: static content is so 90's. MySQL
220       has a lot of name recognition and the WebCore has run on it since its earliest
221       days. But, this doesn't mean that it can <em>only</em> run on MySQL.</p>
222       <p>All references to PHP's data functions are made through a database
223       abstraction layer. All SQL is produced by query objects which map your requests
224       onto the underlying database. When you work with a WebCore application, you
225       rarely, if ever, have to write even a snippet of SQL. This centralization makes
226       your application much more mobile and flexible. If you want to try out
227       PostGreSQL, you don't have to modify a thing: just switch your database type.</p>
228       <p>With the WebCore, you don't set up SQL and execute loops and call database-dependent
229       functions. You work only with objects and list of objects returned by queries.</p>
230       <h3 id="storage">Storage</h3>
231       <p>The <a href="#database">database</a> section shows how your application <em>reads</em>
232       data without you writing any SQL. But, your application defines objects that
233       need to <em>store</em> data.</p>
234       <p>There's another abstract layer here that makes creating and updating objects
235       a piece of cake. If you define or extend objects, you just give the name of the
236       field, its type and its value, and the WebCore takes care of marshalling and
237       validating it into the database.</p>
238       <p>Again, no more SQL for you. Just call 'store' and you're done.</p>
239       <h3><a id="trash_can"></a>Trash can</h3>
240       <p>To make sure that content is always findable and restorable, WebCore
241       applications can use a 'trash-can'. Users can delete objects and they'll
242       disappear from their interface, but users with 'view hidden' privileges can
243       still see them and restore them or purge them from the database for good.</p>
244       <ul>
245         <li>Insulate your users against lost data</li>
246         <li>Since nothing's ever deleted right away, an admin can recover data for a
247         user.</li>
248         <li>Objects can be explictly purged from the database. You can, of course, set
249         up your application to directly purge all objects, skipping the trash can
250         completely.</li>
251       </ul>
252       <p>Hidden objects also lets moderators or admins hide portions of the
253       application while it is under maintenance and smoothly show it again when its
254       ready. <a href="#drafts">Drafts</a> are implemented on top of this system.</p>
255       <h3 id="locations">Locations</h3>
256       <p>Once you've got a bunch of content on your site, you need to be careful: it
257       gets pretty fragile and you're not allowed to move it around too much. Links
258       will break and you'll have missing images and styles popping up in the most
259       unpleasant places.</p>
260       <p>The WebCore lets you define <em>locations</em>, which you use throughout your
261       code as aliases to resources you need. That way, you just update the alias and
262       move the files and your website keeps happily purring along. You can even move
263       stuff to other servers without updating any of your content.</p>
264       <p>A standard application defines areas for <a href="#icons">icons</a>, <a href="#skinning">styles</a>
265       and scripts. There are even some special ones that are object-dependent, like 'attachment'
266       and 'thumbnail'. You can add your own locations and reference them just like the
267       built-in ones.</p>
268       <p>See <a href="text_formatting.php#paths">paths</a> for more information on
269       referring to resources.</p>
270       <h3 id="forms">Forms</h3>
271       <p>If you've done any web development, you know that forms take up the lion's
272       share of your coding and testing time. You've got so much to consider: display,
273       validation, value-conversion, error-handling: the list goes on and on.</p>
274       <p>The WebCore defines an extensive forms library. Forms define a list of fields
275       and indicate how each field is loaded from and stored to the object it
276       represents. Form rendering is separated into another layer, so your application
277       can redefine the look of all forms from a central location.</p>
278       <p>Almost all conceivable control implementations are supported and tested: from
279       all of the standard text fields and drop-downs to truly elegant and simple
280       support for grouped controls like lists of radio buttons or checkboxes.</p>
281       <p>All you have to do for your form is:</p>
282       <ul>
283         <li>Decide which fields it has. You can set the name, type, required status,
284         description and much more.</li>
285         <li>Map values from your data representation (usually an object) to your fields.</li>
286         <li>Map values from the submitted form back to your data.</li>
287         <li>Draw the form with the WebCore's abstract rendering API.</li>
288         <li>Marshalling data from the request object into the right form is handled
289         automatically</li>
290       </ul>
291       <p>It's so much easier and better-looking to use a form object, you'll never
292       hand-code a form again.</p>
293       <h3 id="upload">Uploads</h3>
294       <p>Uploading is tightly integrated with the <a href="#forms">forms</a> library,
295       but it's so hard, it merits its own section. It's hard because of several
296       reasons.</p>
297       <ul>
298         <li>The WebCore shields you from varying browser uploading behavior.</li>
299         <li>PHP also behaves differently depending on the version.</li>
300         <li>You're moving files around on the server -- the WebCore takes care of error-handling
301         for you.</li>
302         <li>The WebCore integrates uploading into the forms library, offering only-upload-once
303         support, which transparently stores uploaded files even if the form didn't
304         validate, so users only have to upload once.</li>
305       </ul>
306       <p><a href="#attachments">Attachments</a> is built on top of this API and it
307       makes nice use of <a href="#icons">icons</a> to show users which kind of file
308       they've uploaded.</p>
309       <h3 id="publishing">Publishing</h3>
310       <p>Once your site is online and you've got users, you probably want to be able
311       to let them know when you've updated your site. This opens up a whole new can of
312       worms, though.</p>
313       <ul>
314         <li>Whom do you notify? You need a list of subscribers and they need to be able
315         to say when and what you send. Spam's a bit of a touchy subject these days.</li>
316         <li>When do you notify? What does it mean to update a site? There are changes
317         you probably don't want to notify subscribers of.</li>
318       </ul>
319       <p>Again, the earthli WebCore provides quite a bit of support in this department.
320       The notion of subscribers is pretty deeply rooted in the library and based on
321       the auditing system described in <a href="#history">history</a>.</p>
322       <p>When you make a change to a website object, you've got the option of
323       modifying the history action that gets created for that change: you can modify
324       the title (email subject) and decide whether messages even get sent at all.
325       Publishing scripts can be set up to troll the database at regular intervals,
326       sending out messages for unprocessed actions.</p>
327       <p>As a user, you've got a load of options to control how much you get and when.</p>
328       <ul>
329         <li>You can set your schedule (immediately, hourly, daily, etc.) and organize
330         your notifications to be grouped into bulk emails.</li>
331         <li>You can, of course, select HTML or plain text format.</li>
332         <li>From the content side, you can subscribe to entire folders or to individual
333         objects. You can even subscribe to a user so you're informed whenever that user
334         does something (our stalking feature).</li>
335       </ul>
336       <h3 id="sharing">Sharing</h3>
337       <p>Since WebCore applications are built on the same base, they can easily share
338       large parts of the database to integrate them even more tightly.</p>
339       <ul>
340         <li>Users are shared by default, allowing your users to browse multiple
341         applications on your site with a single login.</li>
342         <li>You can also elect to share user permissions, giving users the same non-content-specific
343         permissions in all applications.</li>
344         <li>Even tighter integration shares <em>folders</em>, giving all your
345         applications the same structure. Tighter still shares folder permissions too; if
346         users can create content in a folder in one application, they can do so in all
347         the others. Administer all of your applications at once!</li>
348         <li>Global resources like themes and icons are also shared, by default.</li>
349       </ul>
350       <h3 id="customizing">Customization</h3>
351       <p class="quote-block">How do you deploy one of these applications to your own
352       website?</p>
353       <p>The WebCore automatically searches for configuration files in a 'plugins'
354       folder outside of the WebCore code folder. You can grab the default
355       initialization files, customize them and save them here. There are a lot of
356       options to help you get the application seamlessly integrated into your website
357       (you can even make your own <a href="#skinning">skin</a>).</p>
358       <p>On top of that, some applications, like <a href="./#projects">Projects</a>,
359       let you customize right from a web interface.</p>
360       <p class="quote-block">The WebCore is a development platform. How do you develop
361       in it?</p>
362       <p>So you want to customize an existing application: add a field to an object or
363       just change the way a list looks. All objects: data objects, lists, renderers,
364       mailers etc. are created centrally. If you want the WebCore to create a
365       different object for a particular type, say 'Comment renderer', you just
366       register your own class name and file location and the application creates and
367       uses that one instead.</p>
368       <p>All you do is make sure that your object supports the right interface (which
369       you can easily do by inheriting from the class you're replacing) and it will
370       integrate seamlessly. The objects used in the WebCore and its applications are
371       extensively <a href="documentation.php">documented</a>.</p>
372       <p>Existing WebCore applications use the same exact mechanism to 'customize' a
373       default application, so you can develop your own applications in the same way.
374       All modifications, from the smallest tweaks to the biggest overhauls, are
375       supported with the same approach.</p>
376       <p>Store your personal class definitions in the 'plugins' folder and you won't
377       overwrite anything when you upgrade the WebCore or the base application files.</p>
378       <h2>Making it look good</h2>
379       <h3 id="skinning">Skinning (Themes)</h3>
380       <p>All earthli WebCore template pages are defined using a strict set of CSS
381       styles, which are easy to override to provide your own color and style for your
382       application. You can make a bunch of them and let users pick the one they want
383       to use. There are several to get you started in the default package.</p>
384       <p>You can even redefine the header/footer layout by defining your own template
385       and placing specially-named elements in your layout so the WebCore can put the
386       page together the way you want it. Tell your style to use your template instead
387       of the default one and you're all set. This is perfect for adapting a WebCore
388       application to an existing web-site's style. There are a couple of layouters
389       included in your basic package too.</p>
390       <p>If you want to go further and change the layout of the <em>content</em> of
391       pages, like the way a list is displayed or the information displayed with an
392       object, you'll have to head on over to <a href="#customizing">customization</a>.</p>
393       <h3 id="munger">Text formatting</h3>
394       <p>The WebCore provides a powerful formatting language that looks like HTML, but <em>isn't</em>.
395       The formatting tags and attributes mirror HTML for familiarity, but are actually
396       transformed to the target content by the <em>munger</em> (named after the <a href="http://developer.apple.com/documentation/mac/Text/Text-329.html">Apple
397       toolbox function</a>). This HTML-independent language can just as well be
398       transformed to other formats as well. A Plain text formatter is used to generate
399       nicely-formatted emails.</p>
400       <p>Treating all user-entered text in this way has a lot of benefits.</p>
401       <ul>
402         <li>It guarantees compliant HTML, so your pages don't get bent out of shape by
403         invalid user content.</li>
404         <li>In fact, the forms library integrates a validator that keeps users from even <em>entering</em>
405         invalid content. It reports all errors with line and character position to help
406         them pinpoint their errors.</li>
407         <li>It prevents users from deliberately entering malicious HTML, like JavaScript
408         that loops endlessly or pops up other windows.</li>
409         <li>Lines that should be single-line (like titles) simply don't generate block
410         content and the validator flags non-single-line tags like lists.</li>
411         <li>As mentioned above, it's much easier to export other formats.</li>
412       </ul>
413       <p>To see what the tag format looks like, check out the <a href="text_formatting.php">text
414       formatting manual</a>.</p>
415       <h3 id="rendering">Rendering</h3>
416       <p>The earthli WebCore provides a lot of display classes to render your
417       application objects into a page. There are trees, grids, calendars, toolbars and
418       more.</p>
419       <ul>
420         <li>Grids work directly with <a href="#database">queries</a>, displaying the
421         desired rows and columns and paginating automatically for large lists.</li>
422         <li>Toolbars, or <em>buttons</em>, are login-sensitive, automatically showing
423         only buttons for users the logged-in user is allowed to do.</li>
424         <li>Trees render as DHTML or static, depending on the <a href="#browser">browser</a>.</li>
425         <li>Print-preview pages are automatically generated. There are even print
426         options that are specific to the type of object being printed (<a href="./#projects">Projects</a>
427         makes heavy use of this to make very flexible changelists).</li>
428       </ul>
429       <p>Every object also has an individual renderer, which shows all information for
430       that object. These renderers are used everywhere when showing objects, so no
431       more hunting through dozens of web pages with search/replace to get everything
432       up-to-date.</p>
433       <p>This is very cool because the object's home page uses the HTML output to show
434       the object as HTML, print-preview usually uses the HTML renderer too and emails
435       use the HTML or plain text rendering to show the object. And, as you'll see in <a href="#customizing">customization</a>,
436       you can hook in your own renderer for an object and the WebCore will
437       automatically use your renderer everywhere.</p>
438       <h3 id="browser">Browser</h3>
439       <p>Most websites have at least a feature or two that doesn't work on all
440       browsers. For these things, you'd like to know who's asking for a page and send
441       back the best possible version for it.</p>
442       <p>The WebCore's browser detection is a <a href="../browser_detector/">home-grown
443       algorithm</a> and lets you work with <em>capabilities</em> instead of browser
444       types. You don't need to know which browsers support which features, you just
445       ask if a feature is supported and the WebCore takes care of the rest.</p>
446       <p>So it's simple for your pages to ask if a browser handles DHTML. The WebCore
447       takes care of figuring out which browser you're actually using (and the <a href="../browser_detector/">algorithm</a>
448       really is quite good at ignoring spoofing) and knowing which browsers can do
449       what.</p>
450       <h3 id="imaging">Images</h3>
451       <p>A lot of websites post pictures in all sorts of formats. PHP can read the
452       files, figure out how big they are, even resize and reformat them. The WebCore
453       makes all of this functionality accessible and transparent with an image object.
454       You can use it to generate thumbnails of files (JPG or PNG) you've uploaded (like the
455       <a href="#attachments">attachments</a> do), so you don't have that 1280x1024 game screenshot in the middle
456       of your news page. The WebCore applications use the image library to seamlessly
457       offer robust attachments; Albums uses it to make uploading pictures a snap.</p>
458       <p>WebCore images can also automatically extract EXIF information, so all of the
459       information stored by your digital camera doesn't go lost when you add a picture
460       to your site. The WebCore even extracts some EXIF information on older versions
461       of PHP that don't have native EXIF support.</p>
462       <h3 id="icons">Icons and Avatars</h3>
463       <p>You're probably thinking "icons ... big deal".</p>
464       <p>Take a look at any desktop application; there are icons everywhere. You want
465       to make sure you can use icons for labels, buttons and just about everywhere.
466       You don't really want to refer to a specific image file; what if you want to
467       change it at some point?</p>
468       <p>The WebCore defines 'sets' of icons, which can be coordinated with <a href="#skinning">themes</a>
469       to provide a consistent look to your application. You can use <a href="text_formatting.php#paths">paths</a>
470       to refer to these icon resources and make sure you get the right one.</p>
471       <p>The WebCore comes with two sets of icons: a set of GIFs and a set of PNGs.
472       You can add your own to these sets or make a whole new one. There is a whole
473       framework for adding new avatar icons via browser and objects like folders and
474       users have a predefined field for their icon.</p>
475       <h3 id="printing">Printing</h3>
476       <p>As mentioned in <a href="#skinning">skinning</a>, earthli templates use strict CSS for all
477       rendering and display. That makes printing a snap and all renderers and objects are
478       "print-aware" and optimize their rendering for print formats. Print lists or items
479       or just a single one. Making your own objects print nicely is a breeze using the
480       library support.</p>
481       <h3 id="rss">RSS</h3>
482       <p>In addition to <a href="#publishing">publishing</a> by email, earthli applications
483       can be published as RSS feeds. Folder and application home pages have default feeds which
484       are recognized by most modern browsers (shows up as a blue RSS icon in the address bar).
485       Making new ones is easy, as there are base classes for rendering the feed itself and for
486       rendering WebCore objects in a feed. The default implementation simply uses the existing
487       HTML renderers, so any object you can display in a page can be published in an RSS feed
488       instantly. All earthli applications have excellent-looking RSS feeds without any extra
489       work whatsoever.</p>
490       <h3 id="archives">Archives</h3>
491       <p>It's likely that an attachment or an upload is a zip file. The WebCore provides
492       an easy-to-use callback-based API that makes displaying, extracting and working
493       with archives easy. Even if PHP doesn't have the necessary extraction functions,
494       the WebCore uses a third-party library to read the zip file. Your software doesn't
495       change depending on PHP version - it neither knows nor cares which version is used.</p>
496       <p><a href="#attachments">Attachments</a> use the zip libraries to display the list
497       of files inside an uploaded archive. Albums uses them to provide multi-image batch
498       uploading. The batch job extracts each file from the archive, generates a thumbnail
499       using the <a href="#imaging">image</a> library and create a picture entry in the
500       database.</p>
501       <h2>Where to?</h2>
502       <h3 id="future">The future</h3>
503       <p>A product like the earthli WebCore is never finished. There are always things
504       that could be done better or cool features that could be added. Here are some
505       that we're aware of:</p>
506       <ul>
507         <li>Multi-language support in all templates and text.</li>
508         <li>Add a web-interface for administration. Configuration is still done only
509         through config files written in PHP. A user-friendly admin interface to set the
510         myriad available parameters would be helpful.</li>
511         <li>Quizzes and voting supported in an application. As soon as you want quizzes,
512         you have to ask "who gets to make/edit quizzes? ... can users comment on quizzes?
513          " and you realize you need to define these in an application context too. Here's
514          where you can use <a href="#sharing">sharing</a> to tightly integrate with
515          another application.</li>
516         <li>Categories/keywords for objects for improved searching.</li>
517         <li>A moderation system for rating objects/comments/etc. A rudimentary vote
518         gathering system would be good for a start. Almost any application could use a "what
519         did you think about this item?" feature. Moderation-specific permissions could
520         be easily integrated.</li>
521         <li>User tracking -- who's online, how much you've been online, when you were
522         last online. What's new since you last browsed here. Also a pretty low-level
523         feature that any application should be able to snap in.</li>
524         <li>User permissions assignable by group. Groups assignable to groups.</li>
525       </ul>
526       <p>As you can see, once you start thinking about library vs. applications, you
527       can think of a lot of features that aren't really application-specific. Isn't it
528       much cooler to implement integrated moderation when you know it's going to be
529       used in <em>any</em> application instead of just one?</p>
530       <p>And remember, the earthli WebCore and applications are <a href="license.php">open
531       source</a>, so feel free to <a href="download.php">download</a> and pitch in!</p>
532     </div>
533     <div class="right-sidebar">
534       <h2>Your content</h2>
535       <ul>
536         <li><a href="#users">Users</a></li>
537         <li><a href="#folders">Folders</a></li>
538         <li><a href="#comments">Comments</a></li>
539         <li><a href="#attachments">Attachments</a></li>
540         <li><a href="#history">History</a></li>
541         <li><a href="#searching">Searching</a></li>
542         <li><a href="#lists">Lists</a></li>
543         <li><a href="#drafts">Drafts</a></li>
544       </ul>
545       <h2>Making it work</h2>
546       <ul>
547         <li><a href="#environment">Environment</a></li>
548         <li><a href="#security">Security</a></li>
549         <li><a href="#database">Database</a></li>
550         <li><a href="#storage">Storage</a></li>
551         <li><a href="#trash_can">Trash can</a></li>
552         <li><a href="#locations">Locations</a></li>
553         <li><a href="#forms">Forms</a></li>
554         <li><a href="#upload">Uploads</a></li>
555         <li><a href="#publishing">Publishing</a></li>
556         <li><a href="#sharing">Sharing</a></li>
557         <li><a href="#customizing">Customization</a></li>
558       </ul>
559       <h2>Making it look good</h2>
560       <ul>
561         <li><a href="#skinning">Skinning</a></li>
562         <li><a href="#munger">Text formatting</a></li>
563         <li><a href="#rendering">Rendering</a></li>
564         <li><a href="#browser">Browser</a></li>
565         <li><a href="#imaging">Images</a></li>
566         <li><a href="#icons">Icons and Avatars</a></li>
567         <li><a href="#printing">Printing</a></li>
568         <li><a href="#rss">RSS</a></li>
569         <li><a href="#archives">Archives</a></li>
570       </ul>
571       <h2>Where to?</h2>
572       <ul>
573         <li><a href="#future">The future</a></li>
574       </ul>
575     </div>
576   </div>
577 </div>
578 <?php $Page->finish_display (); ?>
579