Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - CMS and E-Commerce

830 Articles
article-image-dynamic-theming-drupal-6-part-1
Packt
24 Oct 2009
9 min read
Save for later

Dynamic Theming in Drupal 6 - Part 1

Packt
24 Oct 2009
9 min read
Using Multiple Templates Most advanced sites built today employ multiple page templates. In this section, we will look at the most common scenarios and how to address them with a PHPTemplate theme. While there are many good reasons for running multiple page templates, you should not create additional templates solely for the purpose of disabling regions to hide blocks. While the approach will work, it will result in a performance hit for the site, as the system will still produce the blocks, only to then wind up not displaying them for the pages. The better practice is to control your block visibility. Using a Separate Admin Theme With the arrival of Drupal 5, one of the most common Drupal user requests was satisfied; that is, the ability to easily designate a separate admin theme. In Drupal, designating a separate theme for your admin interface remains a simple matter that you can handle directly from within the admin system. To designate a separate theme for your admin section, follow these steps: Log in and access your site's admin system. Go to Administer | Site configuration | Administration theme. Select the theme you desire from the drop-down box listing all the installed themes. Click Save configuration, and your selected theme should appear immediately. Multiple Page or Section Templates In contrast to the complete ease of setting up a separate administration theme is the comparative difficulty of setting up multiple templates for different pages or sections. The bad news is that there is no admin system shortcut—you must manually create the various templates and customize them to suit your needs. The good news is that creating and implementing additional templates is not difficult and it is possible to attain a high degree of granularity with the techniques described below. Indeed, should you be so inclined, you could literally define a distinct template for each individual page of your site. Drupal employs an order of precedence based on a naming convention (or "suggestions" as they are now being called on the Drupal site). You can unlock the granularity of the system through proper application of the naming convention. It is possible, for example, to associate templates with every element on the path, or with specific users, or with a particular functionality—all through the simple process of creating a new template and naming it appropriately. The system will search for alternative templates, preferring the specific to the general, and failing to find a more specific template, will apply the default page.tpl.php. Consider the following example of the order of precedence and the naming convention in action. The custom templates above could be used to override the default page.tpl.php and theme either an entire node (page-node.tpl.php), or simply the node with an ID of 1 (page-node-1.tpl.php),or the node in edit mode (page-node-edit.tpl.php), depending on the name given the template. In the example above, the page-node templates would be applied to the node in full page view. In contrast, should you wish to theme the node in its entirety, you would need to intercept and override the default node.tpl.php. The fundamental methodology of the system is to use the first template file it finds and ignore other, more general templates (if any). This basic principle, combined with proper naming of the templates, gives you control over the template used in various situations. The default suggestions provided by the Drupal system should be sufficient for the vast majority of theme developers. However, if you find that you need additional suggestions beyond those provided by the system, it is possible to extend your site and add new suggestions. See http://drupal.org/node/223440 for a discussion of this advanced Drupal theming technique. Let's take a series of four examples to show how this feature can be used to provide solutions to common problems: Create a unique homepage template. Use a different template for a group of pages. Assign a specific template to a specific page. Designate a specific template for a specific user. Create a Unique Homepage Template Let's assume that you wish to set up a unique template for the homepage of a site. Employing separate templates for the homepage and the interior pages is one of the most common requests web developers hear. With Drupal, you can, without having to create a new template, achieve some variety within a theme by controlling the visibility of blocks on the homepage. If that simple technique does not give you enough flexibility, you will need to consider using a dedicated template that is purpose-built for your homepage content. The easiest way to set up a distinct front page template is to copy the existing page.tpl.php file, rename it, and make your changes to the new file. Alternatively, you can create a new file from scratch. In either situation, your front-page-specific template must be named page-front.tpl.php. The system will automatically display your new file for the site's homepage, and use the default page.tpl.php for the rest of the site. Note that page-front.tpl.php is whatever page you specify as the site's front page via the site configuration settings. To override the default homepage setting visit Administer | Site configuration | Site information, then enter the URL you desire into the field labeled Default home page. Use a Different Template for a Group of Pages Next, let's associate a template with a group of pages. You can provide a template to be used by any distinct group of pages, using as your guide the path for the pages. For example, to theme all the user pages you would create the template page-user.tpl.php. To theme according to the type of content, you can associate your page template with a specific node, for example, all blog entry pages can be controlled by the filepage-blog-tpl.php. The table below presents a list of suggestions you can employ to theme various pages associated with the default functionalities in the Drupal system. Suggestion Affected Page page-user.tpl.php user pages page-blog.tpl.php blog pages (but not the individual node pages) page-forum.tpl.php forum pages (but not the individual node pages) page-book.tpl.php book pages (but not the individual node pages) page-contact.tpl.php contact form (but not the form content)   Assign a Specific Template to a Specific Page Taking this to its extreme, you can associate a specific template with a specific page. By way of example, assume we wish to provide a unique template for a specific content item. Let's assume our example page is located at http://www.demosite.com/node/2/edit. The path of this specific page gives you a number of options. We could theme this page with any of the following templates (in addition to the default page.tpl.php): page-node.tpl.php page-node-2.tpl.php page-node-edit.tpl.php A Note on Templates and URLsDrupal bases the template order of precedence on the default path generated by the system. If the site is using a module like pathauto, which alters the path that appears to site visitors, remember that your templates will still be displayed based on the original paths. The exception here being page-front.tpl.php, which will be applied to whatever page you specify as the site's front page via the site configuration settings (Administer | Site configuration| Site information). Designate a Specific Template for a Specific User Assume that you want to add a personalized theme for the user with the ID of 1(the Drupal equivalent of a Super Administrator). To do this, copy the existing page.tpl.php file, rename it to reflect its association with the specific user, and make any changes to the new file. To associate the new template file with the user, name the file: page-user-1.tpl. Now, when user 1 logs into the site, they will be presented with this template. Only user 1 will see this template and only when he or she is logged in and visiting the account page. The official Drupal site includes a collection of snippets relating to the creation of custom templates for user profile pages. The discussion is instructive and worth review, though you should always be a bit cautious with user-submitted code snippets as they are not official releases from the Drupal Association. See, http://drupal.org/node/35728 Dynamically Theming Page Elements In addition to being able to style particular pages or groups of pages, Drupal and PHPTemplate make it possible to provide specific styling for different page elements. Associating Elements with the Front Page Drupal provides $is_front as a means of determining whether the page currently displayed is the front page. $is_front is set to true if Drupal is rendering the front page; otherwise it is set to false. We can use $is_front in our page.tpl.php file to help toggle display of items we want to associate with the front page. To display an element on only the front page, make it conditional on the state of $is_front. For example, to display the site mission on only the front page of the site, wrap $mission (in your page.tpl.php file) as follows: <?php if ($is_front): ?> <div id="mission"> <?php print $mission; ?> </div><?php endif; ?> To set up an alternative condition, so that one element will appear on the front page but a different element will appear on other pages, modify the statement like this: <?php if ($is_front): ?> //whatever you want to display on front page<?php else: ?> //what is displayed when not on the front page<?php endif; ?> $is_front is one of the default baseline variables available to all templates.
Read more
  • 0
  • 0
  • 2952

article-image-miro-interview-nicholas-reville
Packt
24 Oct 2009
6 min read
Save for later

Miro: An Interview with Nicholas Reville

Packt
24 Oct 2009
6 min read
Kushal Sharma: What is the vision behind Miro? Nicholas Reville: There's an opportunity to build a new, open mass medium of online television. We're developing the Miro Internet TV platform so that watching Internet video channels will be as easy as watching TV and broadcasting a channel will be open to everyone. Unlike traditional TV, everyone will have a voice. KS: Does PCF finance the entire project or do you have any other contributors? NR: We have tons of help from volunteers – translating the software, coding, testing, and providing user support. We would not be able to do nearly enough without our community. KS: Are the developers full-time PCF employees or is it similar to other Open Source projects where people voluntarily contribute to the community in their spare-time? NR: We have 6 full-time developers and also volunteers. We're a hybrid model, like Mozilla. KS: Please highlight the most crucial features of Miro, and the idea behind having those features as part of this application. NR: The most crucial feature of Miro is the ability to download and play video RSS feeds. It's a truly open way to distribute video online. Using RSS means that creators can publish with any company they want and users can bring together video from multiple sources into one application. KS: How many languages is Miro translated into? NR: Miro is at least partially translated into more than 40 languages, but we always need helping revising and improving the translations. KS: How is Miro different from other players from the technological perspective? NR: Above all, Miro is open-source. That means that anyone can work on the code, improve, and customize it. Beyond this, Miro is unique in a number of ways. It runs on Mac, Windows, and Linux. It can play almost any video format. And it has more HD content available than any other Internet TV application. KS: Are the Torrent download capabilities as well developed as any other standalone Bit Torrent Client? Please tell us something more about it's download capabilities, the share ratio, configurable upload limits while downloading the torrents etc. compared to other software? NR: Our current version of Miro keeps the BitTorrent capabilities very simple and doesn't provide many options. We think that most users don't even notice when they are downloading a torrent feed, however, we want to expand our options and features for power users in future versions – expect much more bit torrent control in 3 months or so. KS: What type of support do you have for Miro? NR: Most of our support is provided user-to-user in the discussion forums – they are very useful, actually. In addition, because we are an open project, anyone can file a bug or even fix a bug. In the long-term this means we will have a more stable user experience than closed competitors. KS: With a host of TV channels and video content going online, viewers could really use a common solution for all their media needs rather than keeping tabs on multiple sources. How do you see Miro being instrumental in providing this? NR: We think that an open platform for video is the only way to create a unified experience for video. Miro is the only really open Internet video solution right now and we think we have a crucial role to play in unifying Internet TV in an open way. KS: Does Miro download Internet TV programs and store it on the hard disk or does it stream live media like any other online service? NR: For now, Miro downloads everything that's watched. This is useful in two key ways: first, you can watch HD video with no skipping or buffering delays. Second, you can move those files onto any external device, with no DRM or other restrictions. In the future we may add a streaming option for some special cases, or the ability to start watching while the download is in progress. KS: Subscription-free content is a great gift that viewers get with Internet TV, however, bandwidth issues could be a concern for some users. What minimum bandwidth requirements would you suggest for satisfactory Internet TV performance on Miro? Furthermore, does Miro have an alternate solution for users having low Internet bandwidth? NR: Miro actually works better than most Internet video solutions for low bandwidth users. On a dial-up connection, streaming video solutions are unusable. Miro will download videos in those circumstances – it may happen slowly, but once you have the video you can watch it full speed with no skipping. KS: I remember a statement on the PCF site saying “Miro is designed to eliminate gatekeepers”. Could you please elaborate on this? NR: Miro works with open standards and is designed to be decentralized, like the web. That means that users can use Miro to connect directly to any video publisher – they don't need our permission and the files don't travel through our servers. Companies like Joost design their software to be highly centralized so that they can control both users and creators. It's time to leave that model behind. KS: So far, what has the response been like? NR: Response has been great. Last month alone, we had more than 200,000 downloads and we've been growing with each release. I expect that when we release version 1.0 in November we'll see even faster growth. KS: What are your future plans for Miro in terms of releases, updates, functionality, etc.? NR: After version 1.0 is released, we'll be making major changes to Miro to improve performance and add an extension system that will give people new ways of customizing the software to fit their needs. KS: To me, Miro’s agenda is a lot more than simply creating a good player. You’re attempting to change the face of Internet Video and the way it’s being hosted right now. How would you describe the future of Miro and Internet Video to our readers? NR: We want Miro to push online video in an open direction. We're hoping to build the best video experience possible, something that can be a true substitute for traditional television. But that doesn't mean we want to control the future of online video – we want other people to build open video distribution platforms as well. Openness is vital to the future of our mass media. KS: What other projects is the PCF involved in? NR: Right now, PCF is exclusively focused on making video more open and Miro is at the center of that. KS: Thank you for your time Nicholas, and good luck developing Miro!
Read more
  • 0
  • 0
  • 2638

article-image-jquery-table-manipulation-part-2
Packt
24 Oct 2009
6 min read
Save for later

jQuery Table Manipulation: Part 2

Packt
24 Oct 2009
6 min read
Advanced Row Striping Row striping can be as simple as two lines of code to alternate the background color: $(document).ready(function() {   $('table.sortable tbody tr:odd').addClass('odd');   $('table.sortable tbody tr:even').addClass('even'); }); If we declare background colors for the odd and even classes as follows, we can see the rows in alternating shades of gray: tr.even {   background-color: #eee; } tr.odd {   background-color: #ddd; } While this code works fine for simple table structures, if we introduce non‑standard rows into the table, such as sub-headings, the basic odd-even pattern no longer suffices. For example, suppose we have a table of news items grouped by year, with columns for date, headline, author, and topic. One way to express this information is to wrap each year's news items in a <tbody> element and use <th colspan="4"> for the subheading. Such a table's HTML (in abridged form) would look like this: <table class="striped"> <thead> <tr> <th>Date</th> <th>Headline</th> <th>Author</th> <th class="filter-column">Topic</th> </tr> </thead><tbody> <tr> <th colspan="4">2007</th> </tr> <tr> <td>Mar 11</td> <td>SXSWi jQuery Meetup</td> <td>John Resig</td> <td>conference</td> </tr> <tr> <td>Feb 28</td> <td>jQuery 1.1.2</td> <td>John Resig</td> <td>release</td> </tr> <tr> <td>Feb 21</td> <td>jQuery is OpenAjax Compliant</td> <td>John Resig</td> <td>standards</td> </tr> <tr> <td>Feb 20</td> <td>jQuery and Jack Slocum's Ext</td> <td>John Resig</td> <td>third-party</td> </tr></tbody><tbody> <tr> <th colspan="4">2006</th> </tr> <tr> <td>Dec 27</td> <td>The Path to 1.1</td> <td>John Resig</td> <td>source</td> </tr> <tr> <td>Dec 18</td> <td>Meet The People Behind jQuery</td> <td>John Resig</td> <td>announcement</td> </tr> <tr> <td>Dec 13</td> <td>Helping you understand jQuery</td> <td>John Resig</td> <td>tutorial</td> </tr></tbody><tbody> <tr> <th colspan="4">2005</th> </tr> <tr> <td>Dec 17</td> <td>JSON and RSS</td> <td>John Resig</td> <td>miscellaneous</td> </tr></tbody></table> With separate CSS styles applied to <th> elements within <thead> and <tbody>, a snippet of the table might look like this: To ensure that the alternating gray rows do not override the color of the subheading rows, we need to adjust the selector expression: $(document).ready(function() { $('table.striped tbody tr:not([th]):odd').addClass('odd'); $('table.striped tbody tr:not([th]):even').addClass('even');}); The added selector, :not([th]), removes any table row that contains a <th> from the matched set of elements. Now the table will look like this: Three-color Alternating Pattern There may be times when we want to apply more complex striping. For example, we can apply a pattern of three alternating row colors rather than just two. To do so, we first need to define another CSS rule for the third row. We'll also reuse the odd and even styles for the other two, but add more appropriate class names for them: tr.even,tr.first { background-color: #eee;}tr.odd,tr.second { background-color: #ddd;}tr.third { background-color: #ccc;} To apply this pattern, we start the same way as the previous example—by selecting all rows that are descendants of a <tbody>, but filtering out the rows that contain a <th<. This time, however, we attach the .each() method so that we can use its built-in index: $(document).ready(function() { $('table.striped tbody tr').not('[th]').each(function(index) { //Code to be applied to each element in the matched set. });}); To make use of the index, we can assign our three classes to a numeric key: 0, 1, or 2. We'll do this by creating an object, or map: $(document).ready(function() { var classNames = { 0: 'first', 1: 'second', 2: 'third' }; $('table.striped tbody tr').not('[th]').each(function(index) { // Code to be applied to each element in the matched set. });}); Finally, we need to add the class that corresponds to those three numbers, sequentially, and then repeat the sequence. The modulus operator, designated by a %, is especially convenient for such calculations. A modulus returns the remainder of one number divided by another. This modulus, or remainder value, will always range between 0 and one less than the dividend. Using 3 as an example, we can see this pattern: 3/3 = 1, remainder 0.4/3 = 1, remainder 1.5/3 = 1, remainder 2.6/3 = 2, remainder 0.7/3 = 2, remainder 1.8/3 = 3, remainder 2. And so on. Since we want the remainder range to be 0 – 2, we can use 3 as the divisor (second number) and the value of index as the dividend (first number). Now we simply put that calculation in square brackets after classNames to retrieve the corresponding class from the object variable as the .each() method steps through the matched set of rows: $(document).ready(function() { var classNames = { 0: 'first', 1: 'second', 2: 'third' }; $('table.striped tbody tr').not('[th]').each(function(index) { $(this).addClass(classNames[index % 3]); });}); With this code in place, we now have the table striped with three alternating background colors: We could of course extend this pattern to four, five, six, or more background colors by adding key-value pairs to the object variable and increasing the value of the divisor in classNames[index % n].
Read more
  • 0
  • 0
  • 4287

article-image-manipulating-jquery-tables
Packt
24 Oct 2009
20 min read
Save for later

Manipulating jQuery tables

Packt
24 Oct 2009
20 min read
In this article by Karl Swedberg and Jonathan Chaffer, we will use an online bookstore as our model website, but the techniques we cook up can be applied to a wide variety of other sites as well, from weblogs to portfolios, from market-facing business sites to corporate intranets. In this article, we will use jQuery to apply techniques for increasing the readability, usability, and visual appeal of tables, though we are not dealing with tables used for layout and design. In fact, as the web standards movement has become more pervasive in the last few years, table-based layout has increasingly been abandoned in favor of CSS‑based designs. Although tables were often employed as a somewhat necessary stopgap measure in the 1990s to create multi-column and other complex layouts, they were never intended to be used in that way, whereas CSS is a technology expressly created for presentation. But this is not the place for an extended discussion on the proper role of tables. Suffice it to say that in this article we will explore ways to display and interact with tables used as semantically marked up containers of tabular data. For a closer look at applying semantic, accessible HTML to tables, a good place to start is Roger Johansson's blog entry, Bring on the Tables at www.456bereastreet.com/archive/200410/bring_on_the_tables/. Some of the techniques we apply to tables in this article can be found in plug‑ins such as Christian Bach's Table Sorter. For more information, visit the jQuery Plug‑in Repository at http://jQuery.com/plugins. Sorting One of the most common tasks performed with tabular data is sorting. In a large table, being able to rearrange the information that we're looking for is invaluable. Unfortunately, this helpful operation is one of the trickiest to put into action. We can achieve the goal of sorting in two ways, namely Server-Side Sorting and JavaScript Sorting. Server-Side Sorting A common solution for data sorting is to perform it on the server side. Data in tables often comes from a database, which means that the code that pulls it out of the database can request it in a given sort order (using, for example, the SQL language's ORDER BY clause). If we have server-side code at our disposal, it is straightforward to begin with a reasonable default sort order. Sorting is most useful when the user can determine the sort order. A common idiom is to make the headers of sortable columns into links. These links can go to the current page, but with a query string appended indicating the column to sort by: <table id="my-data">   <tr>     <th class="name"><a href="index.php?sort=name">Name</a></th>     <th class="date"><a href="index.php?sort=date">Date</a></th>   </tr>   ... </table> The server can react to the query string parameter by returning the database contents in a different order. Preventing Page Refreshes This setup is simple, but requires a page refresh for each sort operation. As we have seen, jQuery allows us to eliminate such page refreshes by using AJAX methods. If we have the column headers set up as links as before, we can add jQuery code to change those links into AJAX requests: $(document).ready(function() {   $('#my-data .name a').click(function() {     $('#my-data').load('index.php?sort=name&type=ajax');     return false;   });   $('#my-data .date a').click(function() {     $('#my-data').load('index.php?sort=date&type=ajax');     return false;   }); }); Now when the anchors are clicked, jQuery sends an AJAX request to the server for the same page. We add an additional parameter to the query string so that the server can determine that an AJAX request is being made. The server code can be written to send back only the table itself, and not the surrounding page, when this parameter is present. This way we can take the response and insert it in place of the table. This is an example of progressiveenhancement. The page works perfectly well without any JavaScript at all, as the links for server-side sorting are still present. When JavaScript is present, however, the AJAX hijacks the page request and allows the sort to occur without a full page load. JavaScript Sorting There are times, though, when we either don't want to wait for server responses when sorting, or don't have a server-side scripting language available to us. A viable alternative in this case is to perform the sorting entirely on the browser using JavaScript client-side scripting. For example, suppose we have a table listing books, along with their authors, release dates, and prices: <table class="sortable">   <thead>     <tr>       <th></th>       <th>Title</th>       <th>Author(s)</th>       <th>Publish&nbsp;Date</th>       <th>Price</th>     </tr>   </thead>   <tbody>     <tr>       <td>         <img src="../covers/small/1847192386.png" width="49"              height="61" alt="Building Websites with                                                 Joomla! 1.5 Beta 1" />       </td>       <td>Building Websites with Joomla! 1.5 Beta 1</td>       <td>Hagen Graf</td>       <td>Feb 2007</td>       <td>$40.49</td>     </tr>     <tr>       <td><img src="../covers/small/1904811620.png" width="49"                height="61" alt="Learning Mambo: A Step-by-Step                Tutorial to Building Your Website" /></td>       <td>Learning Mambo: A Step-by-Step Tutorial to Building Your           Website</td>       <td>Douglas Paterson</td>       <td>Dec 2006</td>       <td>$40.49</td>     </tr>     ...   </tbody> </table> We'd like to turn the table headers into buttons that sort by their respective columns. Let us look into ways of doing this.   Row Grouping Tags Note our use of the <thead> and <tbody> tags to segment the data into row groupings. Many HTML authors omit these implied tags, but they can prove useful in supplying us with more convenient CSS selectors to use. For example, suppose we wish to apply typical even/odd row striping to this table, but only to the body of the table: $(document).ready(function() {   $('table.sortable tbody tr:odd').addClass('odd');   $('table.sortable tbody tr:even').addClass('even'); }); This will add alternating colors to the table, but leave the header untouched: Basic Alphabetical Sorting Now let's perform a sort on the Titlecolumn of the table. We'll need a class on the table header cell so that we can select it properly: <thead>   <tr>     <th></th>    <th class="sort-alpha">Title</th>     <th>Author(s)</th>     <th>Publish&nbsp;Date</th>     <th>Price</th>   </tr> </thead> To perform the actual sort, we can use JavaScript's built in .sort()method. It does an in‑place sort on an array, and can take a function as an argument. This function compares two items in the array and should return a positive or negative number depending on the result. Our initial sort routine looks like this: $(document).ready(function() {   $('table.sortable').each(function() {     var $table = $(this);     $('th', $table).each(function(column) {       if ($(this).is('.sort-alpha')) {         $(this).addClass('clickable').hover(function() {           $(this).addClass('hover');         }, function() {           $(this).removeClass('hover');         }).click(function() {           var rows = $table.find('tbody > tr').get();           rows.sort(function(a, b) {             var keyA = $(a).children('td').eq(column).text()                                                       .toUpperCase();             var keyB = $(b).children('td').eq(column).text()                                                       .toUpperCase();             if (keyA < keyB) return -1;             if (keyA > keyB) return 1;             return 0;           });           $.each(rows, function(index, row) {             $table.children('tbody').append(row);           });         });       }     });   }); }); The first thing to note is our use of the .each() method to make iteration explicit. Even though we could bind a click handler to all headers with the sort-alpha class just by calling $('table.sortable th.sort-alpha').click(), this wouldn't allow us to easily capture a crucial bit of information—the column index of the clicked header. Because .each() passes the iteration index into its callback function, we can use it to find the relevant cell in each row of the data later. Once we have found the header cell, we retrieve an array of all of the data rows. This is a great example of how .get()is useful in transforming a jQuery object into an array of DOM nodes; even though jQuery objects act like arrays in many respects, they don't have any of the native array methods available, such as .sort(). With .sort() at our disposal, the rest is fairly straightforward. The rows are sorted by comparing the textual contexts of the relevant table cell. We know which cell to look at because we captured the column index in the enclosing .each() call. We convert the text to uppercase because string comparisons in JavaScript are case-sensitive and we wish our sort to be case-insensitive. Finally, with the array sorted, we loop through the rows and reinsert them into the table. Since .append() does not clone nodes, this moves them rather than copying them. Our table is now sorted. This is an example of progressive enhancement's counterpart, gracefuldegradation. Unlike with the AJAX solution discussed earlier, we cannot make the sort work without JavaScript, as we are assuming the server has no scripting language available to it in this case. The JavaScript is required for the sort to work, so by adding the "clickable" class only through code, we make sure not to indicate with the interface that sorting is even possible unless the script can run. The page degrades into one that is still functional, albeit without sorting available. We have moved the actual rows around, hence our alternating row colors are now out of whack: We need to reapply the row colors after the sort is performed. We can do this by pulling the coloring code out into a function that we call when needed: $(document).ready(function() {   var alternateRowColors = function($table) {     $('tbody tr:odd', $table).removeClass('even').addClass('odd');     $('tbody tr:even', $table).removeClass('odd').addClass('even');   };     $('table.sortable').each(function() {     var $table = $(this);     alternateRowColors($table);     $('th', $table).each(function(column) {       if ($(this).is('.sort-alpha')) {         $(this).addClass('clickable').hover(function() {           $(this).addClass('hover');         }, function() {           $(this).removeClass('hover');         }).click(function() {           var rows = $table.find('tbody > tr').get();           rows.sort(function(a, b) {             var keyA = $(a).children('td').eq(column).text()                                                       .toUpperCase();             var keyB = $(b).children('td').eq(column).text()                                                       .toUpperCase();             if (keyA < keyB) return -1;             if (keyA > keyB) return 1;             return 0;           });           $.each(rows, function(index, row) {             $table.children('tbody').append(row);           });           alternateRowColors($table);         });       }     });   }); }); This corrects the row coloring after the fact, fixing our issue:   The Power of Plug-ins The alternateRowColors()function that we wrote is a perfect candidate to become a jQuery plug-in. In fact, any operation that we wish to apply to a set of DOM elements can easily be expressed as a plug-in. In this case, we only need to modify our existing function a little bit: jQuery.fn.alternateRowColors = function() {   $('tbody tr:odd', this).removeClass('even').addClass('odd');   $('tbody tr:even', this).removeClass('odd').addClass('even');   return this; }; We have made three important changes to the function. It is defined as a new property of jQuery.fn rather than as a standalone function. This registers the function as a plug-in method. We use the keyword this as a replacement for our $table parameter. Within a plug-in method, thisrefers to the jQuery object that is being acted upon. Finally, we return this at the end of the function. The return value makes our new method chainable. More information on writing jQuery plug-ins can be found in Chapter 10 of our book Learning jQuery. There we will discuss making a plug-in ready for public consumption, as opposed to the small example here that is only to be used by our own code. With our new plug-in defined, we can call $table.alternateRowColors(), which is a more natural jQuery syntax, intead of alternateRowColors($table). Performance Concerns Our code works, but is quite slow. The culprit is the comparator function, which is performing a fair amount of work. This comparator will be called many times during the course of a sort, which means that every extra moment it spends on processing will be magnified. The actual sort algorithm used by JavaScript is not defined by the standard. It may be a simple sort like a bubble sort (worst case of Θ(n2) in computational complexity terms) or a more sophisticated approach like quick sort (which is Θ(n log n) on average). In either case doubling the number of items increases the number of times the comparator function is called by more than double. The remedy for our slow comparator is to pre-compute the keys for the comparison. We begin with the slow sort function: rows.sort(function(a, b) {   keyA = $(a).children('td').eq(column).text().toUpperCase();   keyB = $(b).children('td').eq(column).text().toUpperCase();   if (keyA < keyB) return -1;   if (keyA > keyB) return 1;   return 0; }); $.each(rows, function(index, row) {   $table.children('tbody').append(row); }); We can pull out the key computation and do that in a separate loop: $.each(rows, function(index, row) {   row.sortKey = $(row).children('td').eq(column).text().toUpperCase(); }); rows.sort(function(a, b) {   if (a.sortKey < b.sortKey) return -1;   if (a.sortKey > b.sortKey) return 1;   return 0; }); $.each(rows, function(index, row) {   $table.children('tbody').append(row);   row.sortKey = null; }); In the new loop, we are doing all of the expensive work and storing the result in a new property. This kind of property, attached to a DOM element but not a normal DOM attribute, is called an expando.This is a convenient place to store the key since we need one per table row element. Now we can examine this attribute within the comparator function, and our sort is markedly faster.  We set the expando property to null after we're done with it to clean up after ourselves. This is not necessary in this case, but is a good habit to establish because expando properties left lying around can be the cause of memory leaks. For more information, see Appendix C.   Finessing the Sort Keys Now we want to apply the same kind of sorting behavior to the Author(s) column of our table. By adding the sort-alpha class to its table header cell, the Author(s)column can be sorted with our existing code. But ideally authors should be sorted by last name, not first. Since some books have multiple authors, and some authors have middle names or initials listed, we need outside guidance to determine what part of the text to use as our sort key. We can supply this guidance by wrapping the relevant part of the cell in a tag: <tr>   <td>     <img src="../covers/small/1847192386.png" width="49" height="61"             alt="Building Websites with Joomla! 1.5 Beta 1" /></td>   <td>Building Websites with Joomla! 1.5 Beta 1</td>   <td>Hagen <span class="sort-key">Graf</span></td>   <td>Feb 2007</td>   <td>$40.49</td> </tr> <tr>   <td>     <img src="../covers/small/1904811620.png" width="49" height="61"          alt="Learning Mambo: A Step-by-Step Tutorial to Building                                                 Your Website" /></td>   <td>     Learning Mambo: A Step-by-Step Tutorial to Building Your Website   </td>   <td>Douglas <span class="sort-key">Paterson</span></td>   <td>Dec 2006</td>   <td>$40.49</td> </tr> <tr>   <td>     <img src="../covers/small/1904811299.png" width="49" height="61"                   alt="Moodle E-Learning Course Development" /></td>   <td>Moodle E-Learning Course Development</td>   <td>William <span class="sort-key">Rice</span></td>   <td>May 2006</td>   <td>$35.99</td> </tr> Now we have to modify our sorting code to take this tag into account, without disturbing the existing behavior for the Titlecolumn, which is working well. By prepending the marked sort key to the key we have previously calculated, we can sort first on the last name if it is called out, but on the whole string as a fallback: $.each(rows, function(index, row) {   var $cell = $(row).children('td').eq(column);   row.sortKey = $cell.find('.sort-key').text().toUpperCase()                                   + ' ' + $cell.text().toUpperCase(); }); Sorting by the Author(s)column now uses the last name:     If two last names are identical, the sort uses the entire string as a tiebreaker for positioning.
Read more
  • 0
  • 0
  • 19215

article-image-development-login-management-module-and-comment-management-module
Packt
24 Oct 2009
12 min read
Save for later

Development of Login Management Module and Comment Management Module

Packt
24 Oct 2009
12 min read
Lets get started right away. Developing the Login Management Module Even though Login and session handling are separate functionalities from User management, they depend on the same table—user. Also, the functionalities are more alike than different. Hence, instead of creating a new Controller, we will be using the UserController itself as the Controller for the Login module. Keeping this point in mind, let us look at the steps involved in developing the Login Management, which are: Creating the Login page Implementing the Authentication Method Setting up the Session Applying Authorization Leaving aside the first step, all other steps mainly focus on the Controller. Here we go. Creating the Login Page We need a login page with text boxes for user name and password in which users can put their credentials and submit to the login authenticator (fancy name for the action method that will contain the logic to authenticate the user). That's what we are going to create now. The convention for any website is to show the login page when the user enters the URL without any specific page in mind. RoR also follows this convention. For example, if you enter the URL as http://localhost:3000/user, it displays the list of users. The reason is that the index action method of the UserController class calls the list method whenever the aforementioned URL is used. From this, we can understand two things—first, the default action method is index, and second, the first page to be shown is changeable if we change the index method. What we need is to show the login page whenever a user enters the URLhttp://localhost:3000/user. So let's change the index method. Open theuser_controller.rb file from the app/views/user folder and remove all the statements from the body of the index method so that it looks like as follows: def indexend Next, let us create an index.rhtml file, which will be shown when the index method is called. This file will be the login page. In the app/views/user folder, create an index.rhtml file. It will be as follows <%= form_tag :action=> 'authenticate'%><table ><tr align="center" class="tablebody"><td>User name:</td><td><%= text_field("user", "user_name",:size=>"15" ) %></td></tr><tr align="center" class="tablebody"><td>Password:</td><td><%= password_field("user","password",:size=>"17" ) %></td></tr><tr align="center" class="tablebody"><td></td><td><input type="submit" value=" LOGIN " /></td></tr></table> It uses two new form helpers—text_field and password_field. The text_field creates a text field with the name passed as the parameter, and the password_field creates a password field again with the name passed as the parameter. We have passed the authenticate method as the action parameter so that the form is submitted to the authenticate method. That completes the login page creation. Next, we will work on the authenticate method. Implementing the Authenticate method Implementing the Authenticate method Authenticating a user essentially means checking whether the user name and password given by the user corresponds to the one in database or not. In our case, the user gives us the user name and password through the login page. What we will be doing is checking whether the user is in database and does the password that we got corresponds to the password stored in the database for the user? Here, we will be working on two levels: Model Controller We can put the data access part in the action method that being the Controller itself. But it will create problems in the future if we want to add something extra to the user name/password checking code. That's why we are going to put (or delegate) the data access part into Model. Model We will be modifying the User class by adding a method that will check whether the user name and password provided by the user is correct or not. The name of the method is login. It is as follows: def self.login(name,password)find(:first,:conditions => ["user_name = ? and password =?",name, password])end It is defined as a singleton method of the User class by using the self keyword. The singleton methods are special class-level methods. The conditions parameter of the find method takes an array of condition and the corresponding values. The find method generates an SQL statement from the passed parameters. Here, the find method finds the first record that matches the provided user_name and password. Now, let us create the method that the Controller will call to check the validity of the user. Let us name it check_login. The definition is as follows: def check_loginUser.login(self.user_name, self.password)end This function calls the login method. Now if you observe closely, check_login calls the login function. One more point to remember—if a method 'test' returns a value and you call 'test' from another method 'test1,' then you don't need to say 'return test' from within 'test1'.The value returned from 'test' will be returned by 'test1' implicitly. That completes the changes to be done at the Model level. Now let us see the changes at the Controller-level. Controller In the Controller for User—UserController—add a new method named authenticate. The method will first create a User object based on the user name and password. Then it will invoke check_login on the newly created User object. If check_login is successful, that is, it does not return nil, then the user is redirected to the list view of Tales. Otherwise, the user is redirected to the login page itself. Here is what the method will look like: def authenticate@user = User.new(params[:user])valid_user = @user.check_loginif logged_in_userflash[:note]="Welcome "+logged_in_user.nameredirect_to(:controller=>'tale',:action => "list")elseflash[:notice] = "Invalid User/Password"redirect_to :action=> "index"endend The redirect_to method accepts two parameters—the name of the Controller and the method within the Controller. If the user is valid, then the list method of TaleController is called, or in other words, the user is redirected to the list of tales. Next, let us make it more robust by checking for the get method. If a user directly types a URL to an action, then the get method is received by the method. If any user does that, we want him/her to be redirected to the login page. To do this, we wrap up the user validation logic in an if/else block. The code will be the following: def authenticate if request.get?render :action=> 'index'else@user = User.new(params[:user])valid_user = @user.check_loginif valid_userflash[:note]="Welcome "+valid_user.user_nameredirect_to(:controller=>'tale',:action => 'list')else flash[:notice] = "Invalid User/Password"redirect_to :action=> 'index'endendend The get? method returns true if the URL has the GET method else it returns false. That completes the login authentication part. Next, let us set up the session. In Ruby, any method that returns a Boolean value—true or false—is suffixed with a question mark (?). The get method of the request object returns a boolean value. So it is suffixed with a question mark (?). Setting up the Session Once a user is authenticated, the next step is to set up the session to track the user. Session, by definition, is the conversation between the user and the server from the moment the user logs in to the moment the user logs out. A conversation is a pair of requests by the user and the response from the server. In RoR, the session can be tracked either by using cookies or the session object. The session is an object provided by RoR. The session object can hold objects where as cookies cannot. Therefore, we will be using the session object. The session object is a hash like structure, which can hold the key and the corresponding value. Setting up a session is as easy as providing a key to the session object and assigning it a value. The following code illustrates this aspect: def authenticateif request.get?render :action=> 'index'else@user = User.new(params[:user])valid_user = @user.check_loginif valid_usersession[:user_id]=valid_user.idflash[:note]="Welcome "+valid_user.user_nameredirect_to(:controller=>'tale',:action => 'list')elseflash[:notice] = "Invalid User/Password"redirect_to :action=> 'index'endendend That completes setting up the session part. That brings us to the last step—applying authorization. Applying Authorization Until now, we have authenticated the user and set up a session for him/her. However, we still haven't ensured that only the authenticated users can access the different functionalities of TaleWiki. This is where authorization comes into the picture. Authorization has two levels—coarse grained and fine grained. Coarse grained authorization looks at the whole picture whereas the fine grained authorization looks at the individual 'pixels' of the picture. Ensuring that only the authenticated users can get into TaleWiki is a part of coarse grained authorization while checking the privileges for each functionality comes under the fine grained authorization. In this article, we will be working with the coarse grained authorization. The best place to apply the coarse grained authorization is the Controller as it is the central point of data exchange. Just like other aspects, RoR provides a functionality to easily apply any kind of logic on the Controller as a whole in the form of filters. To jog your memory, a filter contains a set of statements that need to be executed before, after (or before and after) the methods within the Controllers are executed. Our problem is to check whether the user is authenticated or not, before any method in a Controller is executed. The solution to our problem is using a 'before filter'. But we have to apply authorization to all the Controllers. Hence, the filter should be callable from any of the Controller. If you look at the definition of a Controller, you can find such a place. Each Controller is inherited from the ApplicationController. Anything placed in ApplicationController will be callable from other Controllers. In other words, any method placed in ApplicationController becomes global to all the Controllers within your application. So, we will place the method containing the filter logic in ApplicationController. To check whether a user is authentic or not, the simplest way is to check whether a session exists for that person or not. If it exists, then we can continue with the normal execution. Let us name it check_authentic_user. The implementation will be as follows: def check_authentic_userunless session[:user_id]flash[:notice] = "Please log in"redirect_to(:controller => "user", :action =>"index")endend It checks for the user_id key in a session. If it is not present, the user is redirected to the login page. Place the code in the application.rb file as a method of ApplicationController. Next, let us use it as a filter. First, we will tell UserController to apply the filter for all the action methods except index and authenticate methods. Add the following statement to the UserController. It should be the first statement after the starting of the Controller class. class UserController < ApplicationControllerbefore_filter :check_authentic_user, :except =>[ :index, :authenticate ]::end Similarly, we will place the filter in other Controllers as well. However, in their case, there are no exceptions. So TaleController will have: class TaleController < ApplicationControllerbefore_filter :check_authentic_user::end GenreController and RoleController will be the same as TaleController. Thus, we have completed the 'applying authorization' part for the time being. Now, let's tie up one loose end—the problem of adding a new tale. Tying Up the Loose Ends When we developed the User management, the Tale management was affected as the tales table has a many-to-one relationship with the users table. Now we can solve the problem created by the foreign key reference. First, open the user.rb file and add the following statement indicating that it is at the 'one' end of the relationship: has_many :tale After addition of the statement, the class will look like the following: class User < ActiveRecord::Basevalidates_presence_of :user_name, :password, :first_name,:last_name, :age, :email, :country validates_uniqueness_of :user_namevalidates_numericality_of :age validates_format_of :email, :with => /A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})Z/ibelongs_to :rolehas_many :taledef check_loginUser.login(self.name, self.password)enddef self.login(name,password)find(:first,:conditions => ["user_name = ? and password=?",name, password])endend Next, add the following statement to the tale.rb file: belongs_to :user The file will look like as follows: class Tale < ActiveRecord::Basevalidates_presence_of :title, :body_text, :sourcebelongs_to:genrebelongs_to :userend Next, open the tale_controller.rb file. In the create method, we need to add the user's id to the tale's user id reference so that the referential integrity can be satisfied. For that, we will get the current user's id from the session and set it as the value of the user_id attribute of the tale object. The create method will look like as follows, after doing the changes: def create @tale = Tale.new(params[:tale])@tale.genre_id=params[:genre]@tale.user_id=session[:user_id]@tale.status="new" if @tale.saveflash[:notice] = 'Tale was successfully created.'redirect_to :action => 'list'elserender :action => 'new'endend That's it. The 'loose ends' related to the User management are tied up. Now let us move onto the Comment Management module.
Read more
  • 0
  • 0
  • 1544

article-image-customizing-default-theme-drupal
Packt
23 Oct 2009
3 min read
Save for later

Customizing the Default Theme in Drupal

Packt
23 Oct 2009
3 min read
Let's look at the default theme (garland) and customize it. We can customize the following features: Color scheme, either based on a color set, or by changing the individual colors If certain elements, such as the logo, are displayed The logo The favicon Back in the Themes section of the Administer area, there is a configure link next to each theme; if we click this we are taken to the theme's configuration page. Although Doug ideally wants a new theme that is unique to his website, he also wants to have a look at a few different options for the default theme. In particular, he wants to add his company's logo to the website and try a number of red color schemes as those are his corporate colors. Color Scheme The color scheme settings are quite intuitive and easy to change. We can either: Select a color set Change each color by entering the hexadecimal color codes (the # followed by 6 characters) Select the colors from the color wheel To change a color using the color wheel, we need to click on the color type (base color, link color, etc.) to select it and then chose the general color from the wheel and the shade of the color from the square within. When we change the colors or color set, the preview window below the settings automatically updates to reflect the color change. The following color sets are available: Blue Lagoon (the default set) Ash Aquamarine Belgian Chocolate Bluemarine Citrus Blast Cold Day Greenbeam Meditarrano Mercury Nocturnal Olivia Pink Plastic Shiny Tomato Teal Top Custom Quite a number of these are red-based color schemes, let's look into them, they are: Belgian Chocolate Meditarrano Shiny Tomato Belgian Chocolate Color Set The Belgian Chocolate color set uses a dark red header with a gradient starting with black flowing into a dark red color. The page's background is a cream color and the main content area has a white background as illustrated by the picture below: Mediterrano Color Set The Mediterrano color set uses a lighter red color where the gradient in the header starts with a light orange color which then flows into a light red color. Similar to the Belgian Chocolate color scheme the background is cream in color with a white background for the content area. Shiny Tomato Color Set The Shiny Tomato color set has a gradient header that starts with deep red and flows into a bright red color. The page's background is light grey with white background for the main content area, reflecting a professional image. The Shiny Tomato color set uses a red scheme which is in Doug's logo and he feels this set is the most professional of the three and wants us to use that.  
Read more
  • 0
  • 0
  • 1733
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-planning-extensions-typo3
Packt
23 Oct 2009
8 min read
Save for later

Planning Extensions in TYPO3

Packt
23 Oct 2009
8 min read
Why is Planning Important? Most open source developers see planning as a boring task. Why plan if one can just go and code? The answer is as simple as the question: The "Go and code" approach does not let us create truly optimal code. Portions of code have to be changed while other portions are written. They often lead to redundant code or uninitialized variables, partially covered conditions, and wrong return results. Code gets a "do not touch" reputation because changing anything renders the whole project unstable. Often the code works, but the project is more a failure than a success because it cannot be extended or re-used. Another reason for planning is the ease of bug fixing and the costs associated with it. Open source developers often do not think about it until they start selling their services or work to commercial companies. As shown by recent studies, the cost of problem fixing grows rapidly toward the end of the project. The cost is minimal when development has not started yet, and the person in charge just collects requirements. When requirements are collected and a programmer (or a team of programmers) starts to think how to implement these requirements, a change of requirements, or fixing a problem in the requirements still does not cost much. But it may already be difficult for developers if they came to a certain implementation approach after reviewing requirements. Things become worse at the development stage. Imagine that the selected approach was wrong and it was uncovered close to the end of development. Lots of time is lost, and work may have to start from the beginning. Now imagine what happens if the project is released to the customer and the customer says that the outcome of the project does not work as expected (something was implemented differently (as compared to expectations), or something was not implemented at all). The cost of fixing is likely to be high and overshoot the budget. Next, imagine what would happen if problems occurred when a project went live. After reading the previous paragraph, some developers may ask how the situation applies to non-commercial development, as there is a false perception that there are no costs associated with it (at least, no direct costs). But, the costs exist! And often they are much more sensitive than financial costs. The cost in non-commercial development is reputation. If a developer's product does not work well or does not work at all or it has obvious flaws, the general opinion about the developer may become bad ("cannot trust his code"). Developers will also have troubles improving because often they do not understand what has gone wrong. But the answer is near. Do not rush! Plan it well! You may even think of something about the future code, and then start coding only when the picture is clear. Planning is an important part of software development. While freelancers can usually divide their time freely between planning and implementation, many corporate developers often do not have such freedom. And even worse, many managers still do not see planning as a necessary step in software development. This situation is well explained in The parable of the two programmers, which readers of this book are encouraged to read in full. When it comes to TYPO3, planning is more important than an average application. TYPO3 is very complex, and its implementation is also complex. Without planning, programmers will most likely have to change their already written code to fix unforeseen problems therefore, good planning for TYPO3 extensions is extremely important. But let us move on and see how to plan an extension. How to Plan There are several stages in planning. Typically, each stage answers one or more important questions about development. TYPO3 developers should think about at least three stages: Gathering requirements Implementation planning Documentation planning Of course, each project is unique and has other stages. But these three stages generally exist in every project. Gathering Requirements The first thing that a developer needs to know is what his/her extension will do. While it sounds pretty obvious, not many extension authors know exactly what functionality the extension has in the end. It evolves over time, and often the initial idea is completely different from the final implementation. Predictably, neither the original nor the final is done well. In the other case, when extension features are collected, though planned and implemented according to plan, they usually fit well together. So, the very first thing to do when creating an extension is to find out what that extension should do. This is called gathering requirements. For non-commercial extensions, gathering requirements simply means writing down what each extension should do. For example, for a news extension, it may be: Show list of news sorted by date Show list of latest news Show news archive Show only a small amount of text in news list view As we have seen, gathering requirements looks easier than it actually is. The process, however, may become more complex when an extension is developed for an external customer. Alan Cooper, in his famous About Face book, shows how users, architects, and developers see the same product. From the user's perspective, it looks like a perfect circle. An architect sees something closer to an octagon. A developer creates something that looks like a polygon with many segments connected at different degrees. These differences always exist and each participating party is interested in minimizing them. A developer must not be afraid of asking questions. The cleaner picture he/she has, the better he/she will understand the customer's requirements. Implementation Planning When the requirements are gathered, it is necessary to think which blocks an extension will have. It may be blocks responsible for data fetching, presentation, conversion, and so on. In the case of TYPO3 extension implementation, planning should result in a list of Frontend (FE) plugins, Backend (BE) modules, and standalone classes. The purpose of each plug-in, module, and/or class must be clear. When thinking of FE plugins, caching issues must be taken into account. While most of the output can be cached to improve TYPO3 performance, forms processing should not be cached. Some extensions completely prevent caching of the page when processing forms. But there is a better approach, a separate FE plug-in from the non-cached output. BE modules must take into account the ease of use. Standard BE navigation is not very flexible, and this must be taken into account when planning BE modules. Certain functionalities can be moved to separate classes. This includes common functions and any public APIs that an extension provides to the other extensions. Hooks or "user functions" are usually placed in separate classes depending on the functional zone or hooked class. Documentation Planning A good extension always comes with documentation. Documentation should also be planned. Typically, manuals for extensions are created using standard templates, which have standard sections defined. While this simplifies documentation writing for extension developers, they still have to plan what they will put into these sections. TYPO3-Specific Planning There are several planning issues specific to TYPO3. Developers must take care of them before the actual development. Extension Keys Each extension must have a unique key. Extension keys can be alphanumeric and contain underscore characters. It may not start with a digit, the letter u, or the test_ prefix. However, not every combination of these symbols makes a good extension key. An extension key must be descriptive but not too long. Having personal or company prefixes is not forbidden but is not recommended. Underscores should be avoided. Abbreviations should be avoided as well, because they often do not make sense for other users. Examples of good extension keys are: news comments usertracker loginbox Examples of bad extension keys are: news_extension mycorp_ustr myverygoodextensionthatdoesalotofthings mvgetdalot john_ext div2007 Database Structure Most TYPO3 extensions use a database to load and/or store their own data. Changing the data structure during application development may seriously slow down development, or may even cause damage to data if some data is already entered into the system. Therefore, it is extremely important to think about an extension's data structure well in advance. Such thinking requires knowledge about how TYPO3 database tables are organized. Tables in TYPO3 database must have certain structures to be properly managed by TYPO3. If a table does not fulfill TYPO3 requirements, users may see error messages in the BE (especially in the Web | List module), and data may become corrupted. Every record in every TYPO3 table belongs to a certain page inside TYPO3. TYPO3 has a way to identify which page the record belongs to.
Read more
  • 0
  • 0
  • 1502

article-image-layouts-ext-js
Packt
23 Oct 2009
9 min read
Save for later

Layouts in Ext JS

Packt
23 Oct 2009
9 min read
What are layouts, regions, and viewports? Ext uses Panels, which are the basis of most layouts. We have used some of these, such as FormPanel and GridPanel, already. A viewport is a special panel-like component that encloses the entire layout, fitting it into the whole visible area of our browser. For our first example, we are going to use a viewport with a border layout that will encapsulate many panels. A viewport has regions that are laid out in the same way as a compass, with North,South, East and West regions—the Center region represents what's left over in the middle. These directions tell the panels where to align themselves within the viewport and, if you use them, where the resizable borders are to be placed: The example we're creating will look like the following image, and combines many of the previous examples we have created: This layout is what's called a 'border' layout, which means that each region is separated by a somewhat three dimensional border bar that can be dragged to resize the regions. This example contains four panel regions: North: The toolbar West: A form Center: Grid in a tab panel East: A plain panel containing text Note that there is no 'South' panel in this example—not every region needs to be used in every layout. Our first layout Before we create our layout that uses only four regions let's go ahead and create a layout that utilizes all the regions, and then remove the South panel. We are going to create all of the regions as 'panels', which can be thought of as blank canvases to which we will add text, HTML, images, or even Ext JS widgets. var viewport = new Ext.Viewport({ layout: 'border', renderTo: Ext.getBody(), items: [{ region: 'north', xtype: 'panel', html: 'North' },{ region: 'west', xtype: 'panel', split: true, width: 200, html: 'West' },{ region: 'center', xtype: 'panel', html: 'Center' },{ region: 'east', xtype: 'panel', split: true, width: 200, html: 'East' },{ region: 'south', xtype: 'panel', html: 'South' }]}); Each region is defined as one of the four compass directions—East, West, North, and South. The remainder in the middle is called the center region, which will expand to fill all of the remaining space. Just to take up some blank space in each region and to give a visual indicator as to where the panels are, we defined an 'HTML' config that has just text. (This could also contain complex HTML if needed, but there are better ways to set the contents of panels which we will learn about soon). Ext JS provides an easy, cross-browser compatible, speedy way to get a reference to the body element, by using Ext.getBody(). If everything works out ok, you should see a browser that looks like this: Now we have a layout with all five regions defined. These regions can have other text widgets added into them, seamlessly, by using the xtype config. Alternatively they can be divided up separately into more nested regions—for instance, the center could be split horizontally to have its own South section. A 'Center' region must always be defined. If one is not defined, the layout will produce errors and appear as a jumbled set of boxes in the browser. Splitting the regions The dividers are set up for each panel by setting the split flag—the positioning of the dividers is determined automatically based on the region the panel is in. split: true For this page, we have set the West and East regions as 'split' regions. This, by default, makes the border into a resizing element for the user to change the size of that panel. I want options Typically, when a split is used, it's combined with a few other options that make the section more useful, such as width, minSize, and collapseMode. Here are some of the more commonly-used options: Option Value Description split true/false Boolean value that places a resizable bar between the sections collapsible true/false Boolean value that adds a button to the title bar which lets the user collapse the region with a single click collapseMode Only option is mini mode, or undefined for normal mode When set to 'mini', this adds a smaller collapse button that's located on the divider bar, in addition to the larger collapse button on title bar; the panel also collapses into a smaller space title String Title string placed in the title bar bodyStyle CSS CSS styles applied to the body element of the panel. minSize Pixels, ie: 200 The smallest size that the user can drag this panel to maxSize Pixels, ie: 250 The largest size that the user can drag this panel to margins In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 Can be used to space the panel away from the edges or away from other panels; spacing is applied outside of the body of the panel cmargins In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 Same idea as margins, but applies only when the panel is collapsed   Let's add a couple of these options to our west panel: { region: 'west', xtype: 'panel', split: true, collapsible: true, collapseMode: 'mini', title: 'Some Info', bodyStyle:'padding:5px;', width: 200, minSize: 200, html: 'West'} Adding these config options to our west panel would give us the following look: Expanding and collapsing a panel that does not have a width specified can produce rendering problems. Therefore, it's best to specify a width for panels—of course this is not needed for the center, as this panel automatically fills the remaining space. Tab panels With Ext JS, tab panels are also referred to as a "card" layout because they work much like a deck of cards where each card is layered directly above or below the others and can be moved to the top of the deck, to be visible. We also get pretty much the same functionality in our tab panel as a regular panel, including a title, toolbars, and all the other usual suspects (excluding tools). Adding a tab panel If the Ext JS component is a panel type component, for instance GridPanel andFormPanel, then we can add it directly to the layout using its xtype. Let's start by creating a tabPanel: { region: 'center', xtype: 'tabpanel', items: [{ title: 'Movie Grid', html: 'Center' }]} The items config is an array of objects that defines each of the tabs contained in this tabpanel. The title is the only option that's actually needed to give us a tab, and right now html is just being used as a placeholder, to give our empty tab some content. We will also need to add an activeTab config that is set to zero to our tab panel. This is the index of the tabs in the panel left to right starting with zero and counting up for each tab. This tells the tab panel at position zero to make itself active by default, otherwise, we would have no tabs displayed, resulting in a blank section until the user clicked a tab. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', html: 'Center' }]} If we take a look at this in a browser, we should see a tab panel in the center section of our layout. Adding more tabs is as easy as adding more items into the items array. Each tab item is basically its own panel, which is shown or hidden, based on the tab title that has been clicked on the tab panel. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', html: 'Center' },{ title: 'Movie Descriptions', html: 'Movie Info' }]} Both the Movie Grid and Movie Descriptions tabs are just plain panels right now. So let's add some more configuration options and widgets to them. Widgets everywhere Earlier, I mentioned that any type of panel widget could be added directly to a layout, just as we had done with the tabs. Let's explore this by adding another widget to our layout—the grid. Adding a grid into the tabpanel As we now have these tabs as part of our layout, let's start by adding a grid panel to one of the tabs. Adding the xtype config option to the grid config code will produce a grid that fills one entire tab: { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', xtype: 'gridpanel', store: store, autoExpandColumn: 'title', columns: // add column model //, view: // add grid view spec // },{ title: 'Movie Descriptions', html: 'Movie Info' }]} xtypes offer a quick way to instantiate a new component with minimal typing. This is sometimes referred to as 'lazy rendering' because the components sit around waiting to be displayed before they actually execute any code. This method can help conserve memory in your web application. As we are adding this grid to a tab—which is essentially just a panel—there are some things that we no longer need (like the renderTo option, width, height, and a frame).The size, title, and border for the grid are now handled by our tab panel. Now we should have a layout that looks like this: Accordions The accordion is a very useful layout that works somewhat like a tab panel, where we have multiple sections occupying the same space, with only one showing at a time. This type of layout is commonly used when we're lacking the horizontal space needed for a tab panel, but instead have more vertical space available. When one of the accordion panels is expanded, the others will collapse. Expanding and collapsing the panels can be done either by clicking the panel's title bar or by clicking the plus/minus icons along the rightmost side of the panel.    
Read more
  • 0
  • 0
  • 4840

article-image-password-strength-checker-google-web-toolkit-and-ajax
Packt
23 Oct 2009
8 min read
Save for later

Password Strength Checker in Google Web Toolkit and AJAX

Packt
23 Oct 2009
8 min read
Password Strength Checker Visual cues are great way to inform the user of the status of things in the application. Message boxes and alerts are used much too often for this purpose, but they usually end up irritating the user. A much smoother and enjoyable user experience is provided by subtly indicating to the user the status as an application is used. In this section, we are going to create an application that indicates the strength of a typed password to the user by the use of colors and checkboxes. We are going to use check-boxes very differently than their normal usage. This is an example of using GWT widgets in new and different ways, and mixing and matching them to provide a great user experience. Time for Action—Creating the Checker In the current day and age, passwords are required for almost everything, and choosing secure passwords is very important. There are numerous criteria suggested for creating a password that is secure from most common password cracking exploits. These criteria run the gamut from creating 15 letter passwords with a certain number of lower case and numeric digits to creating passwords using random password generators. In our example application, we are going to create a password strength checker that is very simple, and only checks the number of letters in the password. A password string that contains less than five letters will be considered weak, while a password that contains between five and seven letters will be considered to be of medium strength. Any password containing more than seven letters will be considered as strong. The criteria were deliberately kept simple so that we can focus on creating the application without getting all tangled up in the actual password strength criteria. This will help us to understand the concepts and then you can extend it to use any password strength criteria that your application warrants. This example uses a service to get the password strength, but this could also be done all on the client without needing to use a server. 1. Create a new Java file named PasswordStrengthService.java in the com.packtpub.gwtbook.samples.client package. Define a PasswordStrengthService interface with one method to retrieve the strength of a password string provided as a parameter to the method: public interface PasswordStrengthService extends RemoteService{public int checkStrength(String password);} 2. Create the asynchronous version of this service definition interface in a new Java file named PasswordStrengthServiceAsync.java in the com.packtpub.gwtbook.samples.client package : public interface PasswordStrengthServiceAsync{public void checkStrength(String password, AsyncCallback callback);} 3. Create the implementation of our password strength service in a new Java file named PasswordStrengthServiceImpl.java in the com.packtpub.gwtbook.samples.server package. public class PasswordStrengthServiceImpl extendsRemoteServiceServlet implements PasswordStrengthService{private int STRONG = 9;private int MEDIUM = 6;private int WEAK = 3;public int checkStrength(String password){if (password.length() <= 4){return WEAK;}else if (password.length() < 8){return MEDIUM;}else{return STRONG;}}} 4. Now let's create the user interface for this application. Create a new Java file named PasswordStrengthPanel.java in the com.packtpub.gwtbook.samples.client.panels package that extends the com.packtpub.gwtbook.samples.client.panels.SamplePanel class. Create a text box for entering the password string an ArrayList named strengthPanel for holding the checkboxes that we will use for displaying the strength of the password. Also create the PasswordStrengthService object. public TextBox passwordText = new TextBox();final PasswordStrengthServiceAsync pwStrengthService =(PasswordStrengthServiceAsync)GWT.create(PasswordStrengthService.class);public ArrayList strength = new ArrayList(); 5. Add a private method for clearing all the checkboxes by setting their style to the default style. private void clearStrengthPanel(){for (Iterator iter = strength.iterator(); iter.hasNext();){((CheckBox) iter.next()).setStyleName(getPasswordStrengthStyle(0));}} 6. Add a private method that will return the CSS name, based on the password strength. This is a nice way for us to dynamically set the style for the checkbox, based on the strength. private String getPasswordStrengthStyle(int passwordStrength){if (passwordStrength == 3){return "pwStrength-Weak";}else if (passwordStrength == 6){return "pwStrength-Medium";}else if (passwordStrength == 9){return "pwStrength-Strong";}else{return "";}} 7. In the constructor for the PasswordStrengthPanel class, create a HorizontalPanel named strengthPanel, add nine checkboxes to it, and set its style. As mentioned before, the styles that we are using in the sample applications in this book are available in the file Samples.css, which is part of the source code distribution for this book. We also add these same checkboxes to the strength object, so that we can retrieve them later to set their state. These checkboxes will be used for displaying the password strength visually. Create a new VerticalPanel that we will use as the container for the widgets that we are adding to the user interface. Finally, create the service target and set its entry point. HorizontalPanel strengthPanel = new HorizontalPanel();strengthPanel.setStyleName("pwStrength-Panel");for (int i = 0; i < 9; i++){CheckBox singleBox = new CheckBox();strengthPanel.add(singleBox);strength.add(singleBox);}VerticalPanel workPanel = new VerticalPanel();ServiceDefTarget endpoint=(ServiceDefTarget) pwStrengthService;endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +"pwstrength"); 8. In the same constructor, set the style for the password text box, and add an event handler to listen for changes to the password box. passwordText.setStyleName("pwStrength-Textbox");passwordText.addKeyboardListener(new KeyboardListener(){public void onKeyDown(Widget sender, char keyCode, int modifiers){}public void onKeyPress(Widget sender, char keyCode, int modifiers){}public void onKeyUp(Widget sender, char keyCode,int modifiers){if (passwordText.getText().length() > 0){AsyncCallback callback = new AsyncCallback(){public void onSuccess(Object result){clearStrengthPanel();int checkedStrength = ((Integer) result).intValue();for (int i = 0; i < checkedStrength; i++){((CheckBox) strength.get(i)).setStyleName(getPasswordStrengthStyle(checkedStrength));}}public void onFailure(Throwable caught){Window.alert("Error calling the password strengthservice." + caught.getMessage());}};pwStrengthService.checkStrength(passwordText.getText(), callback);}else{clearStrengthPanel();}}}); 9. Finally, in the constructor, add the password text box and the strength panel to the work panel. Create a little info panel that displays descriptive text about this application, so that we can display this text when this sample is selected in the list of available samples in our Samples application. Add the info panel and the work panel to a dock panel, and initialize the widget. HorizontalPanel infoPanel = new HorizontalPanel();infoPanel.add(new HTML("<div class='infoProse'>Start typing a passwordstring. The strength of the password will bechecked and displayed below. Red indicates that thepassword is Weak, Orange indicates a Mediumstrength password and Green indicates a Strongpassword. The algorithm for checking the strengthis very basic and checks the length of the passwordstring.</div>"));workPanel.add(passwordText);workPanel.add(infoPanel);workPanel.add(strengthPanel);DockPanel workPane = new DockPanel();workPane.add(infoPanel, DockPanel.NORTH);workPane.add(workPanel, DockPanel.CENTER);workPane.setCellHeight(workPanel, "100%");workPane.setCellWidth(workPanel, "100%");initWidget(workPane); 10. Add the service to the module file for the Samples application—Samples.gwt.xml in the com.packtpub.gwtbook.samples package. <servlet path="/pwstrength" class="com.packtpub.gwtbook.samples.server.PasswordStrengthServiceImpl"/> Here is the user interface for the password strength checking application: Now start typing a password string to check its strength. Here is the password strength when you type a password string that is less than five characters: What Just Happened? The password strength service checks the size of the provided string and returns an integer value of three, six, or nine based on whether it is weak, medium, or strong. It makes this determination by using the criteria that if the password string is less than five characters in length, it is weak, and if it is more than five characters but not greater than seven characters, it is considered a medium strength password. Anything over seven characters is considered to be a strong password. The user interface consists of a text box for entering a password string and a panel containing nine checkboxes that visually displays the strength of the typed string as a password. An event handler is registered to listen for keyboard events generated by the password text box. Whenever the password text changes, which happens when we type into the field or change a character in the field, we communicate asynchronously with the password strength service and retrieve the strength of the given string as a password. The returned strength is displayed to the user in a visual fashion by the use of colors to symbolize the three different password strengths. The password strength is displayed in a compound widget that is created by adding nine checkboxes to a HorizontalPanel. The color of the checkboxes is changed using CSS depending on the strength of the password string. This process of combining the basic widgets provided by GWT into more complex widgets to build user interfaces is a common pattern in building GWT applications. It is possible to build quite intricate user interfaces in this way by utilizing the power of the GWT framework. Summary In the current day and age, passwords are required for almost everything, and choosing secure passwords is very important. In this article, we implemented a password strength checker in Google Web Toolkit (GWT) and AJAX. By going through the article, the reader can also get a general idea of implementing other interactive user forms.
Read more
  • 0
  • 0
  • 2825

article-image-table-and-database-operations-php
Packt
23 Oct 2009
8 min read
Save for later

Table and Database Operations in PHP

Packt
23 Oct 2009
8 min read
Various links that enable table operations have been put together on one sub-page of the Table view: Operations. Here is an overview of this sub-page: Table Maintenance During the lifetime of a table, it repeatedly gets modified, and so grows and shrinks. Outages may occur on the server, leaving some tables in a damaged state. Using the Operations sub-page, we can perform various operations, but not every operation is available for every table type: Check table: Scans all rows to verify that deleted links are correct. Also, a checksum is calculated to verify the integrity of the keys; we should get an 'OK' message if everything is all right. Analyze table: Analyzes and stores the key distribution; this will be used on subsequent JOIN operations to determine the order in which the tables should be joined. Repair table: Repairs any corrupted data for tables in the MyISAM and ARCHIVE engines. Note that the table might be so corrupted that we cannot even go into Table view for it! In such a case, refer to the Multi-Table Operations section for the procedure to repair it. Optimize table: This is useful when the table contains overheads. After massive deletions of rows or length changes for VARCHAR fields, lost bytes remain in the table. PhpMyAdmin warns us in various places (for example, in the Structure view) if it feels the table should be optimized. This operation is a kind of defragmentation for the table. In MySQL 4.x, this operation works only on tables in the MyISAM, Berkeley (BDB), and InnoDB engines. In MySQL 5.x, it works only on tables in the MyISAM, InnoDB, andARCHIVE engines. Flush table: This must be done when there have been lots of connection errors and the MySQL server blocks further connections. Flushing will clear some internal caches and allow normal operations to resume. Defragment table: Random insertions or deletions in an InnoDB table fragment its index. The table should be periodically defragmented for faster data retrieval. The operations are based on the underlying MySQL queries available—phpMyAdmin is only calling those queries. Changing Table Attributes Table attributes are the various properties of a table. This section discusses the settings for some of them. Table Type The first attribute we can change is called Table storage engine: This controls the whole behavior of the table: its location (on-disk or in-memory), the index structure, and whether it supports transactions and foreign keys. The drop-down list may vary depending on the table types supported by our MySQL server. Changing the table type may be a long operation if the number of rows is large. Table Comments This allows us to enter comments for the table. These comments will be shown at appropriate places (for example, in the left panel, next to the table name in the Table view and in the export file). Here is what the left panel looks like when the $cfg['ShowTooltip'] parameter is set to its default value of TRUE: The default value of $cfg['ShowTooltipAliasDB'] and $cfg['ShowTooltipAliasTB'] (FALSE) produces the behavior we have seen earlier: the true database and table names are displayed in the left panel and in the Database view for the Structure sub-page. Comments appear when the mouse pointer is moved over a table name. If one of these parameters is set toTRUE, the corresponding item (database names for DB and table names for TB) will be shown as the tooltip instead of the names. This time, the mouse-over shows the true name for the item. This is convenient when the real table names are not meaningful. There is another possibility for $cfg['ShowTooltipAliasTB']: the 'nested' value. Here is what happens if we use this feature: The true table name is displayed in the left panel. The table comment (for example project__) is interpreted as the project name and is displayed as such. Table Order When we Browse a table or execute a statement such as SELECT * from book, without specifying a sort order, MySQL uses the order in which the rows are physically stored. This table order can be changed with the Alter table order by dialog. We can choose any field, and the table will be reordered once on this field. We choose author_id in the example, and after we click Go, the table gets sorted on this field. Reordering is convenient if we know that we will be retrieving rows in this order most of the time. Moreover, if later we use an ORDER BY clause and the table is already physically sorted on this field, the performance should be higher. This default ordering will last as long as there are no changes in the table (no insertions, deletions, or updates). This is why phpMyAdmin shows the (singly) warning. After the sort has been done on author_id, books for author 1 will be displayed first, followed by the books for author 2, and so on. (We are talking about a default browsing of the table without explicit sorting.) We can also specify the sort order: Ascending or Descending. If we insert another row, describing a new book from author 1, and then click Browse, the book will not be displayed along with the other books for this author because the sort was done before the insertion. Table Options Other attributes that influence the table's behavior may be specified using the Table options dialog: The options are: pack_keys:Setting this attribute results in a smaller index; this can be read faster but takes more time to update. Available for the MyISAM storage engine. checksum: This makes MySQL compute a checksum for each row. This results in slower updates, but easier finding of corrupted tables. Available for MyISAM only. delay_key_write: This instructs MySQL not to write the index updates immediately but to queue them for later, which improves performance. Available for MyISAM only. auto-increment: This changes the auto-increment value. It is shown only if the table's primary key has the auto-increment attribute. Renaming, Moving, and Copying Tables The Rename operation is the easiest to understand: the table simply changes its name and stays in the same database. The Move operation (shown in the following screen) can manipulate a table in two ways: change its name and also the database in which it is stored Moving a table is not directly supported by MySQL, so phpMyAdmin has to create the table in the target database, copy the data, and then finally drop the source table. The Copy operation leaves the original table intact and copies its structure or data (or both) to another table, possibly in another database. Here, the book-copy table will be an exact copy of the book source table. After the copy, we will stay in the Table view for the book table unless we selected Switch to copied table. The Structure only copy is done to create a test table with the same structure. Appending Data to a Table The Copy dialog may also be used to append (add) data from one table to another. Both tables must have the same structure. This operation is achieved by entering the table to which we want to copy the data of the current table and choosing Data only. For example, we would want to append data when book data comes from various sources (various publishers), is stored in more than one table, and we want to aggregate all the data to one place. For MyISAM, a similar result can be obtained by using the MERGE storage engine (which is a collection of identical MyISAM tables), but if the table is InnoDB, we need to rely on phpMyAdmin's Copy feature. Multi-Table Operations In the Database view, there is a checkbox next to each table name and a drop-down menu under the table list. This enables us to quickly choose some tables and perform an operation on all those tables at once. Here we select the book-copy and the book tables, and choose the Check operation for these tables. We could also quickly select or deselect all the checkboxes with Check All/Uncheck All. Repairing an "in use" Table The multi-table mode is the only method (unless we know the exact SQL query to type) for repairing a corrupted table. Such tables may be shown with the in use flag in the database list. Users seeking help in the support forums for phpMyAdmin often receive this tip from experienced phpMyAdmin users. Database Operations The Operations tab in the Database view gives access to a panel that enables us to perform operations on a database taken as a whole. Renaming a Database Starting with phpMyAdmin 2.6.0, a Rename database dialog is available. Although this operation is not directly supported by MySQL, phpMyAdmin does it indirectly by creating a new database, renaming each table (thus sending it to the new database), and dropping the original database. Copying a Database Since phpMyAdmin 2.6.1, it is possible to do a complete copy of a database, even if MySQL itself does not support this operation natively. Summary In this article, we covered the operations we can perform on whole tables or databases. We also took a look at table maintenance operations for table repair and optimization, changing various table attributes, table movements, including renaming and moving to another database, and multi-table operations.
Read more
  • 0
  • 0
  • 5632
article-image-minilang-and-ofbiz
Packt
23 Oct 2009
11 min read
Save for later

Minilang and OFBiz

Packt
23 Oct 2009
11 min read
What is Minilang? The syntax of Minilang is simply well formed XML. Developers write XML that obeys a defined schema, this XML is then parsed by the framework and commands are executed accordingly. It is similar in concept to the Gang of Four Interpreter Pattern. We can therefore consider Minilang's XML elements to be "commands". Minilang is usually written in a simple method's XML file, which is specified at the top of the document like this: xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ simple-methods.xsd"> Although Minilang's primary use is to code services and events, concepts from Minilang are also used to prepare data for screen widgets. Much of the simplicity of Minilang arises from the fact that variables are magically there for us to use. They do not have to be explicitly obtained, they are placed in the environment and we can take them as we wish. Should we wish to create a Map, we just use it, the framework will take care of its creation. For example: <set field="tempMap.fieldOne" from-field="parameters.fieldOne"/> will set the value of the fieldOne parameter to tempMap. If tempMap has already been used and is available, this will be added. If not, the Map will be created and the value added to the key fieldOne. Tools to Code XML Minilang is coded in XML and before it can be successfully parsed by the framework's XML parser, this XML must be well formed. Trying to code Minilang in a plain text editor like Notepad is not a wise move. Precious time can be wasted trying to discover a simple mistake such as a missing closing tag or a misspelled element. For this reason, before attempting to code Minilang services, make sure that you have installed some kind of XML editor and preferably one with an auto-complete feature. The latest versions of Eclipse come packaged with one and XML files are automatically associated to use this editor. Alternatively there are many editors available to download of varying functionality and price. For example XML Buddy (http://www.xmlbuddy.com), oXygen XML Editor (http://www.oxygenxml.com), or the heavyweight Altova XMLSpy (http://www.altova.com) Defining a Simple Service Minilang services are referred to as "simple" services. They are defined and invoked in the same way as a Java service. They can be invoked by the control servlet from the controller.xml file or from code in the same way as a Java service. In the following example we will write a simple service that removes Planet Reviews from the database by deleting the records. First open the file ${component:learning}widgetLearningForms.xml and find the PlanetReviews Form Widget. This widget displays a list of all reviews that are in the database. Inside this Form Widget, immediately under the update field element add: <field name="delete"><hyperlink target="RemovePlanetReview?reviewId=${reviewId}" description="Delete"/></field> Our list will now also include another column showing us a hyperlink we can click, although clicking it now will cause an error. We have not added the request-map to handle this request in the controller.xml. It will be added a little later. Defining the Simple Service In the file ${component:learning}servicedefservices.xml add a new service definition: <service name="learningRemovePlanetReview" engine="simple" location="org/ofbiz/learning/learning/LearningServices.xml" invoke="removePlanetReview"> <description>Service to remove a planet review</description> <attribute name="reviewId" type="String" mode="IN" optional="false"/> </service> Note that the engine type is simple. It is a common practice to group service definitions into their own XML file according to behavior. For instance, we may see that all services to do with Order Returns are in a file called services_returns.xml. So long as we add the <service-resource> element to the parent component's ofbiz-component.xml file and let the system know that this service definition file needs to be loaded, we can structure our service definitions sensibly and avoid huge definition files. It is not a common practice, however, to group service definitions by type. The type is abstracted from the rest of the system. When the service is invoked, the invoker doesn't care what type of service it is. It could be Java, it could be a simple service, it doesn't matter. All that matters is that the correct parameters are passed into the service and the correct parameters are passed out. For this reason, simple service definitions are found in the same XML files as Java service definitions. Writing the Simple Method Simple Method XML files belong in the component's script folder. In the root of ${component:learning} create the nested directory structure scriptorgofbizlearninglearning and in the final directory create a new file called LearningServices.xml. Before we add anything to this file we must make sure that the script directory is on the classpath. Open the file ${component:learning}ofbiz-component.xml and if it is not already there add <classpath type="dir" location="script"/> immediately underneath the other classpath elements. The location specified in the service definition can now be resolved. In our newly created file LearningServices.xml add the following code: <simple-methods xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/ simple-methods.xsd"> <simple-method method-name="removePlantetReview" short-description="Delete a Planet Review"> <entity-one entity-name="PlanetReview" value-name="lookedUpValue"/> <remove-value value-name="lookedUpValue"/> </simple-method> </simple-methods> Finally all that is left is to add the request-map to the controller.xml: <request-map uri="RemovePlanetReview"> <security auth="true" https="true"/> <event type="service" invoke="learningRemovePlanetReview"/> <response name="success" type="view" value="ListPlanetReviews"/> <response name="error" type="view" value="ListPlanetReviews"/> </request-map> Since we have added a new service definition OFBiz must be restarted. A compilation is not needed. Restart and fire an http request ListPlanetReviews to webapp learning: Selecting Delete will delete this PlanetReview record from the database. Let's take a closer look at the line of code in the simple service that performs the lookup of the record that is to be deleted. <entity-one entity-name="PlanetReview" value-name="lookedUpValue"/> This command will perform a lookup on the PlanetReview entity. Since the command is <entity-one> the lookup criteria must be the primary key. This code is equivalent in Java to: GenericValue lookedUpValue = delegator.findByPrimaryKey ("PlanetReview", UtilMisc.toMap("reviewId", reviewId)); Already we can see that Minilang is less complicated. And this is before we take into account that the Java code above is greatly simplified, ignoring the fact that the delegator had to be taken from the DispatchContext, the reviewId had to be explicitly taken from the context Map and the method call had to be wrapped in a try/catch block. In Minilang, when there is a look up like this, the context is checked for a parameter with the same name as the primary key for this field, as specified in the entity definition for PlanetReview. If there is one, and we know there is since we have declared a compulsory parameter reviewId in the service definition, then the framework will automatically take it from the context. We do not need to do anything else. Simple Events We can call Minilang events, in the same way that we called Java events from the controller.xml. Just as Minilang services are referred to as simple services, the event handler for Minilang events is called "simple". Tell the control servlet how to handle simple events by adding a new <handler> element to the learning component's controller.xml file, immediately under the other <handler> elements: <handler name="simple" type="request" class="org.ofbiz.webapp.event.SimpleEventHandler"/> A common reason for calling simple events would be to perform the preparation and validation on a set of parameters that are passed in from an XHTML form. Don't forget that when an event is called in this way, the HttpServletRequest object is passed in! In the case of the Java events, it is passed in as a parameter. For simple events, it is added to the context, but is nonetheless still available for us to take things from, or add things onto. In the same location as our LearningServices.xml file (${component:learning} scriptorgofbizlearninglearning) create a new file called LearningEvents.xml. To this file add one <simple-method> element inside a <simple-methods> tag: <simple-methods xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/ simple-methods.xsd"> <simple-method method-name="simpleEventTest" short-description="Testing a simple Event"> <log level="info" message="Called the Event: simpleEventTest"/> </simple-method> </simple-methods> Finally, we need to add a request-map to the controller from where this event will be invoked: <request-map uri="SimpleEventTest"> <security auth=true»https=true/> <event type=»simple»path=»org/ofbiz/learning/learning/ LearningEvents.xml»invoke=»simpleEventTest»/> <response name=»success»type=»view»value=»SimplestScreen»/> <response name=»error»type=»view»value=»SimplestScreen»/> </request-map> Notice our simple method doesn't actually do anything other than leave a message in the logs. It is with these messages that we can debug through Minilang. Validating and Converting Fields We have now met the Simple Methods Mini-Language, which is responsible for general processing to perform simple and repetitive tasks as services or events. Validation and conversion of parameters are dealt with by another type of Minilang—the Simple Map Processor. The Simple Map Processor takes values from the context Map and moves them into another Map converting them and performing validation checks en-route. Generally, Simple Map Processors will prepare the parameters passed into a simple event from an HTML form or query string. As such, the input parameters will usually be of type String. Other object types can be validated or converted using the Simple Map Processor including: BigDecimals, Doubles, Floats, Longs, Integers, Dates, Times, java.sql.Timestamps, and Booleans. The Simple Map Processors are, like simple methods, coded in XML and they adhere to the same schema (simple-methods.xsd). Open this file up again and search for The Simple Map Processor Section. The naming convention for XML files containing Simple Map Processors is to end the name of the file with MapProcs.xml (For example, LearningMapProcs.xml) and they reside in the same directory as the Simple Services and Events. One of the best examples of validation and conversion already existing in the code is to be found in the PaymentMapProcs.xml file in ${component:accounting}scriptorgofbizaccountingpayment. Open this file and find the simple-map-processor named createCreditCard. Here we can see that immediately, the field expireDate is created from the two parameters expMonth and expYear with a "/" placed in between (example, 09/2012): <make-in-string field="expireDate"> <in-field field="expMonth"/> <constant>/</constant> <in-field field="expYear"/> </make-in-string> Towards the end of the <simple-map-processor> this expireDate field is then copied into the returning Map and validated using isDateAfterToday. If the expiration date is not after today, then the card has expired and instead, a fail-message is returned. <process field="expireDate"> <copy/> <validate-method method="isDateAfterToday"> <fail-message message="The expiration date is before today"/> </validate-method> </process> The <validate-method> element uses a method called isDateAfterToday. This method is in fact a Java static method found in the class org.ofbiz.base.util.UtilValidate. We have already been using one of the OFBiz utility classes, UtilMisc, namely the toMap function, to create for us Maps from key-value pairs passed in as parameters. OFBiz provides a huge number of incredibly useful utility methods, ranging from validation, date preparation, and caching tools to String encryption and more. The framework will automatically allow Minilang access to this class. By adding a bespoke validation method into this class and recompiling, you will be able to call it from the <validate-method> in Minilang, from anywhere in your application.
Read more
  • 0
  • 0
  • 2371

article-image-user-access-control-drupal-6
Packt
23 Oct 2009
16 min read
Save for later

User Access Control in Drupal 6

Packt
23 Oct 2009
16 min read
Before we continue, it is worth pointing out that at the moment of adding the basic functionality you are more than likely using the administrative user (user number 1) for all the site's development needs. That is absolutely fine, but once the major changes to the site are completed, you should begin using a normal administrative user that has only the permissions required to complete your day-to-day tasks. The next section will highlight the general philosophy behind user access, which should make the reason for this clear. Planning an Access Policy When you think about how your site should work, focus in on what will be required of yourself, other community members, or even anonymous users. For instance: Will there be a team of moderators working to ensure that the content of the site conforms to the dictates of good taste and avoids material that is tantamount to hate speech, and so on? Will there be subject experts who are allowed to create and maintain their own content? How much will anonymous visitors be allowed to become involved, or will they be forced to merely window shop without being able to contribute? Some of you might feel that the site should grow organically with the community, and so you want to be extremely flexible in your approach. However, you can take it as given that Drupal's access policies are already flexible, given how easy it is to reconfigure, so it is good practice to start out with a sensible set of access rules, even if they are going to change over time. If you need to make modifications later, so be it, but at least there will be a coherent set of rules from the start. The first and foremost rule of security that can be applied directly to our situation is Grant a user permissions sufficient for completing the intended task, and no more! Our entire approach is going to be governed by this rule. With a bit of thought you should be able to see why this is so important. The last thing anyone wants is for an anonymous user to be able to modify the personal blog of a respected industry expert. This means that each type of user should have carefully controlled permissions that effectively block their ability to act outside the scope of their remit. One upshot of this is that it is better to create a larger number of specific roles, rather than create a generic role or two, and allow everyone to use those catch-all permissions. A role constitutes a number of permissions that define what actions any members of that role can and can't perform. We will explore roles in detail in the next section! Drupal gives us fine-grained control over what users can accomplish, and you should make good use of this facility. It may help to think of your access control using the following figure (this does not necessarily represent the actual roles on your site—it's just an example): The shaded region represents the total number of permissions available for the site. Contained within this set are the various roles that exist either by default, like the Anonymous users role, or those you create in order to cater for the different types of users the site will require—in this case, the Blog Writer users and Forum Moderator users roles. From the previous diagram you can see that the Anonymous users role has the smallest set of permissions because they have the smallest area of the total diagram. This set of permissions is totally encapsulated by the Forum Moderator users and Blog Writer users—meaning that forum moderators and blog writers can do everything an anonymous user does, and a whole lot more. Remember, it is not compulsory that forum moderators encapsulate all the permissions of the anonymous users. You can assign any permissions to any role—it's just that in this context it makes sense that a forum moderator should be able to do everything an anonymous user can and more. Of course, the blog writers have a slightly different remit. While they share some privileges in common with the forum administrators, they also have a few of their own. Your permissions as the primary or administrative user encompass the entire set, because there should be nothing that you cannot control. It is up to you to decide which roles are best for the site, but before attempting this it is important to ask: What are roles and how are they used in the first place? To answer this question, let's take a look at the practical side of things in more detail. Roles It may seem a bit odd that we are not beginning a practical look at access control with a discussion on users. After all, it is all about what users can and cannot do! The problem with immediately talking about users is that the focus of a single user is too narrow, and we can learn far more about controlling access by taking a more broad view using roles. Once we have learned everything there is to know about roles, actually working with users becomes a trivial matter. As mentioned, a user role in Drupal defines a set of rules that must be obeyed by all the users in that role. It may be helpful to think of a role as a character in a play. In a play, an actor must always be true to their character (in the same way a user must be faithful to their role in Drupal)—in other words, there is a defined way to behave and the character never deviates (no matter which actor portrays the character). Creating a role in Drupal is very easy. Click the User management link under Administer and select the Roles tab to bring up the following: As you can see, we have two roles already defined by default—the anonymous user and the authenticated user. It is not possible to change these, and so the Operations column is permanently set to locked. To begin with, the anonymous user (this is any user who is browsing the site without logging in) has very few permissions set, and you would more than likely want to keep it this way, despite the fact it is possible to give them any and all permissions. Similarly, the authenticated user, by default, has only a few more permissions than the anonymous user, and it is also sensible to keep these to a minimum. We will see in a little while how to go about deciding who should have which permissions. In order to add a new role, type in a name for the role and click Add role, and you're done. But what name do you want to add? That's the key question! If you are unsure about what name to use, then it is most likely you haven't defined the purpose of the role properly. To see how this is done, let's assume we require a forum moderator who will be a normal user in every way, except for the ability to work directly on the forums (to take some of the burden of responsibility off the administrator's hands) to create new topics, and to edit the content if necessary. To get the ball rolling, type in forum moderator and click Add role—actually, you might even want to be more specific and use something like conservation forum moderator if there will be teams of forum moderators—you get the general idea. Now the roles page should display the new role with the option to edit it, shown in the Operations column. Click edit role in order to change the name of the role or delete it completely. Alternatively, click edit permissions to deal with the permissions for this specific role (we discuss permissions in a moment so let's leave this for now). Our work is just beginning, because now we need to grant or deny the various permissions that the forum moderator role will need in order to successfully fulfill its purpose. New roles are not given any permission at all to begin with—this makes sense, because the last thing we want is to create a role only to find that it has the same permissions as the administrative user. Chances are you will need to add several roles depending on the needs of the site, so add at least a blogger user that can edit their own blog—we will need a few different types to play with later on. Let's move on and take a look at how to flesh out this new role by setting permissions. Permissions In order to work with permissions, click the Permissions link under User management and you should be presented with a screen much like the following (notice the new forum moderator role on the right-hand side of the page): As you can see, this page lists all of the available permissions down the left-hand column and allows you to enable or disable that permission by checking or un-checking boxes in the relevant column. It is easy enough to see that one traverses the list, selecting those permissions required for each role. What is not so easy is actually determining what should and shouldn't be enabled in the first place. Notice too that the permissions given in the list on the left-hand side pertain to specific modules. This means that if we change the site's setup by adding or removing modules, then we will also have to change the permissions on this page. Most times a module is added, you will need to ensure that the permissions are set as required for that module, because by default no permissions are granted. What else can we learn from the permissions page shown in the previous screenshot? Well, what does each permission precisely mean? There are quite a few verbs that allow for completely different actions. The following lists the more common, generic ones, although you might find one or two others crop up every now and then to cater for a specific module: administer: gives the user the ability to affect the function of a module. For example, granting administer rights to the locale module means that the user can add or remove languages, manage strings, and even export .po files. This permission should only ever be given to trusted users, and never to anonymous users. access: gives the user the ability to make use of a module without being able to affect it in any way. For example, granting access rights to the comment module allows a user to view comments without being able to delete, edit, or reply to them. create: gives the user the ability to create content of some sort. For example, granting rights to create stories allows users to do so, but does not also give them the ability to edit those stories. edit any/own: gives the user the ability to work with either anyone's content or specifically the content they have created—depending on whether edit any or edit own is selected. For example, granting edit own rights to the blog module means that the user can modify their own blogs at will. delete any/own: applies to content related modules such as Node and empowers users to remove either anyone's content or confine them to removing only content posted by themselves. For example, setting delete own blog entry allows users to take back any blog postings they may regret having published. There are also other module-specific permissions available, and it is recommended that you play around and understand any new permission(s) you set. Previously, assigning the edit own permission automatically provided the delete own permission. For added security, delete own permissions for individual core content types have been removed from all roles and should be assigned separately. How do we go about setting up the required permissions for the forum moderator user? If we look down the list of permissions shown on the Permission page, we see the following forum-related options (at the moment, the forum moderator permissions are those in the outermost column): Enabling these three options, and then testing out what new powers are made available, should quickly demonstrate that this is not quite what we want. If you are wondering how to actually test this out, you need to create a new user and then assign them to the forum moderator role. The following section on Users explains how to create new users and administer them properly. Jump ahead quickly and check that out so that you have a new user to work with if you are unsure how it is done. The following point might make your life a bit easier: Use two browsers to test out your site. The demo site's development machine has IE and Firefox. Keep one browser for the administrator and the other for anonymous or other users in order to test out changes. This will save you from having to log in and log out whenever testing new permissions. When testing out the new permissions one way or another, you will find that the forum moderator can access and work with all of the forums—assuming you have created any. However, notice that there are node module permissions available, which is quite interesting because most content in Drupal is actually a node. How will this affect the forum moderator? Disable the forum module permissions for the forum moderator user and then enable all the node options for the authenticated user before saving and logging out. Log back in as the forum administrator and it will be clear that despite having revoked the forum based options for this user, it is possible to post to or edit anything in the forum quite easily by selecting the Create content link in the main menu. Is this what you expected? It should be precisely what you expect because the forum moderator is an authenticated user, so they have acquired the permissions that came from the authenticated user. In addition, the forum posts are all nodes, and any authenticated user can add and edit nodes, so even though the forum moderator is not explicitly allowed to work with forums, through generic node permissions we get the same result: Defined roles are given the authenticated user permissions. Actually, the result is not entirely the same because the forum moderator can now also configure all the different types of content on the site, as well as edit any type of content including other people's blogs. This is most certainly undesirable, so log back in as the primary user and remove the node permissions (except the first one) from the authenticated user role. With that done, you can now spend some time building a fairly powerful and comprehensive role-based access control plan. As an addendum, you might find that despite having a goodly amount of control over who does what, there are some things that are not easily done without help from elsewhere. Users A single user account can be given as many or as few permissions as you like via the use of roles. Drupal users are not really anything unless they already have a role that defines the manner in which they can operate within the Drupal framework. Hence, we discussed roles first. Users can be created in two ways. The most common way is by registering on the site—if you haven't already, go ahead and register a new user on your site by clicking the Create new account link on the homepage just to test things out. Remember to supply a valid email address otherwise you won't be able to sign in properly. This will create an authenticated user, with any and all permissions that have been assigned to the authenticated user role. The second way is to use the administrative user to create a new user. In order to do so, log on as the administrative user and click on Users in User management under Administer. Select the Add user tab and follow the instructions on that page. For example, I created a new forum moderator user by ensuring that the relevant role was checked: You will need to supply Drupal with usernames, email addresses, and passwords. Once there are a couple of users to play around with, it's time to begin working with them. Administering Users The site's administrator is given complete access to the other users' account information. By clicking on the edit link shown to the right of each user account (under the Operations column heading) in the Users page under User management, it is possible to make any changes you require to a given user. Before we do though, it's worth noting that the administration page itself is fairly powerful in terms of being able to administer individual users or groups of users with relative ease: The upper box, Show only users where, allows you to specify several filter conditions to cut down the result set and make it more manageable. This will become more and more important as the site accumulates more and more users. Once the various filter options have been implemented, the Update options allow you to apply whatever changes are needed to the list of users selected (by checking the relevant checkbox next to their name). Having both broad, sweeping powers as well as fine-grained control over users is one of the most valuable facilities provided by Drupal, and you will no doubt become very familiar with this page in due course. Click on the edit link next to the forum moderator user and take a look at the Roles section. Notice that it is now possible to stipulate which roles this user belongs to. At present there are only two new roles to be assigned (yours might vary depending on which roles have been created on your setup): Whenever a user is added to another role, they obtain the combined permissions of these roles. With this in mind, you should go about delegating roles in the following fashion: Define the most basic user of the site by setting the anonymous user permissions. Set permissions for a basic authenticated user (i.e. any Tom, Dick or Harry that registers on your site). Create special roles by only adding the specific additional permissions that are required by that role, and no more. Don't re-assign permissions that the authenticated user already has. Create new users by combining whatever roles are required for their duties or needs.
Read more
  • 0
  • 0
  • 3412

article-image-implementing-calendar-control-yahoo-user-interface-yui
Packt
23 Oct 2009
10 min read
Save for later

Implementing a Calendar Control in the Yahoo User Interface (YUI)

Packt
23 Oct 2009
10 min read
The Basic Calendar Class The most basic type of calendar is the single-panel Calendar which is created with the YAHOO.widget.Calendar class. To display a calendar, an HTML element is required to act as a container for the calendar. The screenshot shows a basic Calendar control: The constructor can then be called specifying, at the very least the id of the container element as an argument. You can also specify the id of the Calendar object as an argument, as well as an optional third argument that can accept a literal object containing various configuration properties. The configuration object is defined within curly braces within the class constructor. It contains a range of configuration properties and keys that can be used to control different Calendar attributes such as its title, a comma-delimited range of pre-selected dates, or a close button shown on the calendar. There are a large number of methods defined in the basic Calendar class; some of these are private methods that are used internally by the Calendar object to do certain things and which you normally wouldn't need to use yourself. Some of the more useful public methods include: Initialization methods including init, initEvents, and initStyles which initialize either the calendar itself or the built-in custom events and style constants of the calendar. A method for determining whether a date is outside of the current month: isDateOOM. Navigation methods such as nextMonth, nextYear, previousMonth, and previousYear that can be used to programmatically change the month or year displayed in the current panel. Operational methods such as addMonths, addYears, subtractMonths, and subtractYears which are used to change the month and year shown in the current panel by the specified number of months or years. The render method is used to draw the calendar on the page and is called in for every implementation of a calendar, after it has been configured. Without this method, no Calendar appears on the page. Two reset methods: reset which resets the Calendar to the month and year originally selected, and resetRenderers which resets the render stack of the calendar. Selection methods that select or deselect dates such as deselect, deselectAll, desellectCell, select, and selectCell. As you can see, there are many methods that you can call to take advantage of the advanced features of the calendar control. The CalendarGroup Class In addition to the basic calendar, you can also create a grouped calendar that displays two or more month panels at once using the YAHOO.widget.CalendarGroup class. The control automatically adjusts the Calendar's UI so that the navigation arrows are only displayed on the first and last calendar panels, and so that each panel has its own heading indicating which month it refers to. The CalendarGroup class contains additional built-in functionality for updating the calendar panels on display, automatically. If you have a two-panel calendar displaying, for example, January and February, clicking the right navigation arrow will move February to the left of the panel so that March will display as the right-hand panel. All of this is automatic and nothing needs to be configured by you. There are fewer methods in this class; some of those found in the basic Calendar class can also be found here, such as the navigation methods, selection methods, and some of the render methods. Native methods found only in the CalendarGroup class include: The subscribing methods sub and unsub, which subscribe or unsubscribe to custom events of each child calendar. Child functions such as the callChildFunction and setChildFunction methods which set and call functions within all child calendars in the calendar group. Implementing a Calendar To complete this example, the only tool other than the Yahoo User Interface (YUI) that you'll need is a basic text editor. Native support for the YUI is provided by some web authoring software packages, most notably Aptana, an open-source application that has been dubbed 'Dreamweaver Killer'. However, I always find that writing code manually while learning something is much more beneficial. It is very quick and easy to add the calendar, as the basic default implementations require very little configuration. It can be especially useful in forms where the visitor must enter a date. Checking that a date has been entered correctly and in the correct format takes valuable processing time, but using the YUI calendar means that dates are always exactly as you expect them to be. So far we've spent most of this article looking at a lot of the theoretical issues surrounding the library; I don't know about you, but I think it's definitely time to get on with some actual coding! The Initial HTML Page Our first example page contains a simple text field and an image, which once clicked will display the Calendar control on the page, thereby allowing for a date to be selected and added to the input. Begin with the following basic HTML page: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd"><html lang="en"><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><title>YUI Calendar Control Example</title><link rel="stylesheet"type="text/css"href="yui/build/calendar/assets/skins/sam/calendar.css"><script type="text/javascript"src="yui/build/yahoo-dom-event/yahoo-dom-event.js"></script><script type="text/javascript"src="yui/build/calendar/calendar-min.js"></script><style type="text/css">input {margin:0px 10px 0px 10px;}</style></head><body class="yui-skin-sam"><div><label>Please enter your date of birth:</label><input type="text" name="dobfield" id="dobfield"><img id="calico" src="icons/cal.png"alt="Open the Calendar control"></div><div id="mycal"></div></body></html> We begin with a valid DOCTYPE declaration, a must in any web page. For validity, we can also add the lang attribute to the opening <html> tag and for good measure, enforce the utf-8 character set. Nothing so far is YUI-specific, but coding in this way every time is a good habit. We link to the stylesheet used to control the appearance of the calendar control, which is handled in this example by the sam skin within the <link> tag. Accordingly, we also need to add the appropriate class name to the <body> tag. Following this, we link to the required library files with <script> tags; the calendar control is relatively simple and requires just the YAHOO, Document Object Model (DOM), and Event components (using the aggregated yahoo-dom-event.js file for efficiency), as well as the underlying source file calendar-min.js. A brief <style> tag finishes the <head> section of the page with some CSS relevant to this particular example, and the <body> of the page at this stage contains just two <div> elements: the first holds a <label>, text field, and a calendar icon (which can be used to launch the control), while the second holds the calendar control. When viewed in a browser, the page at this point should appear like this: The calendar icon used in this example was taken, with gratitude from Mark Carson at http://markcarson.com. Beginning the Scripting We want the calendar to appear when the icon next to the text field is clicked, rather than it being displayed on the page-load, so the first thing we need to do is to set a listener for the click event on the image. Directly before closing </body> tag, add the following code: <script type="text/javascript">//create the namespace object for this exampleYAHOO.namespace("yuibook.calendar");//define the lauchCal function which creates the calendarYAHOO.yuibook.calendar.launchCal = function() {}//create calendar on page load YAHOO.util.Event.onDOMReady(YAHOO.yuibook.calendar.launchCal);</script> Let's look at each line of the above code. We first use the .namespace() method of the YAHOO utility to set up the namespace object used for this example. Next we define the anonymous launchCal function, which will hold all of the code that generates the calendar control. Then we use the .onDOMReady() method of the Event utility to execute the launchCal function when the DOM is in an usable state. We'll be looking at the DOM utility in much greater detail later in the book. Now we can add the extremely brief code that's required to actually produce the Calendar. Within the braces of our anonymous function, add the following code: //create the calendar object, specifying the containerVar myCal = new YAHOO.widget.Calendar("mycal");//draw the calendar on screenmyCal.render();//hide it again straight awaymyCal.hide(); This is all that we need to create the Calendar; we simply define myCal as a new Calendar object, specifying the underlying container HTML element as an argument of the constructor. Once we have a Calendar object, we can call the .render() method on it to create the calendar and display it on the page. No arguments are required for this method. Since we want the calendar to be displayed when its icon is clicked, we hide the calendar from view straight away. To display the calendar when the icon for it is clicked, we'll need one more anonymous function. Add the following code beneath the .hide() method: //define the showCal function which shows the calendarVar showCal = function() {//show the calendarmyCal.show();} Now we can attach a listener which detects the click event on the calendar icon: //attach listener for click event on calendar iconYAHOO.util.Event.addListener("calico", "click", showCal); Save the file that we've just created as calendar.html or similar in your yuisite directory. If you view it in your browser now and click the Calendar icon, you should see this: The calendar is automatically configured to display the current date, although this is something that can be changed using the configuration object mentioned earlier. If you use a DOM explorer to view the current DOM of a page with an open calendar on it, you'll see that a basic Calendar control is rendered as a table with eight rows and seven columns. The first row contains the images used to navigate between previous or forthcoming months and the title of the current month and year. The next row holds the two-letter representations of each of the different days of the week, and the rest of the rows hold the squares representing the individual days of the current month. The screenshot on the next page show some of the DOM representation of the Calendar control used in our example page: Now that we can call up the Calendar control by clicking on our Calendar icon, we need to customize it slightly. Unless the person completing the form is very young, they will need to navigate through a large number of calendar pages in order to find their date of birth. This is where the Calendar Navigator interface comes into play. We can easily enable this feature using a configuration object passed into the Calendar constructor. Alter your code so that it appears as follows: //create the calendar object, using container & config objectmyCal = new YAHOO.widget.Calendar("mycal", {navigator:true}); Clicking on the Month or Year label will now open an interface which allows your visitors to navigate directly to any given month and year: The configuration object can be used to set a range of calendar configuration properties including the original month and year displayed by the Calendar, the minimum and maximum dates available to the calendar, a title for the calendar, a close button, and various other properties.
Read more
  • 0
  • 0
  • 3721
article-image-business-blogging-technorati-state-blogosphere-2008
Packt
23 Oct 2009
4 min read
Save for later

Business Blogging On The Up - Technorati State of the Blogosphere 2008

Packt
23 Oct 2009
4 min read
The report also states that blogs are profitable, it says: The majority of bloggers we surveyed currently have advertising on their blogs. Among those with advertising, the mean annual investment in their blog is $1,800, but it’s paying off. The mean annual revenue is $6,000 with $75K+ in revenue for those with 100,000 or more unique visitors per month. It is interesting to note that the majority of bloggers now display advertising. One of the most encouraging statistics is that the proportion of people blogging about their jobs and on behalf of their business is now so high: About half of bloggers are professional bloggers — blogging is not necessarily their full-time job, but they blog about their industry or profession in an unofficial capacity. 12% of bloggers blog in an official capacity for their company. The amount of cross-over between the groups is also interesting. It shows that personal and business blogging can be successfully combined: More than half of professional and corporate bloggers are also personal bloggers. This could be on a separate blog, or they may blog about personal interests within their professional blog. Corporate bloggers: 69% are also personal bloggers 65% are professional bloggers Professional bloggers: 59% are also personal bloggers 17% are corporate bloggers It’s very encouraging to see the positive benefits being enjoyed by business and professional bloggers, with the majority of those surveyed reporting a positive impact as a result of their blog. Half of them say they are better known in their industry and a quarter see their blog as a useful résumé enhancement. Impact of blogging on professional life: Business bloggers also report that blogging has brought many unique opportunities that wouldn’t have otherwise been available. Taking part in an event, contributing to a print publication or even appearing on radio or TV are the kinds of things they are involved in, thanks to their blog. Have you been invited to any of the following as the result of your blog? Blogging is a time consuming activity. This is confirmed by the report which shows that a quarter of bloggers spend over 10 hours per week on their blog and nearly half spend 5 hours or more. Time spent blogging each week: As I mention in WordPress For Business Bloggers, many bloggers take on help to run their blog. This is particularly true for corporate or business bloggers, of whom nearly 20% have paid staff working for them. Blogs with higher Technorati authority are updated more frequently than those with less authority, as the report states: The Technorati Top 100 are prolific, with 43% posting ten times per day or more often. Only 8% post once a day or less frequently, compared to 13% of the next 500 bloggers, and 22% of the next 5000 bloggers. I highlight the importance of using tags in WordPress For Business Bloggers, and this is borne out by the data. Technorati top 100 bloggers are twice as likely to tag their posts. Percentage of bloggers who use tags: Promoting a blog well is key to its success and the report shows us the top traffic-building strategies used. These are particularly important for business bloggers, so all the techniques highlighted in the chart below are covered in WordPress For Business Bloggers, you’ll find many of them in Chapter 7, Supercharged Promotion: The vast majority of bloggers are tracking their site visitors and monthly page views, with Google Analytics being used by two thirds of them. Using Google Analytics with WordPress is covered in detail in the book, WordPress For Business Bloggers. Direct revenue generation is becoming an important aspect of blogging, with the majority of bloggers now displaying ads, affiliate marketing or other form of revenue generation (this subject is covered in detail in Chapter 10 of WordPress For Business Bloggers): The report data seems to suggest that the medium of blogging is gaining credibility and being taken more seriously as a source of information. 37% of bloggers have been quoted in the traditional media as a result of one of their posts. This is encouraging for business bloggers who use their blog as a PR tool. All in all, the State of the Blogosphere 2008 report makes encouraging reading for business bloggers as well as anyone who is thinking about starting a blog for their business. A blog can be a tremendously powerful tool for any business and using a top quality platform like WordPress makes running a blog extremely easy.  
Read more
  • 0
  • 0
  • 1466

article-image-third-party-video-hosting-drupal-websites
Packt
23 Oct 2009
7 min read
Save for later

Third-Party Video Hosting on Drupal Websites

Packt
23 Oct 2009
7 min read
Third-Party Video Providers Many sites desiring video will choose to use a third-party video provider such as YouTube or Blip.TV. This reduces the bandwidth requirement from their server, is easy to include in their posts, and allows videos to be easily shared virtually by users across the Internet. The easiest way, without further configuration of a basic Drupal installation, for an administrator to include a third-party video is to simply paste the video's embedded code in a post. Most video providers will offer a snippet of HTML that may be copied from a particular video page, which will embed the video. However, this requires using a filter that will allow <object>, <embed>, and <param> tags. But since they open the door to attacks on the site, they should only be used by administrators and trusted editors. You could also use the Full HTML filter, but this is even more dangerous as allowing that filter to be generally used would open the site to cross-site scripting (XSS) attacks. First, you'll need to set up a filter that allows the tags. Add an input format at Administer | Site configuration | Input formats (at /admin/settings/filters/add). After naming the filter, check the role(s) you wish to give access to this filter such as edit role. Check HTML corrector, HTML filter, and Line break converter. After pressing Save configuration, click on the Configure tab. Using YouTube as an example, an administrator would first need to upload a video to YouTube. This will require an account at YouTube, but they make it fairly painless for a user to jump in and contribute videos. You'll just need to follow their instructions: Once you have a video there, you will find the embedded code on the video page. You will need to click in the text field where that is provided, and copy the HTML for pasting on your own page: Next you will submit a node on your site such as from Node | Add | Page (at /node/add/page), and paste the embed code in the body for the node. You will need to enable either the new filter created earlier or Full HTML, as the embedded code will contain object and/or embedded tags, which would be filtered out by the default filter in Drupal. If you want editors to have the ability to select their filter, you will need to enable that ability for a role, and possibly set up a new filter depending on your needs. Also note that you will need to disable the TinyMCE Rich Text Editor when embedding video directly into content if the TinyMCE module is enabled on your site. After submitting, your video will appear in the content. As with any HTML embedded in your node body, you may manually place your video at any point within the content such as after the second paragraph or at the end of the node: Embedded Embedded Media Field Finally, we come to the alternative of hosting video from our own servers. Although using a module such as Media Mover combined with services such as Amazon S3 makes serving video a slightly easier task than it might have otherwise been, for most sites the bandwidth required for serving video is generally not a viable option. Additionally, sites may wish to take advantage of the viral opportunities of hosting video through a widely recognized provider such as YouTube or Blip.TV. There are several modules that provide some limited support for embedding third-party media, including both the Video and Asset modules. However, at the time of this writing, the most comprehensive and by far the easiest to configure and use is the Embedded Media Field, which includes the Embedded Video Field as part of its package. Install both of these modules and set up a new content type with an Embedded Video Field. You will need, of course, to have the CCK (Content) module installed as well. As with our other examples, you will first add your type from Administer | Content management | Content types | Add content type (at /admin/content/types/add), give it a name such as Video, and add the field from Administer | Content management | Content types | Video | Add field (at /admin/content/node-type/video/add_field). Before continuing, I must confess a bias here. I wrote the original Embedded Media Field module with assistance from Sam Tresler during DrupalCamp NYC in 2007, and rewrote it for a more solid and flexible API during OSCMS later that year. I am also indebted to Alex Urevick-Ackelsberg for his assistance in the ongoing maintenance and support. Without doing anything else, you may now add a new video from a provider by simply pasting its URL into the field. The module will then automatically parse and display the video appropriately. There are several settings on the following page that may be set, including allowed providers, video and thumbnail sizes, and whether the video plays automatically. You may leave the providers alone to allow content from any of them, or select only the providers you wish to allow editors and users to use The local checkbox is experimental at the time of this writing and may not actually be on the version you're reading. The module maintainers (myself included, of course) intend to hook into other APIs to provide better local video support without reinventing the wheel. That may or may not be ready by the time you read this book. The Custom URL provider is also used to experimentally support direct videos from any source available from an HTTP request, including your local server. It is not recommended for general use, as it would be easy to use that to unethically hotlink to videos from someone else's server. Hundreds of flying monkeys will hunt you down if you do that. Basically, always turn off support for that unless you have a specific (and moral) use for that feature. You can set video sizes in the next sections for full size and preview size video display. By default, videos will be displayed in full size. You can change the display to video preview or thumbnail at the display settings page, by browsing to Administer | Content management | Content types | Video | Display fields (at /admin/content/node-type/video/display). Videos will be forced to display at the size provided here, regardless of how they are offered by the provider. You can also determine if the video will autoplay or not. For instance, you might use a small video preview for teasers and a larger full-size video when viewing the node page, turning on the autoplay in that case. Finally, you may wish to use thumbnails, for instance when displaying a video as a teaser or when using views. Note that thumbnails are not yet supported for all video providers. Some providers do not offer an easy API to discover a particular video's thumbnail file. To learn if thumbnails are supported by a particular provider, go to Administer | Content management | Embedded Media Field Configuration (at /admin/content/emfield) and open the fieldset for Embedded Video Field. You will see the supported features for each provider within their particular fieldsets, where you may also disable them or enable unique settings. You may wish to provide for custom thumbnails, whether for providers lacking an automatic thumbnail or for any external video in general. For this purpose, the Embedded Custom Thumbnail module is included in the module's package. Just enable that module, and then check the Allow custom thumbnails for this field box on the type's administration screen We now have a full-featured video field in place, which is as easy to use as cut and paste. Summary Video is still a maturing media on the Internet. Much has happened as it has exploded onto sites across the world, and contributors to Drupal have made recent strides in supporting it. However, there is still much to be done to make it easier for administrators to support it. Also, although there are many new and traditional tools available such as Views and Embedded Media Field, these still require some setup to get working.
Read more
  • 0
  • 0
  • 1641
Modal Close icon
Modal Close icon