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
All 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 & E-Commerce

830 Articles
article-image-add-tools-and-theming-tips-plone-3
Packt
16 Oct 2009
10 min read
Save for later

Add-on Tools and Theming Tips for Plone 3

Packt
16 Oct 2009
10 min read
(For more resources on Plone, see here.) Popular add-on Plone products One of the best things about open source development is the proliferation of products to solve common use cases. Plone themers are fortunate to have a solid set of tools available to them to solve these use cases. Enabling drop downs using webcouturier.dropdownmenu As most themers know, a lot of clients desire drop-down menus. In the past, this required coding HTML strings and the use of a product by Quintagroup named qPloneDropDownMenu. This product is still the recommended drop-down menu product for Plone 2.5x, but for 3.x, the real star is Denys Mishunov's product, webcouturier.dropdownmenu. The joy of this product is that you install it, and it works instantly. The product works by subclassing the globalsections viewlet via the following code, found in the browser/configure.zcml file of the webcouturier.dropdownmenu product: <!-- Override global sections viewlet --> <browser:viewlet name="plone.global_sections" manager="plone.app.layout.viewlets.interfaces.IPortalHeader" class=".dropdown.DropdownMenuViewlet" layer=".interfaces.IDropdownSpecific" permission="zope2.View" /> In the event that you've already customized your globalsections viewlet, you will have to subclass the DropdownMenuViewlet class in the webcouturier.dropdownmenu product. Unlike older drop-down menu products, webcouturier.dropdownmenu does not require any ongoing maintenance or manual adjustment of URLs. It is controlled by the navigation settings found in the Site Setup area, so you can control what types of items display in the navigation. The product also provides some basic CSS styling that can be easily adjusted in your own theme product, if desired. It can be downloaded here: http://plone.org/products/webcouturier-dropdownmenu/ Collage Another helpful Plone product is Malthe Borch's Collage. Collage allows you to create a grid containing rows and columns, and within those columns you can pull in the contents of other objects—a folder, a page, a collection, or even an image. Using this mechanism, you can create a complex page layout without knowing any programming. Until very recently, Collage did not have hooks that allowed it to be styled using CSS, and it did not respect different views. For example, if you created a special mysection_view.pt (same as a homepage_view), and you assigned that view to your page, Collage would default to the original document_view. This behavior has now been altered so that CSS hooks are available and different views are respected. This is a huge win for sites that are heavily styled and need to maintain consistency. It's suggested that when using Collage, you do not create your objects within the Collage itself; you should instead create the objects in your normal Plone content tree, and pull those items in as aliases. The reason for suggesting this is that it is not possible to access the contents of a Collage via the standard folder_contents view that is normally possible in a folder. Hence, if you need to move that content to another area of your site, you cannot. This also invites some jeopardy when migrating to a new version of Plone. It's worth mentioning that Collage will not become part of core Plone in the future, as the mechanism for organizing blocks of content on a page in the future will be accomplished via a new drag-and-drop mechanism. The lead programmer for Collage has stated, however, that there will be a migration path, but the reality of this is unknown. Finally, the usability of the Collage product is a bit clunky, but with some common sense, it's easy to use and can be a quite powerful layout tool for Plone 3. It can be downloaded here: http://plone.org/products/collage. Tableless styling using Plone Tableless A popular product for CSS purists is Simon Kaeser's plone.tableless. Plone's default main_template is created using tables, which many themers do not wish to use. To get a tableless version of Plone's main_template, simply install this product; make sure your site's portal_css is in debug mode, and test the following code: #portal-column-one {float:right;}#portal-column-two {float:left;} If you're able to switch the position of these two columns, the product works and you can style in full tableless mode. There are a few issues with Plone and tableless layouts that are unrelated to this product, but in general it works. As of this writing, the product was not tested against some of the newer browsers. It can be downloaded here: http://plone.org/products/plone-tableless/. CSSManager End users often want to have some control over basic modifications to their site—background color, link colors, and so on. The WebLion Group from Penn State University created CSSManager, a product that gives a simple, through the web interface to let users change the colors, borders, site logo, and other visual characteristics of their Plone site. Essentially, it uses the DTML variables defined in the base_properties.props file available within Plone. The product can be downloaded here: http://plone.org/products/cssmanager. To use it, install the product, go to your site's Site Setup area, and find the configlet for this tool, and try changing a few options. The CSSManager tool will supersede a theme product's base_properties if the CSSManager skin layer is above the theme product's skin layers in portal_skins/properties in the ZMI. If uninstalled, your settings can still be found in the custom folder for your Plone site via this URL: http://localhost:8080/mysite/portal_skins/custom/base_properties/manage_propertiesForm. So you can feel confident removing it if you no longer need it. Products.EasyAsPiIE Until IE7, there was no fully native support for PNG alpha channel transparency in Internet Explorer. However, since IE5.5, there has been some support in the form of a proprietary filter called AlphaImageLoader. Internet Explorer filters can be applied directly in your CSS (for both inline and background images), or by setting the same CSS property with JavaScript. Unfortunately, there's no CSS property called filter in the W3C CSS spec. It's a proprietary extension added by Microsoft that could potentially cause other browsers to reject your entire CSS rule. Also, AlphaImageLoader does not magically add full PNG transparency support so that a PNG in the page will just start working. Instead, when applied to an element in the page, it draws a new rendering surface in the same space that element occupies and loads a PNG into it. If that sounds weird, it is. However, by and large the result is that PNGs with an alpha channel can be accommodated. The WebLion Group's Products.EasyAsPiIE product uses this filter approach to handle transparent PNGs with IE6. All it does is enable JavaScript written by Angus Turnbull: http://www.twinhelix.com. You can download it from here: http://plone.org/products/productseasyaspiie/ and follow the installation instructions. Optionally, if you choose not to use this product, you can also just export to PNG8 format, instead of PNG24, to get around IE6 problems, and of course there are a lot of alternative solutions out there as well. You can read more about PNGs here: http://www.sitepoint.com/blogs/2007/09/18/png8-the-clear-winner/. Both Photoshop and Fireworks can export to PNG8, though other graphical programs may not. collective.skinny Another Plone product that has surfaced is Daniel Nouri's collective.skinny, which can be downloaded from http://plone.org/products/collectiveskinny/. This product is an example implementation of a separate, public-facing skin that abstracts away some of the complexity of the theming process. According to the product page, it's been described as being vastly easier than skinning Plone the conventional way, but it also has a few drawbacks. For example, you can't use it for community sites where people other than your site editors log in and modify content. It's also a little confusing from my perspective, but it's a product adventurous themers might pay attention to. It's probable that Deliverance and collective.xdv (the future of theming for Plone) will make this product obsolete, as Deliverance removes a lot of complexity and makes theming accessible to individuals who don't even know what Plone is. FS Dump For themers who started their skin creation through the web or who have content they wish to extract from the ZMI, FS Dump is an excellent tool. To use it, download the product from http://www.plone.org/products/fsdump and follow the installation instructions. This is a product that lives in the Products namespace, so it is not installed like egg-based products. Once installed, use the Add drop-down menu, found at http://www.mysite.com/manage_main, and create a Dumper instance in a folder (or product) that contains the TTW code to be dumped. This tool appears to work best when trying to dump items from the custom/ folder, though, hypothetically, it should work for any other folder in the ZMI. Next, supply an absolute path to a directory on the filesystem in which the dumper is to create the files, for example /opt. (Note that the user for whom Zope is running needs write access to this directory.) Click the Change and Dump button to do the dump to the indicated directory, and then copy the dumped files into your theme product's skins/ folder in the appropriate locations. qPloneSkinDump Another popular dumper product is known as Plone Skin Dump (qPloneSkinDump) by Quintagroup. Plone Skin Dump allows users to create a Plone product in the Products namespace by exporting the custom/ folder. It creates an old-school Plone theme product for you, but it does not provide the plonetheme-type of product. The product has not been tested against Plone 3, so it may not be the best option. Moreover, at the time this article was written, it was not possible to download the product from its SourceForge repository. In the event you wish to try this product, you can find it here: http://plone.org/products/plone-skin-dump. Again, it is in the Products namespace, so all you need to do is drop it in your buildout's products/ folder. You can then follow the directions posted on the product page. It's a bit more complicated than FS Dump, but obviously it does a bit more. Collection and static portlets While portlets are not add-on products, they are tools that can greatly enhance the impact of your site and worth mentioning. Default Plone provides collection and static portlets that can be added on any page by clicking on the Manage Portlets link on your site. These portlets provide great power and can be styled using CSS. A collection portlet, for example, can be set to display random contents fitting certain criteria—maybe a randomized spotlight content type tagged with a special keyword. This keeps the look and feel of a site fresh and gives some power to the end user. These portlets have the same structure as other portlets, so they will use any default styling that may be applied.
Read more
  • 0
  • 0
  • 1419

article-image-managing-content-through-tagging-grails-part-1
Packt
16 Oct 2009
9 min read
Save for later

Managing Content through Tagging in Grails: Part 1

Packt
16 Oct 2009
9 min read
Add basic tagging Tagging is a loose, community-based way of categorizing content. It allows a group of people to categorize by consensus. Anyone is able to tag a piece of content. The more a tag is used, the more meaning it takes on and the more widely used it becomes. This categorization by consensus has been dubbed as folksonomy (http://en.wikipedia.org/wiki/Folksonomy) So let's get started by building our tagging support. Tagging domain model When implementing tagging in our system, we need to consider the following: We must be able to have many tags in our system We must be able to associate a single tag with many different files and messages We need to make sure that new domain objects can be easily tagged without having to change the tagging logic We want to know when a domain object was tagged To satisfy these requirements, we need to create the following new domain classes: Tag—to store the name of the tag. There is one instance of this class per unique tag name in the application. Tagger—to store the relationship from domain objects to a tag. This allows us to store the date a tag was added to a domain object. Let's create these domain classes and then write a test to prove that we can tag a message using this tagging structure. The Tag class We are going to separate the tagging classes out from our application domain classes. Create a folder under grails-app/domain called tagging. This is where we will put the domain model to implement tagging. Our Tag class is extremely simple and holds only a name property: package taggingclass Tag { String name static constrains = { name( blank: false ) } } The Tagger class The next class that we are going to create is the Tagger class. In relational terms, this object represents a link table between a Tag and any other domain class. It is important that the relationship between tagged domain classes and the Tagger relationship class is unidirectional. By this, we mean the domain classes are allowed to know that they can be tagged, but tags do not know which domain classes can be tagged, otherwise every tagged domain class would need a special relationship class. Create the Tagger class as a domain class in the tagging package as follows: package taggingclass Tagger { Tag tag static constraints = { tag( nullable: false ) }} The basics of our tagging model are complete! We now need some logic to allow tags to be created. Create a new service class called TagService under grails-app/services/tagging, as shown below: package taggingclass TagService { boolean transactional = true def createTagRelationships(String spaceDelimitedTags) { return spaceDelimitedTags?.split(' ')?.collect { tagName -> createTagRelationship( tagName ) }}def createTagRelationship(String tagName) {def tag = Tag.findByName(tagName)?: new Tag(name: tagName).save()return new Tagger( tag: tag )} This service provides two utility methods to create new relationships by tag name or by a space delimited string of tag names. The important behavior of these two methods is that they do not allow duplicate tags to be created in the application. If a tag name already exists, the tag will be retrieved from the database and used as the tag in the relationship. Notice that the createTagRelationships method is using the collect method to simplify what would normally take a few more lines of code to achieve. The collect method is dynamically added to any object that can be iterated over. For example, collections, arrays, strings and so on. It takes a closure as its argument and executes this closure for each item in the collection. The return value from each execution of the closure is added to a new collection that the collect method builds up and then returns once it has finished iterating the original collection. In createTagRelationship, we are using another neat language feature of Groovy called the "Elvis operator". It is named so, as it looks like Elvis' hair style. This is a shorter version of the normal Java ternary operator. If the operand being checked is true then the checked operand will be returned as the default, otherwise the alternative operand will be used. So in our example:     def tag = Tag.findByName(tagName) ?: new Tag(name: tagName).save() If a tag can be found from the database then it is used, otherwise a new tag is created. Tagging a message The next step is to allow a message to be tagged. Write some integration tests to make sure the relationships are working before using tagging in the application. In the folder test/integration/app, create the file TaggableIntegrationTests.groovy and add the following code: package appimport tagging.Tagclass TaggableIntegrationTest extends GroovyTestCase { User flancelot protected void setUp() { flancelot = User.findByUsername('flancelot') Tag.list().each { it.delete() } Message.list().each { it.delete() } }} The code above sets up the test data needed to create messages and associate tags to messages. Remember that the flancelot user already exists because it was created by the BootStrap class. The first test will determine that we can add tags to a message and then retrieve messages by tag. Add the following test method to your test class: void testCanRetrieveMessagesByTags() { Message message = new Message(user: flancelot, title: 'tagged', detail: "I've been tagged.").save(flush: true) Message secondMessage = new Message(user: flancelot, title: 'other tagged', detail: "I've been tagged.").save(flush: true) message.addTag('urgent') message.addTag('late') secondMessage.addTag('urgent') def taggedMessages = Message.withTag( 'urgent' ) assertEquals(2, taggedMessages.size()) assertEquals(2, Tag.list().size()) def secondMessages = Message.withTag( 'late' ) assertEquals(1, secondMessages.size()) assertEquals(2, Tag.list().size())} The test above does the following: Creates two new messages Adds the urgent tag to both messages Adds the late tag to one message Checks if we can retrieve both messages by using the urgent tag Checks if only one message is returned for the late tag Notice that the highlighted lines of code have not been implemented yet. To allow this test to pass, we need to add the following methods to the Message domain class: addTag—instance method to allow a message to be tagged withTag—class method to retrieve all messages with a particular tag Add the following method to the Message class (don't forget to import tagging.Tagger): def addTag(String tagName) { tags = (tags)?:[] tags << tagService.createTagRelationship( tagName )} This method simply delegates the creation of the tag relationship off to the TagService class, and then stores the relationship in the tags list. Add the following method to the Message class that retrieves all messages with a given tag name: def static withTag(String tagName) { return Message.withCriteria { tags { tag { eq('name', tagName ) } } }} This method must be static on the Message class, as it is used to load message instances for a given tag. We do not want to have to instantiate a message before we can perform the search. Before running the test, you will notice both of these new methods assume that there is a property on the Message class called tags. This has not yet been created. We need to create a one-to-many relationship from Message to Tagger that will allow messages to be tagged. We also need to inject the TagService into new instances of the Message class so the work for creating a new tag relationship can be delegated. Add the relationship to the Message class and inject TagService as shown below: class Message { def tagService static hasMany = [tags:Tagger] ...} Now we can run our tests by entering the following on the command line: grails test-app We should see some output in the command line similar to: Running test app.TaggableTest... testCanRetrieveMessagesByTags...SUCCESS Tagging a file Now that we have implemented tagging for messages, we need to make tagging available for files. Currently the logic for creating and fetching tags is in the Message domain class. We need to extract this logic so the File domain class can reuse it. It's time to look at how GORM supports inheritance. GORM inheritance The GORM supports inheritance of domain classes by default through the underlying Hibernate framework. Hibernate has a number of strategies for handling inheritance and Grails supports the following two: Table-per-hierarchy—this strategy creates one database table per inheritance hierarchy. This is the default strategy in Grails. Table-per-subclass—this strategy creates a database table for each subclass in an inheritance hierarchy and treats the inheritance (is a) relationship as a foreign key (has a) relationship. Taking our domain as an example, we have two classes. They are Message and File. We are going to make them both extend a super class Taggable, which will handle all of our tagging logic and state. Table-per-hierarchy If we were to choose the table-per-hierarchy strategy, we would end up with one table called Taggable that contained the data for both Message and File. The database structure would look something like: The interesting side-effect of this approach is that all of the fields to be persisted must be nullable. If a File is created and persisted, it is obviously not possible for the fields from Message to be populated. Table-per-subclass By using the table-per-subclass strategy, we would keep two separate tables called Message and File, and both would have the tags relationship inherited from Taggable. So the Message table will look like: We can see in the diagram above that the Message and File tables have remained separate and a table representing the superclass Taggable has been created, which the subclass tables have foreign key relationships to. In the table-per-subclass strategy, a table must exist to represent the inheritance (is a) relationship. We are going to follow the table-per-subclass strategy so that we can retain database level data integrity. The default behavior for GORM is to use the table-per-hierarchy strategy. To override this we must use the mapping property: static mapping = { tablePerHierarchy false}
Read more
  • 0
  • 0
  • 1413

article-image-joomla-15-template-reference-part-1
Packt
16 Oct 2009
2 min read
Save for later

Joomla! 1.5 Template Reference: Part 1

Packt
16 Oct 2009
2 min read
  Take note that we'll see how these Joomla! 1.5 items differ in use from a Joomla! 1.0 template, so that those of you looking to update a Joomla! 1.0 template to 1.5 can quickly get a handle on what to update in your templates and what new features to add. Consider this article your "cheat sheet". Jdoc include tags The jdoc include tags are new to Joomla! 1.5 templates. Previously in Joomla! 1.0, more complicated, abstract PHP code, originally created for Mambo, was used. The jdoc tags are much cleaner, visually make sense (no more guessing what attribute values like "-3" mean), and, thus, are much easier to remember. Site header information tag This is pretty simple: the tag outputs all the appropriate meta tags and header information that corresponds to your site and each individual page: <jdoc:include type="head" /> Joomla! 1.0 to 1.5 conversion If you're converting a 1.0 template to 1.5, you'll replace this PHP function in your 1.0 template's header with the above jdoc tag: <head>...<?php mosShowHead(); ?>... The component include tag Wherever you place this include, all component content will appear (from articles to poll results to contact forms, and so on): <jdoc:include type="component" /> Joomla! 1.0 to 1.5 conversion The 1.0 equivalent of this tag is the mosMainBody function. You'll replace this PHP function with the above jdoc include: <?php mosMainBody(); ?> Module position tags With module tags, we have a few options to work with. So, we can control what modules load into the area, thus assigning their positions as well as what style to output the module content with: <jdoc:include type="modules" name="position" style="styleName" /> Module position styles In the jdoc include example above, within the style attribute, you can place one of the following six style names to various effect:
Read more
  • 0
  • 0
  • 1163
Visually different images

article-image-joomla-15-template-reference-part-2
Packt
16 Oct 2009
4 min read
Save for later

Joomla! 1.5 Template Reference: Part 2

Packt
16 Oct 2009
4 min read
Common Joomla! CSS As you can see, via template overrides, you can pretty much define any CSS ids or classes you want. For those of you who are into creating and tweaking template overrides, unless you're going to create a highly custom, private, not-for-the-public template, my recommendation is you continue to use Joomla's general CSS ids and classes for component and module output as much as possible. This is a good way to ensure your template is familiar to other Joomla! administrators, especially if you want to offer your template to the public or for commercial sale. It's easy for them to look up and customize CSS rules rather than forcing them to discover all the new and interestingly-named CSS ids and classes you created. For those of us working with Joomla's core output or the Beez template overrides (which attempts to use Joomla's standard CSS), here is a list of some of the most common CSS ids and classes. Those of you familiar with Joomla! 1.0 template design will be pleased to find these haven't really changed. This list has been put together after a bit of research and a lot of experimentation with the Web Developer Toolbar CSS tools. It is probably not complete, but if you account for these items in your CSS rules, you'll be pretty well covered for most Joomla! projects, and it will be easy to spot any ids or classes not covered here and add them to your CSS sheet. The Joomla.org forum has a post with a fairly comprehensive list, most of which you'll recognize here, so it's definitely worth checking out: http://forum.joomla.org/viewtopic.php?t=125508. Joomla! 1.5 CSS ids #active_menu This is generated by the type="modules" include. Use it to style and control the currently selected main menu item. #blockrandom This is generated by the type="component" include when you're using the wrapper. This is the iFrame's id. #contact_email_copy This is generated by the type="component" include when you're in the contact form page view. This is a field name id. #contact_text This is generated by the type="component" include when you're in the contact form page view. This is a field name id. #emailForm This is generated by the type="component" include when you're in the contact form page view. This is a field name id. #mainlevel This is generated by the type="modules" include. Use it to style and control the main menu div holding each main menu item. #mod_login_password This is generated by the type="modules" include. This is a field name id. #mod_login_remember This is generated by the type="modules" include. This is a field name id. #mod_login_username This is generated by the type="modules" include. This is a field name id. #poll This is generated by the type="modules" include by the poll module. You can control the placement of the entire id with this. #search_ordering This is generated by the type="component" include when you're in the search form page view. This is a field name id. #search_searchword This is generated by the type="component" include when you're in the search form page view. This is a field name id. #searchphraseall This is generated by the type="component" include when you're in the search form page view. This is a field name id. #searchphraseany This is generated by the type="component" include when you're in the search form page view. This is a field name id. #searchphraseexact This is generated by the type="component" include when you're in the search form page view. This is a field name id. #voteid1,#voteid2,#voteid3, and so on This is generated by the type="modules" include. This is generated by the poll module and are field name ids for the radio buttons.    
Read more
  • 0
  • 0
  • 1027

article-image-managing-and-enhancing-multi-author-blogs-wordpress-27part-1
Packt
16 Oct 2009
18 min read
Save for later

Managing and Enhancing Multi-Author Blogs with WordPress 2.7(Part 1)

Packt
16 Oct 2009
18 min read
Creating an author page template If you have different authors on your blog, then my suggestion to you would be to display the biographical and contact information of each author on his own dedicated page. Luckily, WordPress allow us to do just that. Getting ready In this recipe, we're going to create an author page template for the purpose of displaying author related information. Make sure that you have understood the creation and usage of a page template. How to do it Create a new file named authors.php on your WordPress theme directory. Insert the following code into your file named authors.php: <?php/*Template Name: Authors Page*/?><?php get_header(); ?><div id="content" class="narrowcolumn"><?phpif(isset($_GET['author_name'])) :$curauth = get_userdatabylogin($author_name);else :$curauth = get_userdata(intval($author));endif;?><h2>About <?php echo $curauth->nickname; ?></h2><div class="excerpt"><?php echo $curauth->nickname; ?> personal website:<a href="<?php echo $curauth->user_url; ?>"><?php echo $curauth->user_url; ?></a></div><?php echo $curauth->user_description; ?><h2>Latest posts by <?php echo $curauth->nickname; ?>:</h2>Chapter 6133<ul><?php if ( have_posts() ) : while ( have_posts() ) :the_post(); ?><li><a href="<?php the_permalink() ?>"><?php the_title();?></a> on <?php the_time('d M Y'); ?></li><?php endwhile; else: ?><p><?php _e('No posts by this author.'); ?></p><?php endif; ?></ul></div><!--/content--><?php get_sidebar(); ?><?php get_footer(); ?> Save the file and upload it to the wp-content/themes/yourtheme folder of your WordPress install. Log in to your WordPress dashboard, create a new page, and select the Authors Page as a page template. Give it the title of your choice, such as, About the Author and publish the page. Open the single.php file from your theme. Depending on the theme that you're using, you may need to add the following code in order to display the author's name and a link to the author's page: Posted by <?php the_author_posts_link(); ?> Once you have saved the modifications made in your single.php file, visit one of your blog posts and click on the author name. The author page is displayed showing the author name, description, and web site. How it works The first thing that we need to know is the name of the author whose information is to be displayed. To do so, we have to get the author_name parameter sent via the GET method. With this value, we can initialize a $curauth php object that will allow us to get some personal information about the author, such as his web site, email, biography, and so on, with the help of the classic php syntax, that is, $curauth->nickname;. Once the author data, that is to be displayed, has been retrieved, we shall add a WordPress loop in order to be able to view the recent posts by this author. The following screenshot shows a well-prepared author page: There's more... In the preceding example we retrieved the author name, description, and web site URL. However, as you may know, users can provide much more information (in Administration, Profile, Your Profile options) such as their email address, AIM and Yahoo! messenger nickname, and login information. A few more template tags can be used to retrieve another kind of information from the author data. These tags are listed under the There's more! section of Displaying author-related information on posts, which we will see later in this article. Displaying a custom login form in your blog's sidebar It doesn't matter whether you're running a multi-author blog, or a blog where readers can register. Having a login form embedded in your sidebar will make your blog look a lot more professional and user friendly. Here is what you can expect from this recipe. In the following screenshot, a login form has been added to the K2 theme sidebar. Getting ready To achieve this recipe, you'll have to edit the sidebar.php file from your theme. The following hack works with WordPress 2.0 to 2.8. How to do it Open the sidebar.php file for editing. Find the opening <ul> tag and paste the following code under it: <li><?php global $user_ID, $user_identity, $user_level ?><?php if ( $user_ID ) : ?><h2><?php echo $user_identity ?></h2><ul><li><a href="<?php bloginfo('url') ?>/wp-login.php?action=logout&amp;redirect_to=<?php echo urlencode($_SERVER['REQUEST_URI']) ?>">Logout</a></li></ul><?php elseif ( get_option('users_can_register') ) : ?>Managing and Enhancing Multi-Author Blogs136<h2>Identification</h2><ul><li><form action="<?php bloginfo('url')?>/wp-login.php" method="post"><p><label for="log"><input type="text" name="log"id="log" value="<?php echo wp_specialchars (stripslashes($user_login), 1) ?>" size="22" /> User</label><br /><label for="pwd"><input type="password"name="pwd" id="pwd" size="22" /> Password</label><br /><input type="submit" name="submit" value="Login"class="button" /><label for="rememberme"><input name="rememberme"id="rememberme" type="checkbox" checked="checked"value="forever" /> Remember me</label><br /></p><input type="hidden" name="redirect_to" value="<?php echo$_SERVER['REQUEST_URI']; ?>"/></form></li><li><a href="<?php bloginfo('url')?>/wp-register.php">Register</a></li><li><a href="<?php bloginfo('url') ?>/wp-login.php?action=lostpassword">Recover password</a></li></ul><?php endif ?></li> Save the file. Your users can now login directly from your blog's sidebar. How it works The working of this code is quite simple. First, you initialize the global variables to get the user ID, name, and level. Then, you check the value of the $user_ID variable. If the value is not null, which means that the current user is logged in, you then display a quick hello user text and a link to log out. If the user isn't logged in, you check whether registering is allowed on the blog. If the user is logged in, then you simply display an HTML form that allows the user to log in directly from the blog. A link has also been included for registration if the current user doesn't have an account yet. This code was inspired from a tutorial available at www.wpdesigner.com. Adding a control panel to your blog's sidebar Now that you have learned how to check whether a user is logged in or not, why not learn how to add a small control panel to your blog's sidebar that is only visible to the logged in users. In this recipe, you'll learn how to achieve this task. Getting ready The upcoming piece of code works in exactly the same way as the code from the previous recipe does. It is all about checking if the user is logged in and whether he or she has the right to do a certain kind of thing. The following screenshot shows a simple, but useful, control panel which is similar to the one we're about to create: How to do it Open sidebar.php for editing. Find the first opening <ul> HTML tag, and paste the following code under the <ul> tag: <li><?php global $user_ID, $user_identity, $user_level ?><?php if ( $user_ID ) : ?><h2>Control panel</h2><ul><li>Identified as <strong><?php echo $user_identity ?></strong>.<ul><li><a href="<?php bloginfo('url') ?>/wp-admin/">Dashboard</a></li><?php if ( $user_level >= 1 ) : ?><li><a href="<?php bloginfo('url') ?>/wp-admin/post-new.php">Write an article</a></li><?php endif; ?><li><a href="<?php bloginfo('url') ?>/wp-admin/profile.php">Profile and personal options</a></li><li><a href="<?php bloginfo('url') ?>/wp-login.php?action=logout&amp;redirect_to=<?php echourlencode($_SERVER['REQUEST_URI']) ?>">Logout</a></li><?phpif (is_single()) {?><li><a href="<?php bloginfo('wpurl');?>/wp-admin/edit.php?p=<?php the_ID(); ?>">Edit Post</a></li><?php } ?></ul></li></ul><?php endif; ?></li> Once you are done, save the file. The allowed users can now go to their dashboard, edit their profile, or write a new post directly from the blog. How it works As mentioned earlier, this code works in the same way as the code that was used to create a login form in the sidebar. After you've made sure that the $user_ID variable isn't null, you work towards displaying the options available to the user. It is possible to define what a user can perform according to his role (administrator, author, contributor, subscriber, and so on). We're going to have a look at this in the next recipe. There's more... Now that you have learned how to add a control panel to the blog's sidebar, let's go ahead and try out something new. Adding a login form and a control panel Now that you know how to add a login form and a mini control panel to your blog's sidebar, why not try mixing the two codes? If the user isn't logged in, we'll display the login form. Otherwise, the custom panel will be shown to the user. The code below works in the same way as the two that we studied previously. Add the following code to the sidebar.php file of your theme: <li><?php global $user_ID, $user_identity, $user_level ?><?php if ( $user_ID ) : ?><h2>Control panel</h2><ul><li>Identified as <strong><?php echo $user_identity ?></strong>.<ul><li><a href="<?php bloginfo('url') ?>/wp-admin/">Dashboard</a></li><?php if ( $user_level >= 1 ) : ?><li><a href="<?php bloginfo('url') ?>/wp-admin/post-new.php">Write an article</a></li><?php endif; ?><li><a href="<?php bloginfo('url') ?>/wp-admin/profile.php">Profile and personal options</a></li><li><a href="<?php bloginfo('url') ?>/wp-login.php?action=logout&amp;redirect_to=<?php echo urlencode($_SERVER['REQUEST_URI']) ?>">Logout</a></li><?phpif (is_single()) {?><li><a href="<?php bloginfo('wpurl');?>/wp-admin/edit.php?p=<?php the_ID(); ?>">Edit Post</a></li><?php } ?></ul></li></ul><?php elseif ( get_option('users_can_register') ) : ?><h2>Identification</h2><ul><li><form action="<?php bloginfo('url') ?>/wp-login.php"method="post"><p><label for="log"><input type="text" name="log" id="log" value="<?php echo wp_specialchars(stripslashes($user_login), 1)?>" size="22" /> User</label><br /><label for="pwd"><input type="password" name="pwd" id="pwd"size="22" /> Password</label><br /><input type="submit" name="submit" value="Login"class="button" /><label for="rememberme"><input name="rememberme" id="rememberme" type="checkbox" checked="checked"value="forever" /> Remember me</label><br /></p><input type="hidden" name="redirect_to" value="<?php echo$_SERVER['REQUEST_URI']; ?>"/></form></li><li><a href="<?php bloginfo('url') ?>/wp-register.php">Register</a></li><li><a href="<?php bloginfo('url') ?>/wp-login.php?action=lostpassword">Recover password</a></li></ul><?php endif; ?></li> The custom logging form for unregistered users will look similar to the following screenshot: And the control panel for logged in users will look similar to the following screenshot: Configuring author roles Now that you have learned about the different aspects of the user's roles and capabilities, there's probably something that you're finding a little frustrating. By default, you can't configure author roles to fit your blog's needs. For example, a contributor can't upload images. Moreover, by default, you can't change it. Luckily, there's a plugin called Role Manager which allows you to configure author roles in the way that you want. Getting ready The Role Manager plugin can be found at the following link: http://www.im-web-gefunden.de/wordpress-plugins/role-manager/ Download it, unzip it onto your hard drive, and install it as any other WordPress plugin. How to do it Once the Role Manager plugin is installed, log in to your WordPress dashboard and go to Users | Roles. A list of all of the available user roles will be displayed. For each role you can define what the user can do. For example, you can choose to let a contributor upload images. What is even better is that you're not limited to the 5 default user roles that are provided by WordPress. The Role Manager plugin allows you to create new roles, as well as the ability to rename, copy, or delete existing ones. How it works The job of the Role Manager plugin is pretty easy. It simply creates custom roles with the options that you have defined and save it on the WordPress database. There's more... Now that we have configured the author roles, let's learn how to control the author's actions. Controlling what authors can do Even if your blog is powered by multiples authors, it is still your blog. Therefore, you shouldn't allow every author to have the right to edit posts or delete comments. Since version 2.0, WordPress features user roles. User roles are defined as a group of actions that can be accomplished by a specific range of users. For example, the administrator can edit theme files, but the subscribers can't. User roles and their capabilities Here are the 5 predefined roles for WordPress users: Administrator: The administrator is the blog owner. He has unlimited access to all of the administration features such as writing posts, editing his own posts along with the posts from other authors, installing plugins, selecting a new theme, editing themes, and editing plugin files. Editor: The editor can write or publish posts, upload images, edit his own posts, and manage other's posts. Author: The author can write, publish, and edit his own his own posts. He's also allowed to upload images for use in his posts. Contributor: A contributor can write posts but can't publish them himself. Once he has written a post, the post is pending approval from the administrator. The contributor can't upload images either. This role is very good for guest authors on your own blog. Subscriber: A subscriber is a registered user of your blog, but can't write posts. For an exhaustive description of user roles and capabilities, you should read the related page in WordPress Codex: http://codex.wordpress.org/Roles_and_Capabilities. Controlling what users can see in your theme In the previous example, we built a sidebar control panel that allows the user to edit the current post. However, the code doesn't let you control which kind of author is allowed to edit the current post. For now, even if only the users with a sufficient role level will be capable of editing the post, every logged in user can see the related link. The solution to that problem is a built-in WordPress function, called current_user_can(). As an argument, this function takes a string describing the action or the required role level to perform a specific task. For example, the following code will provide a link to edit the current post to the administrators only: <?phpif (current_user_can('level_10')){ ?><a href="<?php bloginfo('wpurl');?>/wp-admin/edit.php?p=<?php the_ID(); ?>">Edit Post</a><?php } ?> The current_user_can() function accepts user_0 to user_10 as a parameter. Here is the conversion table between the role levels and the roles: Suscriber: level_0 Contributor: level_1 Author: level_2 to level_4 Editor: level_5 to level_7 Administrator: level_8 to level_10 The current_user_can() function can also be used with a specific action as a parameter. This is the recommended use, as the level parameter is becoming obsolete. The following example checks if the current user can edit a post he previously published. If yes, then a link to edit the post will be displayed. <?phpif (current_user_can('edit_published_posts')){ ?><a href="<?php bloginfo('wpurl');?>/wp-admin/edit.php?p=<?php the_ID(); ?>">Edit Post</a><?php } ?> Here are all of the arguments that are accepted by the current_user_can() function:      switch_themes      edit_themes      activate_plugins      edit_plugins      edit_users      edit_files      manage_options      moderate_comments      manage_categories      manage_links      upload_files      import      unfiltered_html      edit_posts      edit_others_posts      edit_published_posts      edit_pages      edit_others_pages      edit_published_pages      edit_published_pages      delete_pages      delete_others_pages      delete_published_pages      delete_posts      delete_others_posts      delete_published_posts      delete_private_posts      edit_private_posts      read_private_posts      delete_private_pages      edit_private_pages      read_private_pages      delete_users      create_users      unfiltered_upload      edit_dashboard      update_plugins      delete_plugins Displaying author-related information on posts In a multi-author blog, it's always good for the reader to know the author of the article that they're currently reading. It's even better if they can grab some extra information about the author, such as his website, a short bio, and so on. In this recipe, you'll learn how to edit your single.php theme file to automatically retrieve the author-related information, and display it at the top of the page. Getting ready As we're going to display author information on posts, the first thing to do is to make sure that your contributing authors have entered their biography and other information into the WordPress database. Any author can enter his information by logging in to the WordPress dashboard, and then going to Profile. The blog administrator can edit all of the profiles. The following screenshot shows the WordPress 2.7 profile editor for the authors. How to do it Once you have made sure that your authors have successfully filled their information, you can start coding by carrying out the following steps: Open the file single.php for addition. Paste the following code within the loop: <div id="author-info"><h2>About the author: <?php the_author();?></h2><?php the_author_description(); ?><?php the_author();?>'s website: <a href="<?php the_author_url();?>"><?php the_author_url(); ?></a><br />Other posts by <?php the_author_posts_link(); ?></div><!--/author-info--> Save the file and visit your blog. You will notice that your posts now automatically display the author-related information, as shown in the following screenshot: How it works WordPress provides a dozen of author-related template tags, which are an easy way to retrieve information that is entered by authors in their profile. Note that all of these tags must be used within the loop for them to work. There's more... Here are all the available template tags related to authors:
Read more
  • 0
  • 2
  • 2263

article-image-views-urls-and-generic-views-django-10
Packt
16 Oct 2009
19 min read
Save for later

Views, URLs, and Generic Views in Django 1.0

Packt
16 Oct 2009
19 min read
An overview Views are at the heart of Django and hold most of your application logic. They are nothing more than Python functions that take an HTTP request as input and return an HTTP response or error. A mechanism called the dispatcher identifies an incoming URL against a set of URL patterns and their associated view functions. When a match is found, the associated view is called and the request gets handled. Since many views follow a common strategy of loading an object or list, loading a template, rendering the template, and returning a response, Django offers a way of doing this without writing a view function. These generic views are called from the URL dispatcher and go right to the template. Creating the application Before we start looking at views and URLs, let's create a sample application to experiment with. Since most books and examples use blog models as their demos, let's keep things fresh by making our demo a press release application for a company website. The press release object will have a title, body, published date, and author name. Create the data model In the root directory of your project (in the directory projects/mycompany), create the press application by using the startapp command: $ python manage.py startapp press This will create a press folder in your site. Edit the mycompany/press/models.py file: from django.db import modelsclass PressRelease(models.Model): title = models.CharField(max_length=100) body = models.TextField() pub_date = models.DateTimeField() author = models.CharField(max_length=100) def __unicode__(self): return self.title Create the admin file To take advantage of the automatic admin interface that Django gives us, we need to create a file called an admin file. Create a file called admin.py in the mycompany/press directory, adding these lines: from django.contrib import adminfrom mycompany.press.models import PressReleaseadmin.site.register(PressRelease) If you've used Django before version 1.0, this step is new. The admin configuration directives were taken out of the model and put into their own files starting in version 1.0. Add the press and admin applications to your INSTALLED_APPS variable in the settings.py file: INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.admin', 'django.contrib.contenttypes', 'djan?go.contrib.sessions', 'django.contrib.sites', 'mycompany.press',) In the root directory of your project, run the syncdb command to add the new models to the database: $ python manage.py syncdb Because we have Django's authentication system listed as one of our installed applications, the initial syncdb process will ask us if we want to create a superuser. Go ahead and create a superuser account; you will be using it later to access the admin site. Configure the URLs Finally, edit the mycompany/urls.py file: from django.conf.urls.defaults import *from django.contrib import adminadmin.autodiscover()urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root),) Add data in the admin application By adding django.contrib.admin to our INSTALLED_APPS setting and creating a URL mapping for it, we can access the admin site by browsing to http://localhost:8000/admin/. Go into the admin app and add two or three press releases so that we have some sample data to work with: Mapping URLs to views When Django accepts an incoming request, one of the first things it does is that it looks at the URL and tries to match it against a group of URL patterns. In order to identify patterns, Django uses regular expressions to see if the URLs follow a known format. Consider these URLs: http://localhost:8000/press/detail/1/ http://localhost:8000/press/detail/2/ These URLs appear to follow a pattern that they start with press/detail/ and end with a number that represents the ID of a press release. (Recall that we don't work with the domain name portion of the URL. Django takes care of this automatically for us and just sends us everything that follows the domain name.) With this pattern, we can add a new line to our mycompany/urls.py file: from django.conf.urls.defaults import *from django.contrib import adminadmin.autodiscover()urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root), (r'^press/detail/d+/$', 'mycompany.press.views.detail'),) If you're not familiar with Python's regular expressions, this new line may look a bit wonky. This is the most important part: r'^press/detail/d+/$' It reads like this: "A string that starts with press/detail/ and ends with one or more digits followed by a slash". The second segment of the new line is the view function that will get called when an incoming URL matches this pattern. In this case, it will be a function called detail in the mycompany/press/views.py file. There's only one problem with this pattern—it recognizes that a number will be at the end of the URL, but doesn't do anything to pass that number to the view when it's called. We can use a Python regular expression group to capture that number: urlpatterns = patterns('', (r'^admin/', include('django.contrib.admin.urls')), (r'^press/detail/(?P<pid>d+)/$', 'mycompany.press.views.detail'),) This grouping syntax looks really funky, but it's easy to understand once you've seen it a few times. (?P ) is the Python syntax for a named group, which allows the regular expression to save the piece that matched, and put a label on it so that we can call it later. The <pid> part is where we assign the label of pid to the ID of the press release that was sent with the URL. In the case of this URL, the named group pid will be equal to 2: http://localhost:8000/press/detail/2/ Any named groups that we get from a URL are passed as arguments to our view function. In this example, our detail function in press/views.py will have a method signature like this: def detail(request, pid): p = PressRelease.object.get(id=pid) .. There are two keyword arguments to the detail function, request and pid. (Django automatically passes the keyword request, which we'll explore a little later.) Because we used a named group in the URL configuration to capture the press release ID, it's passed to our detail function as pid. You can use multiple named groups in your URL patterns to capture multiple pieces of information and pass them to your functions. Note: URL configurations and patterns are usually referred to as URLConf. Handling unmatched URL patterns URLs are matched up with view functions when they match patterns, but what happens when a match isn't found? This URL wouldn't match the patterns we created because it doesn't end in a number: http://localhost:8000/press/detail/abc/ In this case, the URL dispatcher wouldn't match against our pattern and would keep trying other patterns until a match is found. If no match is found, a 404 error is raised. If you have debug set to true (DEBUG=True) in your settings file, you'll see an error message like this: Splitting up the URL configurations We created the URL configurations for the press application in the mycompany/urls.py file. While this is perfectly acceptable, sticking all the configurations into the main urls.py file can get unwieldy for large projects with many applications. It also isn't very modular if we want to share applications with others or use applications that other people distribute. Instead of writing the press release configuration in our main mycompany/urls.py file, let's create a new file at mycompany/press/urls.py: from django.conf.urls.defaults import *urlpatterns = patterns('', (r'^detail/(?P<pid>d+)/$', 'press.views.detail'),) This looks very similar to what we already have, but note that we've dropped press from the beginning of the regular expression. This line will match URLs that start with detail. Open your mycompany/urls.py file and edit the highlighted line: from django.conf.urls.defaults import *from django.contrib import adminadmin.autodiscover()urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root), (r'^press/', include('mycompany.press.urls')),) We've changed the regular expression portion to match URLs that start with press/. If one is found, Django will hop over to the press/urls.py file to try to match the rest of the URL (without the press/ prefix). With this setup, we are telling Django that any URLs that start with press will be handled in a separate urls.py file in the press directory. Creating views Now that we're matching a URL to a view and passing it information, we can look at how a view is structured. Views have two rules you must follow: The view must accept the request object as its first argument. The view must return an HTTP response or an exception. Beyond this, just remember that a view is a standard Python function and you can do just about anything in it that you can do in a Python program. Accepting the request object Our first rule for views states that a view must accept the request object as its first argument. What is this request object? Django automatically creates the request object when a page is requested. It contains data about the incoming HTTP request such as the requestor's IP address, user agent, request method, cookies, GET parameters, POST parameters, and so on. Everything you should need to know about an incoming request will be found in this object. When you build your view functions, always specify request as the first keyword argument: def detail(request): # Python code here If you forget to add request as the first parameter, you'll know quickly because your view will fail to load with some kind of error message about the arguments (the exact error depends on what other keyword arguments you might be using). Responding with an HTTP response The second rule for views is that a view must return an HTTP response or an exception. Let's start by talking about what an HTTP response is. In order for a browser to understand how to render a web page, it looks at some special hidden information called headers, which is sent by the server along with the content or document being requested. These headers tell the browser information such as what kind of web server is sending the response, which version of the HTTP protocol is being used, how big the content is, and what kind of content is being sent. Luckily, we don't have to worry about most of this because the web server and Django take care of it for us. All we have to do is make sure we send the response out of our view using the HttpResponse method. In your mycompany/press/views.py file, add the following lines: from django.http import HttpResponsedef detail(request, pid): return HttpResponse('This is just a test.') Point your browser to http://localhost:8000/press/detail/1/. Here's what it should look like: Obviously, our views are going to be more complicated than this one, but it illustrates how simple they can be. Responding with an exception The second part of our rule said that the view can respond with an exception instead of an HTTP response. When Django encounters an error during the processing of a view, we usually want to return a friendly error message to the user to let them know something went wrong (as opposed to just sending back a blank screen). Usually, these error messages are in the form of 404 or 500 Error pages. 404 errors are also known as page not found errors. Anyone who has spent time surfing the Web has undoubtedly encountered a 404 Error page when clicking an old link that is no longer valid. In traditional HTML publishing, 404 errors popped up when the user requested a filename that wasn't found on the server (that's where the "page" in "page not found" comes from). With Django, we don't have URLs that represent filenames on the server, but we still return a 404 error when the user is looking for a resource that does not exist. Django makes it easy to return a 404 page by returning the error using the HttpResponseNotFound function: from django.http import HttpResponseNotFounddef detail(request, pid): return HttpResponseNotFound('Page Not Found') Similarly, requests that cause errors on the server are usually referred to as 500 errors. (500 is the standard HTTP response code for a server error.) Django also makes it easy to serve a 500 error: from django.http import HttpResponseServerErrordef detail(request, pid): return HttpResponseServerError('An Error Has Occurred.') Putting the views together Now that we know how a view works and what it needs to do, let's write the real view to work with our sample application. Building the basic view In your mycompany/press/views.py file, replace any contents with the following lines: from django.http import HttpResponsefrom django.http import HttpResponseNotFoundfrom mycompany.press.models import PressReleasedef detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' try: p = PressRelease.objects.get(id=pid) return HttpResponse(p.title) except PressRelease.DoesNotExist: return HttpResponseNotFound('Press Release Not Found') If you'd like to test it out, point your browser to http://localhost:8000/press/detail/1/. You should see the title of your press release. Change the number at the end of the press release to an ID that doesn't exist (such as 99) and you should get a Page Not Found error. This view doesn't return a very pretty output, but it follows the rule that the view must serve an HTTP response or an error/exception. The try/except error handling to make sure the press release exists is kind of ugly. Luckily, Django gives us a more elegant way of handling it. Cleaning up the error handling Instead of putting a try/except block around the object lookup, Django has a get_object_or_404 method that will automatically raise an error if the object is not found. Change the highlighted lines in your mycompany/press/views.py file: from django.http import HttpResponsefrom django.shortcuts import get_object_or_404from mycompany.press.models import PressReleasedef detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=pid) return HttpResponse(p.title) That's a much cleaner way of doing things! Note: If you're getting a list instead of an object, Django has a get_list_or_404 method that you can use. We'll see this in a few pages. Adding the template files The last thing we need to do is add a way to load up the response with the output of a rendered template. We're going to load a template file, replace placeholders in that file with our data (called "rendering" the template), and then return the contents of the template as a string as an HTTP response. We create a templates directory at mycompany/templates, and configured the settings.py file to tell Django where to find it: TEMPLATE_DIRS = ( '/projects/mycompany/templates/',) Verify that you have configured your project this way before continuing. With this setting in place, we can load templates relative to this path. Create a directory under the mycompany/templates directory called press. (It's common practice to use subdirectories to group template files by the application they are associated with.) Create a new file at mycompany/templates/press/detail.html and add these lines: <html><head><title>{{ press.title }}</title></head><body><h1>{{ press.title }}</h1><p>Author: {{ press.author }}<br/>Date: {{ press.pub_date }}<br/></p><p>{{ press.body }}</p></body></html> This simple template file has placeholders for our title, author, pub_date, and body fields. When the template is rendered, these placeholders will be replaced with their respective values. Now that we have a template, we can tell the view to use it. Adding the template to the view In our mycompany/press/views.py file, let's add a few lines to load our template. Replace the contents of your file with these lines: from django.http import HttpResponsefrom django.shortcuts import get_object_or_404from django.template import loader, Contextfrom mycompany.press.models import PressReleasedef detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=1) t = loader.get_template('press/detail.html') c = Context({'press': p}) rendered_template = t.render(c) return HttpResponse(rendered_template) In the function, we're retrieving the press/detail.html template file and creating a special data object called Context. So for now, just understand that it passes data to the template so that it can be rendered. The context object in this example passes our press release object to the template in a variable called press. Our template gets rendered into a string called rendered_template that is sent back to the browser via HttpResponse the same way we sent back simple lines of text in previous examples. The rendered_template variable was used for clarity. You can omit it and just return the response like this: def detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=1) t = loader.get_template('press/detail.html') c = Context({'press': p}) return HttpResponse(t.render(c)) Point your browser to the URL http://localhost:8000/detail/1/. You should see something like this depending on what you entered earlier into the admin site as sample data: Creating the list view and template In addition to displaying the detail for a specific press release, we'll also need a way to display a list of press releases. The steps to add this will be very similar to what we just did to add our detail view. In your mycompany/press/views.py file, add the highlighted lines: from django.http import HttpResponsefrom django.shortcuts import get_object_or_404from django.shortcuts import get_list_or_404from django.template import loader, Contextfrom mycompany.press.models import PressReleasedef detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=1) t = loader.get_template('press/detail.html') c = Context({'press': p}) return HttpResponse(t.render(c))def press_list(request): ''' Returns a list of press releases ''' pl = get_list_or_404(PressRelease) t = loader.get_template('press/list.html') c = Context({'press_list': pl}) return HttpResponse(t.render(c)) In your mycompany/press/urls.py file, add the highlighted line: from django.conf.urls.defaults import *urlpatterns = patterns('', (r'detail/(?P<pid>d+)/$','mycompany.press.views.detail'), (r'list/$', 'mycompany.press.views.press_list'),) Any incoming request starting with press/ will be sent to our press/urls.py file. If the remaining part of the URL is list/, it will be handled by the press_list function in our press/views.py file. If the remaining part is detail/<number> (such as detail/1 or detail/2), it will be handled by the detail function. Finally, create a new file at mycompany/templates/press/list.html: <html><head><title>Press Releases</title></head><body><h1>Press Releases</h1><ul>{% for press in press_list %}<li><a href="/press/detail/{{ press.id }}/">{{ press.title }}</a></li>{% endfor %}</ul></body></html> Point your browser to the URL http://localhost:8000/press/list/. You should see something like this, depending on what you entered earlier into the admin site: Using generic views to shorten development time What we've done so far in this article is pretty standard for web application development: We created a view to load an object by its ID. We created a view to load a list of objects. We retrieved our object using the data sent in from the URL or retrieved a list of objects. We loaded a template file. We rendered the template. We returned an HTTP response. Because these actions are so common, Django has a way to cut out the whole step of writing a view, called generic views. Generic views are called from the URL configuration file, which allows you to go right from the URL pattern to your template. Generic views come in a few types: Simple List/detail Date-based Create/update/delete We won't be covering the date-based or create/update/delete generic views. But after reading this article, you'll be well-prepared to read about them in the online documentation. Simple generic views The two simple generic views that handle loading of a template don't require any data lookup (going directly to a template) and redirecting from one URL to another. Loading a template directly If you just need to load and render a template when a URL is requested, you can use the direct_to_template generic view. For example, let's build a robots exclusion file (aka a robots.txt file) that search engine spiders will request at http://localhost:8000/robots.txt. (Search engines wouldn't index pages on a localhost domain, but pretend for this example that they would.) Since the file is rarely changed after being created, you may not want the overhead of a database lookup to serve it, so you just want to render a template when the URL is requested. Create a new file at mycompany/templates/robots.txt and add these lines: User-agent: *Disallow: /admin This very simple example will prevent spiders from trying to index your admin path (visit robotstxt.org for more info on how exclusion files work). In your mycompany/urls.py file, add the highlighted lines: from django.conf.urls.defaults import *from django.contrib import adminadmin.autodiscover()urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root), (r'^press/', include('mycompany.press.urls')), (r'^robots.txt$', 'django.views.generic.simple.direct_to_template', 'template': 'robots.txt'}), ) Point your browser to the URL http://localhost:8000/robots.txt/. You'll get a response that looks like this:
Read more
  • 0
  • 0
  • 3509
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 $15.99/month. Cancel anytime
article-image-jboss-portals-and-ajax-part-2
Packt
16 Oct 2009
7 min read
Save for later

JBoss Portals and AJAX - Part 2

Packt
16 Oct 2009
7 min read
AJAX support for markup Special tags are added to layout JSPs that facilitate the placement of AJAX features on a page. Similarly, renderers are used to interpret the tags and to render AJAX-driven content. The obvious advantage is the in-built support for the auto-creation and control of AJAX components on portal pages. Layout markup Layouts provide a structure for the creation and serving of portal pages. Layouts aggregate all of the content generated by the portlet, based on region and order, merge them with some additional content provided by the portal, and serve a response back to the user. By providing support for AJAX in the layout, helps facilitate the easy development and implementation of dynamic functionality in pages, with minimal effort. Layout markup is implemented using JSP tags. The JBoss JSP tag library, portlet-layout.tld, offers tags that facilitate the implementation of AJAX features in layouts. A JSP layout can be changed to an AJAX-supported page simply by adding references to the tags. Hence, using tags also helps with the easy implementation of features. The following is the layout page from the default portal generic layout ${JBOSS_PORTAL_HOME}serverdefaultdeployjboss-portal.sarportal-core.warlayoutsgenericindex.jsp, and shows AJAX support implemented as tags: <%@ page import="org.jboss.portal.server.PortalConstants" %><%@ taglib uri="/WEB-INF/theme/portal-layout.tld" prefix="p" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head> <title><%= PortalConstants.VERSION.toString() %></title> <meta http-equiv="Content-Type" content="text/html;"/> <!-- to correct the unsightly Flash of Unstyled Content. --> <script type="text/javascript"></script> <!-- inject the theme, default to the Renaissance theme if nothing is selected for the portal or the page --> <p:theme themeName="renaissance"/> <!-- insert header content that was possibly set by portlets on the page --> <p:headerContent/> <%@include file="/layouts/common/modal_head.jsp"%></head><body id="body"><p:region regionName='AJAXScripts' regionID='AJAXScripts'/><%@include file="/layouts/common/modal_body.jsp"%><div id="portal-container"> <div id="sizer"> <div id="expander"> <div id="logoName"></div> <table border="0" cellpadding="0" cellspacing="0" id="header-container"> <tr> <td align="center" valign="top" id="header"> <!-- Utility controls --> <p:region regionName='dashboardnav' regionID='dashboardnav'/> <!-- navigation tabs and such --> <p:region regionName='navigation' regionID='navigation'/> <div id="spacer"></div> </td> </tr> </table> <div id="content-container"> <!-- insert the content of the 'left' region of the page, and assign the css selector id 'regionA' --> <p:region regionName='left' regionID='regionA'/> <!-- insert the content of the 'center' region of the page, and assign the css selector id 'regionB' --> <p:region regionName='center' regionID='regionB'/> <hr class="cleaner"/> </div> </div> </div></div><div id="footer-container" class="portal-copyright">Powered by <a class="portal-copyright" href="http://www.jboss.com/products/jbossportal">JBoss Portal</a><br/></div><p:region regionName='AJAXFooter' regionID='AJAXFooter'/></body></html> Renderer markup The portal combines the renderers and layouts to generate the final content. Enabling support for AJAX in the renderer just requires adding the statement <ajax-enabled>true</ajax-enabled> to the renderer descriptor. The following example, at {JBOSS_PORTAL_HOME}serverdefaultdeployjbossportal.sarportal-core.warWEB-INFlayoutportal-renderSet.xml, shows the renderer configuration of the emptyRenderer RenderSet for AJAX support: <renderSet name="emptyRenderer"> <set content-type="text/html"> <ajax-enabled>true</ajax-enabled> <region-renderer> org.jboss.portal.theme.impl.render.empty.EmptyRegionRenderer </region-renderer> <window-renderer> org.jboss.portal.theme.impl.render.empty.EmptyWindowRenderer </window-renderer> <portlet-renderer> org.jboss.portal.theme.impl.render.empty.EmptyPortletRenderer </portlet-renderer> <decoration-renderer> org.jboss.portal.theme.impl.render.empty.EmptyDecorationRenderer </decoration-renderer> </set></renderSet> AJAX support for content Whereas the layout and renderer contribute to AJAX behavior at the markup level, JBoss portal's support for object-level configuration can be leveraged to provide AJAX support at the page level. The object property inherits a configured behavior from its parent. Currently, two features are offered for AJAX-driven content: Drag and drop: Facilitates easy movement of portlets to various locations on screen using the mouse. Screen Refresh: Allows sub-components of pages or individual portlets to refresh themselves without refreshing the entire page. Drag-and-Drop As the name suggests, this feature is triggered by a user action, and allows a portlet to detach itself from a specific location on the page and move to a different location on the page. This allows for the customization of the user interface to a form that is most convenient to the user. The dynamic view behavior comes from a combination of DHTML and asynchronous server-side communication. Due to the nature of the behavior, drag-and-drop capability is available and effective only in dashboard pages where there are multiple portlets and the page layout can be personalized. The feature is allowed by default on the dashboard, but can be turned off by setting the value in the configuration file to false. The following is a snippet of the default object configuration file ( jboss-portal.sar/conf/data/default-object.xml ), which illustrates the enabling of the feature. Please note that this can also be configured using the administration console user interface of the JBoss server. <deployment> <if-exists>keep</if-exists> <context> <context-name>dashboard</context-name> <properties> ... <!-- Set the dnd property --> <property> <name>theme.dyna.dnd_enabled</name> <value>true</value> </property> ... </properties> </context></deployment> <name>theme.dyna.dnd_enabled</name> value enables or disables the drag-and-drop behavior. Partial content refresh One of the most expensive processes in a portal is the refresh of portlets when the page is generated. For every user action on a page, the portal calls all of the portlet methods in a serial, but non-specific order, which involves a significant amount of time and server-side processing. Partial content refresh support mitigates these issues to a large extent with an effective use of client-server asynchronous communication. When the state of a single portlet changes, a partial content refresh facilitates the update and refresh of only that portlet, instead of for all of the portlets on the page. This prevents the regeneration of the whole page and the initialization of all of the portlets on the page. The following image illustrates the partial content refresh flow:   The partial refresh capability is compatible with the JSR-168 portlet API, which allows for programmatic update of portlet states during runtime. Partial refreshes can be enabled through portal object configuration or through configuration at the default server level.
Read more
  • 0
  • 0
  • 1362

article-image-jquery-ui-accordion-widget-part-1
Packt
16 Oct 2009
9 min read
Save for later

jQuery UI Accordion Widget - Part 1

Packt
16 Oct 2009
9 min read
Accordion's structure Let's take a moment to familiarize ourselves with what an accordion is made of. Within the outer container is a series of links. These links are the headings within the accordion and each heading will have a corresponding content panel, or drawer as they are sometimes referred to, which opens when the heading is clicked. The following screenshot shows these elements as they may appear in an accordion: It's worth remembering that when using the accordion widget, only one content panel can be open at any one time. Let's implement a basic accordion now. In a blank page in your text editor, create the following 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>jQuery UI Accordion Widget Example 1</title> </head> <body> <ul id="myAccordion"> <li> <a href="#">Header 1</a> <div>Wow, look at all this content that can be shown or hidden with a simple click!</div> </li> <li> <a href="#">Header 2</a> <div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpatligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est. Ut posuere, mauris at sodales rutrum, turpis tellus fermentum metus, ut bibendum velit enim eu lectus. Suspendisse potenti. </div> </li> <li> <a href="#">Header 3</a> <div>Donec at dolor ac metus pharetra aliquam. Suspendisse purus. Fusce tempor ultrices libero. Sed quis nunc. Pellentesque tincidunt viverra felis. Integer elit mauris, egestas ultricies, gravida vitae, feugiat a, tellus.</div> </li> </ul> <script type="text/javascript" src="jqueryui1.6rc2/jquery-1.2.6.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.core.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.accordion.js"></script> <script type="text/javascript"> //function to execute when doc ready $(function() { //turn specified element into an accordion $("#myAccordion").accordion(); }); </script> </body></html> Save the file as accordion1.html in your jqueryui folder and try it out in a browser. We haven't specified any styling at all at this stage, but as you can see from the following screenshot, it still functions exactly as intended: Little code is required for a basic working version of the accordion widget. A simple unordered list element is the mark-up foundation which is transformed by the library into the accordion object. The following three separate external script files are required for an accordion: The jQuery library itself (jquery-1.2.6.js) The UI base file (ui.core.js) The accordion source file (ui.accordion.js) The first two files are mandatory requirements of all components of the UI library. They should be linked to in the order shown here. Each widget also has its own source file, and may depend on other components as well. The order in which these files appear is important. The jQuery library must always appear first, followed by the UI base file. After these files, any other files that the widget depends upon should appear before the widget's own script file. The library components will not function as expected if files are not loaded in the correct order. Finally, we use a custom <script> block to turn our <ul> element into the accordion. We can use the jQuery object shortcut $ to specify an anonymous function which will be executed as soon as the document is ready. This is analogous to using $(document).ready(function(){}) and helps to cut down on the amount of code we have to type. Following this, we use the simple ID selector $("#myAccordion") to specify the element on the page we want to transform. We then use the accordion() constructor method to create the accordion Other elements can be turned into accordions as well. All list element variants are supported including ordered lists and definition lists. You don't even need to base the accordion on a list element at all. You can build a perfectly functional accordion using just nested <div> and <a> elements, although additional configuration will be required In the above example, we used an empty fragment (#) as the value of the href attribute. You should note that any URLs supplied for accordion headers will not be followed when the header is clicked within the accordion when using the default implementation. Styling the accordion With no styling, the accordion will take up 100% of the width of its container. Like with other widgets, we have several options for styling the accordion. We can create our own custom stylesheet to control the appearance of the accordion and its content, we can use the default or flora themes that come with the library, or we can use Theme Roller to create an extensive skin for the whole library. Let's see how using the flora theme for the accordion will cause it to render. In accordion1.html, add the following <link> tag to the <head> of the page: <link rel="stylesheet" type="text/css" href="jqueryui1.6rc2/themes/flora/flora.accordion.css"> Save the new file as accordion2.html, also in the jqueryui folder, and view it again in a browser. It should appear something like this: The accordion theme file assumes that an unordered list is being used as the basis of the widget and specifically targets <li> elements with certain style rules. We can easily create our own custom theme to style the accordion for situations where we want to use a non-list-based accordion widget, or if we simply want different colors or font styles. You can use the excellent Firebug plugin for Firefox, or another DOM viewer, to see the class names that are automatically added to certain elements when the accordion is generated. You can also read through an un-minified version of the source file if you really feel like it. These will be the class names that we'll be targeting with our custom CSS. The following screenshot shows Firebug in action: Change accordion2.html so that it appears as follows (new code is shown in bold): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html lang="en"> <head> <link rel="stylesheet" type="text/css" href="styles/accordionTheme.css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>jQuery UI Accordion Widget Example 3</title> </head> <body> <div id="myAccordion"> <span class="corner topLeft"></span><span class="corner topRight"></span><span class="corner bottomLeft"></span><span class="corner bottomRight"></span> <div><a href="#">Header 1</a><div>Wow, look at all this content that can be shown or hidden with a simple click!</div></div> <div><a href="#">Header 2</a><div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpatligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est. Ut posuere, mauris at sodales rutrum, turpis tellus fermentum metus, ut bibendum velit enim eu lectus. Suspendisse potenti.</div></div> <div><a href="#">Header 3</a><div>Donec at dolor ac metus pharetra aliquam. Suspendisse purus. Fusce tempor ultrices libero. Sed quis nunc. Pellentesque tincidunt viverra felis. Integer elit mauris, egestas ultricies, gravida vitae, feugiat a, tellus.</div></div> </div> <script type="text/javascript" src="jqueryui1.6rc2/jquery-1.2.6.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.core.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.accordion.js"></script> <script type="text/javascript"> //function to execute when doc ready $(function() { //turn specified element into an accordion $("#myAccordion").accordion(); }); </script> </body></html> Save this version as accordion3.html in the jqueryui folder. The class name ui-accordion is automatically added to the accordion's container element. Therefore, we can use this as a starting point for most of our CSS selectors. The links that form our drawer headers are given the class ui-accordion-header so we can also target this class name. In a new file, create the following stylesheet: #myAccordion { width:200px; border:2px solid #000000; position:relative; list-style-type:none; padding-left:0;}.ui-accordion-header { text-decoration:none; font-weight:bold; color:#000000; display:block; width:100%; text-align:center;}.ui-accordion div div { font-size:90%;}.ui-accordion a { color:#ffffff; background:url(../img/accordion/header-sprite.gif) repeat-x 0px 0px;}.ui-accordion a.selected { background:url(../img/accordion/header-sprite.gif) repeat-x 0px -22px;}.ui-accordion a:hover { background:url(../img/accordion/header-sprite.gif) repeat-x 0px -44px;}/* container rounded corners */.corner { position:absolute; width:12px; height:13px; background:url(../img/accordion/corner-sprite.gif) no-repeat;}.topLeft { top:-2px; left:-2px; background-position:0px 0px;}.topRight { top:-2px; right:-2px; background-position:0px -13px;}.bottomRight { bottom:-2px; right:-2px; background-position:0px -26px;}.bottomLeft { bottom:-2px; left:-2px; background-position:0px -39px;} Save this file as accordionTheme.css in your styles folder and preview accordion3.html in a browser. We will need a new folder for the images we use in this and subsequent examples. Create a new folder inside the img folder and name it accordion. With just two images, and a few simple style rules, we can drastically change the default appearance of the accordion with our own custom skin as shown in the following screenshot: Configuring accordion The accordion has a range of configurable properties which allow us to easily change the default behaviour of the widget. The following table lists the available properties, their default value, and gives a brief description of their usage:
Read more
  • 0
  • 0
  • 3750

article-image-jboss-portals-and-ajax-part-1
Packt
16 Oct 2009
7 min read
Save for later

JBoss Portals and AJAX - Part 1

Packt
16 Oct 2009
7 min read
Rich user interfaces and AJAX Rich user interfaces can be achieved by using a combination of dynamic HTML elements such as HTML and JavaScript. However, the scope of such an interface is limited to client-side behavior and has minimal functional implications due to the lack of server-side interactions. The power of AJAX is in its capability to provide even richer interface by supplementing its dynamic user interface with powerful functionality through seamless server-side invocation power. AJAX allows individual user interface components to communicate with the server and exchange data without the need for refreshing the whole screen. This is achieved using a process called Web Remoting. Web remoting, or the process of communicating between a browser and a server, can be performed in multiple ways. The popular approaches that are supported by today's browsers are IFrames and XMLHttpRequest. Dynamic HTML can be complemented with either of these methods to generate AJAX functionality. Asynchronous JavaScript and XML or AJAX Asynchronous communication between the client and the server forms the backbone of AJAX. Although an asynchronous request-response method can provide significant value in the development of rich functionality by itself, the results are lot more pronounced when used in conjunction with other functional standards such as CSS, DOM, JavaScript, and so on. The predominant popularity of AJAX stems from such usage. Client-server communication can be achieved either by using IFrames, or by using the supported JavaScript function called XMLHttpRequest(). Due to certain limitations of IFrames, XMLHttpRequest has gained a lot more acceptance. While IFrame can also be an effective option for implementing AJAX-based solutions, in this article, we will focus largely on an XMLHttpRequest-based implementation. The primary advantage of using AJAX-based interfaces is that the update of content occurs without page refreshes. A typical AJAX implementation using XMLHttpRequest happens as described in the following steps: An action on the client side, whether this is a mouse click or a timed refresh, triggers a client event An XMLHttpRequest object is created and configured The XMLHttpRequest object makes a call The request is processed by a server-side component The component returns an XML (or an equivalent) document containing the result The XMLHttpRequest object calls the callback() function and processes the result The HTML DOM is updated with any resulting values The following simplified image illustrates the high-level steps involved in an AJAX request flow. The portal client page gets served to the client browser, where the execution of JavaScript functions takes place. The following example illustrates the initialization of the request object and its basic use: if (window.XMLHttpRequest) // Object of the current window { // for non-IE browsers request = new XMLHttpRequest();}else if (window.ActiveXObject){ // For IE request = new ActiveXObject("Microsoft.XMLHTTP");}request.onreadystatechange = function(){ // do something to process response};if (request.readyState == 4){ // everything received, OK. Do something now..} else { // wait for the response to come to ready state} In subsequent sections, we will modify our sample portal application by adding AJAX functionality to one of the portlets. AJAX in JBoss portal AJAX has gained tremendous popularity in the traditional web application development world due to the richness and agility that it brings to user interfaces. Portals, such as JBoss portal, can also gain significantly from AJAX, in terms of implementation of both behavior and functionality. Refreshing the page content tends to be a time-consuming and resource-intensive process. Every request that a user makes to the server, either by clicking on submissions or links, results in the portal calling doView() and a series of methods for each portlet on the page, one at a time, before aggregating the results and sending the response back to the browser. Using AJAX allows for simultaneous submissions of request in their own independent threads of execution, resulting in an asynchronous and parallel execution. The portal page refresh overhead is now only as long as the time consumed by the slowest portlet. The response times observed by the user improve dramatically, while at the same time allowing more functionality on pages. Architecturally, vertical independent stacks of execution facilitate cleaner and more modular designs and implementations. AJAX can be implemented in JBoss portal in the following two ways: Using in-built support for asynchronous portal behavior by using configurations Writing custom behavior in portlets and page content by using AJAX libraries The in-built support for asynchronous behavior comprises of support for both markup and content. The markup support is in layouts and renderers, while the content is supported through configurable drag-drop and partial page refresh behavior. Almost all of the AJAX behavior supported by JBoss portal relates to asynchronous communication between the client and the portal servers. The only exception is the drag-drop behavior, which is largely view functionality. As far as the custom development within a portlet is concerned, the options are innumerable. A portlet can be developed using many advanced frameworks that are available as either commercial or open source products. For example, user interface features such as drag-and-drops, grids, accordion selects, pull-down menus, content refresh, and so on can be implemented by using third-party libraries including Scriptaculous, JQuery, and DOJO, which have gained a strong following among developers, even on traditional applications and non-portal platforms. In the next few sections, we will walk through an example of AJAX-enabled portlets using one of these libraries, developed on the JBoss portal platform. However, before we go into the implementation, let's step back and understand the limitations that the current portlet specification– JSR-286–addresses, facilitating easy development of AJAX portlets. JSR-168 AJAX limitations Before we look at the features and options provided by the new specification, let's look at how traditional JSR-168 portlets functioned. As shown in the following figure, the "Action" request invoked the processAction method on the server, which implemented controller logic to route it to the correct view. The "Render" request then invokes the render method to serve the content page to the browser. However, when the portlet uses AJAX and needs to makes an asynchronous call, it has to use ActionURL. This in turn follows the standard processing when processAction processes the request and the render method creates the user interface. However, now when the user interface is sent back, the portal injects some other markup and recreates the entire portal page. Hence, instead of refreshing a snippet of user interface, we end up refreshing the whole page. The issues with JSR-168 and AJAX can be broadly summarized as follows: ActionURL and RenderURL point to a portal, and not to a portlet. When we point to a portal, the result is a complete portal page, even if the portlet generates only a snippet. As per the specification, the user interface rendered by the portlet is supposed to be aggregated with some other markup and served back to the browser. When more than only the necessary data and markup is sent back, the JavaScript code on the client side that makes the asynchronous call cannot process the request. Asynchronous calls are made through XMLHttpRequest, which is designed to consume and process the complete response from the portlet. With the portal processing the request in between, XMLHttpRequest cannot consume the original response for processing. This defeats the purpose and value of using asynchronous calls to the server, and we end up with traditional full page refreshes. There were obviously a few workarounds to this. The most common practice was to serve the request from outside of the portal container into the web container. The idea is that the AJAX call can still be made to ActionURL, but the render function copies or shares its context with a traditional Java servlet in the web container of the application server. The AJAX call can now make a direct request to the servlet and get an asynchronous response from the servlet with no interference from the portal. There was a need for a better solution, and one that was incorporated as part of the specification. JSR-286, the latest portlet specification, addresses these problems.
Read more
  • 0
  • 0
  • 1974

article-image-extending-opencms-developing-custom-widget
Packt
16 Oct 2009
8 min read
Save for later

Extending OpenCms: Developing a Custom Widget

Packt
16 Oct 2009
8 min read
Structured Content Types Support for structured content is a key feature of OpenCms. Structured content types allow different templates to be used to re-skin a site, or to share content with other sites that have a different look. Structured content types are defined by creating XSD schemas and placing them into modules. Once a new content type has been defined, the Workplace Explorer provides a user interface to create new instances of the content and allows it to be edited. There are some sample content types and templates that come with the Template One group of modules. These content types are very flexible and allow a site to be built using them right away. However, they may not fit our site requirements. In general, site requirements and features will determine the design of the structured content types and templates that need to be developed. BlogEntry Content Type For designing a blog website it is required that the content type contains blog entries. The schema file for the BlogEntry content type looks like the following : <!-- ======================================================== Content definition schema for the BlogEntry type ========================================================== --> <!-- 1. Root Element --> <xsd:schema elementFormDefault="qualified"> <!-- 2. Define the location of the schema location --> <xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd"/> <!-- 3. Root element name and type of our XML type --> <xsd:element name="BlogEntrys" type="OpenCmsBlogEntrys"/> <!-- 4. Definition of the type described above --> <xsd:complexType name="OpenCmsBlogEntrys"> <xsd:sequence> <xsd:element name="BlogEntry" type="OpenCmsBlogEntry" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <!-- 5. Data field definitions --> <xsd:complexType name="OpenCmsBlogEntry"> <xsd:sequence> <xsd:element name="Title" type="OpenCmsString" minOccurs="1" maxOccurs="1" /> <xsd:element name="Date" type="OpenCmsDateTime" minOccurs="1" maxOccurs="1" /> <xsd:element name="Image" type="OpenCmsVfsFile" minOccurs="0" maxOccurs="1" /> <xsd:element name="Alignment" type="OpenCmsString" minOccurs="1" maxOccurs="1" /> <xsd:element name="BlogText" type="OpenCmsHtml" minOccurs="1" maxOccurs="1" /> <xsd:element name="Category" type="OpenCmsString" minOccurs="0" maxOccurs="10" /> </xsd:sequence> <!-- 6. locale attribute is required --> <xsd:attribute name="language" type="OpenCmsLocale" use="required"/> </xsd:complexType> <!—optional code section --> <xsd:annotation> <xsd:appinfo> <!-- Mappings allow data fields to be mapped to content properties --> <mappings> <mapping element="Title" mapto="property:Title" /> <mapping element="Date" mapto="attribute:datereleased" /> </mappings><!-- Validation rules for fields --> <validationrules> <rule element="BlogText" regex="!.*[Bl]og.*" type= "warning" message="${key.editor.warning.BlogEntry. dontallowblog|${validation.path}}"/> </validationrules> <!-- Default values for fields --> <defaults> <default element="Date" value="${currenttime}"/> <default element="Alignment" value="left"/> </defaults> <!-- user interface widgets for data fields --> <layouts> <layout element="Image" widget="ImageGalleryWidget"/> <layout element="Alignment" widget="SelectorWidget" configuration="left|right|center" /> <layout element="Category" widget="SelectorWidget" configuration="silly|prudent|hopeful|fearful| worrisome|awesome" /> <layout element="BlogText" widget="HtmlWidget"/> </layouts> <!-- UI Localization --> <resourcebundle name="com.deepthoughts.templates.workplace"/> <!-- Relationship checking --> <relations> <relation element="Image" type="strong" invalidate="node" /> </relations> <!-- Previewing URI --> <preview uri="${previewtempfile}" /> <!-- Model Folder for content models --> <modelfolder uri="/system/modules/com.deepthoughts.templates /defaults/" /> </xsd:appinfo> </xsd:annotation> </xsd:schema> The BlogEntry content type file is named as blogentry.xsd and it placed in the folder named schemas in modules. Designing a Custom Widget Referring to the highlighted code in BlogEntry content type schema file we can see that the category field is populated from a drop-down list provided by SelectorWidget. The SelectorWidget obtains its values from the static configuration string defined within the blog schema file. This design is problematic as we would like category values to be easily changed or added. Ideally, the list of category values should be able to be updated by site content editors. Fortunately, we can create our own custom widget to handle this requirement. An OpenCms widget is a Java class that implements the I_CmsWidget interface, located in the org.opencms.widgets package. The interface contains a number of methods that must be implemented. First there are some methods dealing with instantiation and configuration of the widget: newInstance: This returns a new instance of the widget. setConfiguration: This method is called after the widget has been initialized to configure it. The configuration information is passed as a string value coming from the declaration of the widget within the schema file of the content type using it. getConfiguration: This is called to retrieve the configuration information for the widget. Next, there are some methods used to handle the rendering. These methods are called by widget enabled dialogs that might be used in a structured content editor or an administration screen. The methods provide any Javascript, CSS, or HTML needed by the widget dialogs: getDialogIncludes: This method is called to retrieve any Javascript or CSS includes that may be used by the widget. getDialogInitCall: This method may return Javascript code that performs initialization or makes calls to other Javascript initialization methods needed by the widget. getDialogInitMethod: This method may return Javascript code containing any functions needed by the widget. getDialogHtmlEnd: This method is called at the end of the dialog and may be used to return an HTML or Javascript needed by the widget. getDialogWidget: This method returns the actual HTML and Javascript used to render the widget along with its values. getHelpBubble: This method returns the HTML for displaying the help icon relating to this widget. getHelpText: This method returns the HTML for displaying the help text relating to this widget. Lastly, there are some methods used to get and set the widget value: getWidgetStringValue: This method returns the value selected from the widget. setEditorValue: This method sets the value into the widget. All these methods have base implementations in the A_CmsWidget class. In most cases, the base methods do not need to be overridden. As such, we will not cover all the methods in detail. If it is necessary to override the methods, the best way to get an idea of how to implement them is to look at the code using them. All widgets are used in dialog boxes which have been enabled for widgets, by implementing the I_CmsWidgetDialog interface. There are two general instances of these dialogs, one is used for editing structured XML content, the other is found in any dialog appearing in the Administration View. The two classes implementing this interface are: org.opencms.workplace.CmsWidgetDialog org.opencms.workplace.editors.CmsXmlContentEditor The CmsWidgetDialog class is itself a base class, which is used by all dialogs found in the Administrative View. Before designing a new widget, it is useful to examine the existing widget code. The default OpenCms widgets can be found in the org.opencms.widgets package. All the widgets in this package subclass the A_CmsWidget class mentioned earlier. Often, a new widget design may be subclassed from an existing widget. Designing the Widget As mentioned earlier, we would like to have a widget that obtains its option data values dynamically rather than from a fixed configuration string value. Rather than create a widget very specific to our needs, we will use a flexible design where the data source location can be specified in the configuration parameter. The design will allow for other data sources to be plugged into the widget. This way, we can use a single widget to obtain dynamic data from a variety of sources. To support this design, we will use the configuration parameter to contain the name of a Java class used as a data source. The design will specify a pluggable data source through a Java interface that a data source must implement. Furthermore, a data source can accept parameters via the widget configuration string. With this design, an example declaration for a widget named CustomSourceSelectWidget would look like this: <layout element="Category" widget="CustomSourceSelectWidget" configuration="source='com.widgets.sources.MySource'| option1='some config param'| option2='another param'" /> This declaration would appear in the schema of a content type, using the widget as covered earlier. The configuration parameter consists of name/value pairs, delimited by the vertical bar character. Each name/value pair is separated by the equal to sign and the value is always enclosed in single quotes. The design requires that at least the source parameter be specified. Additional parameters will depend upon the specific data source being used. The example declaration specifies that the data field named Category will use the CustomSourceSelectWidget widget for its layout. The configuration parameter contains the name of the Java class to be used to obtain the data source. The data source will receive the two parameters named option1 and option2 along with their values. Next, lets move on to the code to see how this all gets implemented.
Read more
  • 0
  • 0
  • 1632
article-image-posting-your-wordpress-blog
Packt
16 Oct 2009
12 min read
Save for later

Posting on Your WordPress Blog

Packt
16 Oct 2009
12 min read
The central activity you'll be doing with your blog is adding posts. A post is like an article in a magazine; it's got a title, content, and an author (you). If a blog is like an online diary, then every post is an entry in that diary. A blog post also has a lot of other information attached to it, such as a date and categories. In this article, you will learn how to create a new post and what kind of information you can attach to it. Adding a simple post Let's review the process of adding a simple post to your blog. Whenever you want to do maintenance on your WordPress website, you have to start by logging in to the WP Admin (WordPress Administration panel) for your site. To get to the admin panel, just point your web browser to http://yoursite.com/wp-admin. Remember that if you have installed WordPress in a subfolder (for example, blog), then your URL has to include the subfolder (that is, http://yoursite.com/blog/wp-admin). When you first log into the WP Admin, you'll be at the Dashboard. The Dashboard has a lot of information on it. The very top bar, which I'll refer to as the top menu, is mostly dark grey and on the left, of course, is the main menu. The top menu and the main menu exist on every page within the WP Admin. The main section on the right contains information for the current page you're on. In this case, we're on the Dashboard. It contains boxes that have a variety of information about your blog, and about WordPress in general. The quickest way to get to the Add New Post page at any time is to click on the New Post link at the top of the page in the top bar (top menu). This is the Add New Post page: To quickly add a new post to your site, all you have to do is: Type in a title into the text field under Add New Post (for example, Making Lasagne). Type the text of your post in the content box. Note that the default view is Visual, but you actually have a choice of the HTML view as well. Click on the Publish button, which is at the far right. Note that you can choose to save a draft or view a preview of your post. In the following image, the title field, the content box, and the Publish button of the Add New Post page are highlighted: Once you click on the Publish button, you have to wait while WordPress performs its magic. You'll see yourself still on the Edit Post page, but now the following message has appeared telling you that your post was published and giving you a link to View post: If you go to the front page of your site, you'll see that your new post has been added at the top (newest posts are always at the top): Common post options Now that we've reviewed the basics of adding a post, let's investigate some of the other options on the Add New Post page. In this section we'll look at the most commonly used options, and in the next section we'll look at the more advanced options. Categories and tags Categories and tags are two similar types of information that you can add to a blog post. We use them to organize the information in your blog by topic and content (rather than just by, say, date), and to help visitors find what they are looking for on your blog. Categories are primarily used for structural organizing. They can be hierarchical. A relatively busy blog will probably have at least 10 categories, but probably not more than 15 or 20. Each post in this blog will likely have one to four categories assigned to it. For example, a blog about food might have these categories: Cooking Adventures, In The Media, Ingredients, Opinion, Recipes Found, Recipes Invented, and Restaurants. Tags are primarily used as shorthand for describing the topics covered in a particular blog post. A relatively busy blog will have anywhere from 15 to 30 tags in use. Each post in this blog will likely have three to ten tags assigned to it. For example, a post on the food blog about a recipe for butternut squash soup may have these tags: soup, vegetarian, autumn, hot, easy. Let's add a new post to the blog. This time, we'll give it not only a title and content, but also tags and categories. When adding tags, just type your list of tags into the Tags box on the right, separated by commas: Then click on the Add button. The tags you just typed in will appear below the text field with little xs next to them. You can click on an x to delete a tag. Once you've used some tags in your blog, you'll be able to click on the Choose from the most popular tags link in this box so that you can easily re-use tags. Categories work a bit differently than tags. Once you get your blog going, you'll usually just check the boxes next to existing categories in the Categories box. In this case, as we don't have any existing categories, we'll have to add one or two. In the Categories box on the right, click on the + Add New Category link. Type your category into the text field and click on the Add button. Your new category will show up in the list, already checked. Look at the following screenshot: If in the future you want to add a category that needs a parent category, select Parent category from the pull-down menu before clicking on the Add button. If you want to manage more details about your categories, move them around, rename them, assign parent categories, and assign descriptive text. You can do this on the Categories page, which we'll see in detail later in this article. Now fill in your title and content here: Click on the Publish button and you're done. When you look at the front page of your site, you'll see your new post on the top, your new category in the sidebar, and the tags and category (that you chose for your post) listed under the post itself: Adding an image to a post You may often want to have an image show up in your post. WordPress makes this very easy. Let's add an image to the post we just created. You can click on Edit underneath your post on the front page of your site to get there quickly. Alternatively, go back to the WP Admin, open Posts in the main menu, and then click on Edit underneath your new post. To add an image to a post, first you'll need to have that image on your computer. Before you get ready to upload an image, make sure that your image is optimized for the Web. Huge files will be uploaded slowly and slow down the process of viewing your site. You can re-size and optimize images using software such as GIMP or Photoshop. For the example in this article, I have used a photo of butternut squash soup that I have taken from the website where I got the recipe, and I know it's on the desktop of my computer. Once you have a picture on your computer and know where it is, follow these steps to add the photo to your blog post: Click on the little photo icon, which is next to the word Upload/Insert and below the box for the title: In the box that appears, click on the Select Files button and browse to your image. Then click on Open and watch the uploader bar. When it's done, you'll have a number of fields you can fill in: The only fields that are important right now are Title, Alignment, and Size. Title is a description for the image, Alignment will tell the image whether to have text wrap around it, and Size is the size of the image. As you can see, I've chosen the Right alignment and the Thumbnail size. Now click on Insert into Post. This box will disappear, and your image will show up in the post on the edit page itself: Now click on the Update Post button and go look at the front page of your site again. There's your image! You may be wondering about those image sizes. What if you want bigger or smaller thumbnails? You can set the pixel dimensions of your uploaded images and other preferences by opening Settings in the main menu and then clicking on Media. This takes you to the Media Settings page: Here you can specify the size of the uploaded images for: Thumbnail Medium Large If you change the dimensions on this page and click on the Save Changes button, only images you upload in the future will be affected. Images you've already uploaded to the site will have had their thumbnail, medium, and large versions created already using the old dimensions. Using the Visual editor versus the HTML editor WordPress comes with a Visual editor, otherwise known as a WYSIWYG editor (pronounced wissy-wig, which stands for What You See Is What You Get). This is the default editor for typing and editing your posts. If you're comfortable with HTML, you may prefer to write and edit your posts using the HTML editor—particularly useful if you want to add special content or styling. To switch from the rich text editor to the HTML editor, click on the HTML tab next to the Visual tab at the top of the content box: You'll see your post in all its raw HTML glory and you'll get a new set of buttons that lets you quickly bold and italicize text as well as add link code, image code, and so on. You can make changes and swap back and forth between the tabs to see the result. If you want the HTML tab to be your default editor, you can change this on your Profile page. Navigate to Users | Your Profile, and select the Disable the visual editor when writing checkbox. Drafts, timestamps, and managing posts There are three additional, simple but common, items I'd like to cover in this section: drafts, timestamps, and managing posts. Drafts WordPress gives you the option to save a draft of your post so that you don't have to publish it right away but can still save your work. If you've started writing a post and want to save a draft, just click on the Save Draft button at the right (in the Publish box), instead of the Publish button. Even if you don't click on the Save Draft button, WordPress will attempt to save a draft of your post for you about once a minute. You'll see this in the area just below the content box. The text will say Saving Draft... and then the time of the last draft saved: At this point, after a manual save or an auto-save, you can leave the Edit Post page and do other things. You'll be able to access all of your draft posts from the Dashboard or from the Edit Posts page. Timestamps WordPress will also let you alter the timestamp of your post. This is useful if you are writing a post today that you wish you'd published yesterday, or if you're writing a post in advance and don't want it to show up until the right day. The default timestamp will always be set to the moment you publish your post. To change it, just find the Publish box and click on the Edit link (next to the calendar icon and Publish immediately), and fields will show up with the current date and time for you to change: Change the details, click on the OK button, and then Publish your post (or save a draft). Managing posts If you want to see a list of your posts so that you can easily skim and manage them, you just need to go to the Edit Posts page in the WP Admin by navigating to Posts in the main menu. You'll see a detailed list of your posts, as seen in the next screenshot: There are so many things you can do on this page! You can: Choose a post to edit—click on a post title and you'll go back to the main Edit Post page Quick-edit a post—click on the Quick Edit link for any post and new options will appear right in the list, which will let you edit the title, timestamp, categories, tags, and more Delete one or more posts—click on the checkboxes next to the posts you want to delete, choose Delete from the Bulk Actions drop-down menu at the bottom, and click on the Apply button Bulk edit posts—choose Edit from the Bulk Actions menu at the bottom, click on the Apply button, and you'll be able to assign categories and tags to multiple posts, as well as edit other information about them You can experiment with the other links and options on this page. Just click on the pull-down menus and links, and see what happens.
Read more
  • 0
  • 0
  • 4191

article-image-recording-calls-freepbx-25
Packt
16 Oct 2009
2 min read
Save for later

Recording Calls in FreePBX 2.5

Packt
16 Oct 2009
2 min read
Asterisk has a wonderful, built-in ability to record calls. No additional software is required to make this happen. When Asterisk records a call, both sides of the call are recorded and written out to a file for playback on a computer. Call recording is often performed in call centers to ensure call quality, or to keep calls for later review, should the need arise. Asterisk provides the ability to record all of the calls, or to selectively record calls. In this article, we will look the following:   General recording options Recording calls to extensions Recording calls to queues Recording calls to conferences Maintaining call recordings Before enabling call recording for your PBX, make sure that you are aware of the legalities surrounding call recordings and privacy laws. Call recordings are prohibited in certain places, unless the caller is told that the call will be recorded. For example, in the state of California all of the parties on the call must consent to the call being recorded before it begins. Playing back a message stating that the call is being recorded prior to the call being answered is considered a valid form of consent. Recording formats FreePBX allows calls to be recorded in the following formats: WAV WAV49 ULAW ALAW SLN GSM Each format has its own ratio of file size to recording quality, and certain formats will not play on all of the computers. A comparison between all of the  available formats is as follows:
Read more
  • 0
  • 0
  • 2810

article-image-creating-new-types-plone-portlets
Packt
15 Oct 2009
4 min read
Save for later

Creating New Types of Plone Portlets

Packt
15 Oct 2009
4 min read
(For more resources on Plone, see here.) Plone makes it easy to create new types of portlets that include custom programming logic for your site. There are several ways to create custom portlets, but the simplest way to get started is to use the add-on product collective.portlet.tal which provides a new type of portlet, called a TAL Portlet. This portlet allows you to write simple bits of code using Zope's TAL templating language. Let's walk through a quick example of building a custom TAL portlet, which will show a randomly-selected news item from your site. Installing collective.portlet.tal Before you can add a TAL portlet, you must download the product from Plone.org/products and install the add-on product collective.portlet.tal on your site. The best way to do this is to modify your buildout.cfg file. Add collective.portlet.tal to the eggs and zcml sections of your buildout. Here's a code snippet with the changes made to it: [buildout] ... eggs = ... collective.portlet.tal [instance] recipe = plone.recipe.zope2instance ... zcml = collective.portlet.tal Once you've made these changes, re-run buildout by issuing the following command: $ ./bin/buildout Once you've added the product to your buildout, visit Site Setup and choose Add/Remove Products, to install collective.portlet.tal in your site. Finally, add a few news items to your site so that we have something for our new TAL portlet to find. Adding a simple TAL portlet With the collective.portlet.tal product in place, the following can happen: Navigate to your Plone site. Choose Manage Portlets in the right column. From the Add portlet... drop-down list, choose TAL Portlet. You'll see an empty text box in which you can enter a title. We will specify Featured News Item as our title. We'll soon see the code needed to feature a random one of our site's published news items. In addition to the Title text box, you'll also see an HTML text area titled TAL code. Conveniently, this comes pre-populated with some boilerplate HTML and TAL code. Skim this, so that you get a feel for how this looks and what the common HTML structure is like, for a portlet in Plone. As an immediate experiment, we will find the following snippet of code: <dd class="portletItem odd"> Body text</dd> We will modify this, slightly, to: <dd class="portletItem odd"> Is this thing on?</dd> Click on Save and navigate through the site, and you should see your first TAL portlet in action. Of course, there's nothing in this example that couldn't be accomplished with a static text portlet. So let's navigate back to the Featured News Item portlet and make it a bit more interesting and dynamic. Update the code in your TAL Portlet to include the following: <dl class="portlet portlet${portlet_type_name}" tal_define="newsitems python:context.portal_catalog (portal_type='News Item', review_state='published');" tal_condition="newsitems"> <dt class="portletHeader"> <span class="portletTopLeft"></span> <span> Featured News Item </span> <span class="portletTopRight"></span> </dt> <dd class="portletItem odd" tal_define="random_newsitem python:random.choice(newsitems)"> <a tal_content="random_newsitem/Title" href="[replaced by random news item link]" title="[replaced by random news item title]" tal_attributes="href random_newsitem/getURL; title random_newsitem/Title">[replaced by random news item title]</a> </dd> <dd class="portletFooter"> <span class="portletBotomLeft"></span> <span> <a href="http://example.com/news">More news...</a> </span> <span class="portletBottomRight"></span> </dd> </dl> Now, let's go into more detail on a few of these sections, so that you understand what's happening. If at any point you need more context, try reading the excellent ZPT reference manual at http://plone.org/documentation/tutorial/zpt.
Read more
  • 0
  • 0
  • 1593
article-image-structure-content-your-plone-site
Packt
15 Oct 2009
6 min read
Save for later

Structure the Content on your Plone Site

Packt
15 Oct 2009
6 min read
(For more resources on Plone, see here.) Real world information architecture tips Based on what your users need and/or want to see, you need to structure your content within topics, or high-level containers that are typically content-specific sections. As an example, we will take a look at http://plone.org. When visitors enter a Plone site, no matter how deep they go, the navigation tends to stay the same. The following screenshot shows that a visitor is in the Documentation section of the site, with the opportunity to drill down within this section for additional documentation topics: By default, Plone has a portlet that shows the navigation aids on the left-hand side of the browser, which helps the visitors navigate within the subject matter. In this example, there are several subsections below Development. Structuring your content When planning your site, you must first decide how you want to structure your content. The structuring can be worked out through brainstorming sessions with other people involved with your site, in order to come up with a structure suits your business objectives. Investigating other sites that share your organization's model could be a good starting point towards developing your final solution. To really understand how Plone can be an effective solution for your content delivery needs, we will take a look at how to implement Plone for a High School web site. In this type of structure, you will see how some content is targeted at all users, while other content is tailored to specific users. We will use the following high-level topics for demonstration purposes: Home News Events Academics Sports Clubs PTO (Parent-Teacher Organization) Alumni In order to create these sections, we will first create folders for the above sections, into which you will add content. Each of the above sections will be visible in your top-level navigation. Within each top-level folder, we will also create subfolders to help you to structure your content. To create a folder, go to your homepage, select Add new... and choose the Folder option from the drop-down list, as shown in the following screenshot: Specify the Title and the optional Description. In this case, we will create a folder for the Academics section: We're going to just keep the defaults here; we will cover the Settings tab shortly. Click on Save, and then make sure that your folder has been published: Now take a look at the overall navigation structure: There is now a new tab in your navigation bar, which represents a container for holding all of the content that will be part of the academics section of the site. You will follow the same process to create the rest of the top-level tabs. First, we will need to make a change to the default tab behavior in Plone. Specifically, we want to remove Users as a top-level navigation item. Removing it from the tab navigation does not mean that it no longer exists; we're just making sure that items that are more important to this specific site are shown to the visitors and users. To remove Users from the navigation bar, click on the Users tab, and then select Edit. Once you are in Edit mode, there is the section where you can select Settings. You can then select the Exclude from navigation checkbox. After saving your changes, you can see that the tab Users is no longer part of your navigation: Using the same process for adding new folders, we'll add Sports, Clubs and PTO. We end up with the following: Now that we have the top-level structure in place, we can focus on what will need to go within each topic. The process is similar, with the difference being that you need to be within the given topic before creating the next level of folders. When you create folders in the Home section, you have the ability to create top-level tabs. Creating folders within the other top-level folders you create allows you to be more specific for the given topic. We will use the example of the Sports top-level tab for creating an additional folder/site structure. We will need to create the following sub-folders: Football Basketball Soccer Track and Field Lacrosse Baseball Softball To do so, we must drill down into the Sports folder and add new folders within it. Once you have added these folders under the Sports section, the Navigation to the new folders is available in the leftmost side of your browser window: Note that the navigation shows only the contents of the current folder. This can be adjusted via the Manage portlets link, which is available on the home page, below the left and right columns. This link is also accessible via http://www.mysite.com/@@manage-portlets, where www.mysite.com is the name of your Plone site. Simply set the Start Level to 0 and save your changes. Now that the structure for the Sports folder is in place, let's take a look at how you can change the order of display of the folders. If the football season is over, it may make sense to move this category to the bottom of the navigation. To change the order of the Football folder, go to the Contents view under Sports, then click in the Order column for the Football row. The row will turn yellow, and the cursor will change to a four-headed arrow, which indicates that the content object can be moved. Drag the row up or down in the list, to the desired location. Now, when you click on the top level of Sports, the navigation listing appears in the new location that you have just defined: Now, let's take the new folder structure created under the Sports section, and create some more folders that are specific to each sub topic. Select a folder, and then go to the Contents tabbed page. In this example, we will create the following folders under the Soccer folder, which is under the Sports folder: Varsity Boys Girls Junior Varsity Boys Girls Boosters As identified in the preceding screenshot, the breadcrumbs navigation shows the progression through the site. You can also see how the navigation within the Sports section can grow to fit specific content. By understanding these concepts that apply creating folders for your navigation structure, you will be well on your way to having consistent navigation throughout your site.
Read more
  • 0
  • 0
  • 1985

article-image-jquery-ui-accordion-widget-part-2
Packt
15 Oct 2009
7 min read
Save for later

jQuery UI Accordion Widget - Part 2

Packt
15 Oct 2009
7 min read
Accordion animation You may have noticed the default slide animation built into the accordion. Apart from this, there are two other built-in animations that we can easily make use of. We can also switch off animations entirely by supplying false as the value of the animated property, although this doesn't look too good! The other values we can supply are bounceslide and easeslide. However, these aren't actually unique animations as such. These are different easing styles which don't change the animation itself but instead, alter the way it runs. You should note at this stage that additional jQuery plugins are required for these easing methods. For example, the bounceslide easing method causes the opening drawer to appear to bounce up and down slightly as it reaches the end of the animation. On the other hand, easeslide makes the animation begin slowly and then builds up to its normal speed. Let's take a moment to look at these different easing methods now. Change accordion11.html so that it appears as follows: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <link rel="stylesheet" type="text/css" href="styles/accordionTheme2.css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>jQuery UI Accordion Widget Example 12</title> </head> <body> <div id="myAccordion"> <span class="corner topLeft"></span><span class="corner topRight"></span><span class="corner bottomLeft"></span> <span class="corner bottomRight"></span> <div><a href="#">Header 1</a><div>Wow, look at all this content that can be shown or hidden with a simple click!</div></div> <div><a href="#">Header 2</a><div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpat ligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est. Ut posuere, mauris at sodales rutrum, turpis tellus fermentum metus, ut bibendum velit enim eu lectus. Suspendisse potenti.</div> </div> <div><a href="#">Header 3</a><div>Donec at dolor ac metus pharetra aliquam. Suspendisse purus. Fusce tempor ultrices libero. Sed quis nunc. Pellentesque tincidunt viverra felis. Integer elit mauris, egestas ultricies, gravida vitae, feugiat a, tellus. </div> </div> </div> <script type="text/javascript" src="jqueryui1.6rc2/jquery-1.2.6.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.core.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/jquery.easing.1.3.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/jquery.easing.compatibility.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.accordion.js"></script> <script type="text/javascript"> //function to execute when doc ready $(function() { //set custom easing var accOpts = { animated: "bounceslide" } //turn specified element into an accordion $("#myAccordion").accordion(accOpts); }); </script> </body> </html> Save this file as accordion12.html. We've used a couple of new script files in the source code. The jquery.easing.1.3.js file is the latest version of the easing plugin, and the jquery.easing.compatibility.js plugin which enables the latest version of the easing file to work without any further modifications. The easing type names were renamed in version 1.2 of the easing plugin. Both of these files can be found on the jQuery site. The built-in easing effects, based on a series of equations created by Robert Penner in 2006, are very easy to use and create a great effect which can help build individuality into accordion implementations Plugins There are many jQuery plugins available. These are often developed by the open-source community instead of the library's authors and can be used with jQuery and jQuery UI. A good place to find plugins is on the jQuery site itself at http://plugins.jquery.com/. Some of these plugins, such as the easing plugin, work with the library components, while other plugins, such as the compatibility plugin, assist other plugins. Accordion events The accordion defines the custom change event which is fired after a drawer on the accordion opens or closes. To react to this event, we can use the change configuration property to specify a function to be executed every time the event occurs. In a new file in your text editor, add the following code: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <link rel="stylesheet" type="text/css" href="styles/accordionTheme.css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>jQuery UI Accordion Widget Example 13</title> </head> <body> <div id="myAccordion"> <span class="corner topLeft"></span><span class="corner topRight"></span><span class="corner bottomLeft"></span> <span class="corner bottomRight"></span> <div><a href="#">Header 1</a><div id="panel1">Wow, look at all this content that can be shown or hidden with a simple click!</div> </div> <div><a href="#">Header 2</a><div id="panel2">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean sollicitudin. Sed interdum pulvinar justo. Nam iaculis volutpat ligula. Integer vitae felis quis diam laoreet ullamcorper. Etiam tincidunt est vitae est. Ut posuere, mauris at sodales rutrum, turpis tellus fermentum metus, ut bibendum velit enim eu lectus. Suspendisse potenti.</div></div> <div><a href="#">Header 3</a><div id="panel3">Donec at dolor ac metus pharetra aliquam. Suspendisse purus. Fusce tempor ultrices libero. Sed quis nunc. Pellentesque tincidunt viverra felis. Integer elit mauris, egestas ultricies, gravida vitae, feugiat a, tellus.</div> </div> </div> <script type="text/javascript" src="jqueryui1.6rc2/jquery-1.2.6.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.core.js"></script> <script type="text/javascript" src="jqueryui1.6rc2/ui/ui.accordion.js"></script> <script type="text/javascript"> //function to execute when doc ready $(function() { //define config object var accOpts = { //add change event callback change: function(e, ui) { alert($(ui.newContent).attr("id") + " was opened, " + $(ui.oldContent).attr("id") + " was closed"); } }; $("#myAccordion").accordion(accOpts); }); </script> </body> </html> Save this as accordion13.html. In this example, we use the change configuration property to specify an anonymous callback function which is executed every time the event is triggered. This function will automatically receive two objects as arguments. The first object is the event object which contains information about the event. The second object is an object containing useful information about the accordion widget, such as the content drawer that just opened or closed. In the mark-up for the accordion, we have given each of the content drawer <div> elements an id attribute which can be used in the alert generated by the change callback. We can use the ui.newContent and ui.oldContent properties to obtain the relevant content drawer and display its id in the alert. The accordion widget also defines the accordion change event which is fired after a drawer on the accordion opens or closes. To react to this event, we can use the standard jQuery bind() method to specify a callback function, just like with the tabs widget.
Read more
  • 0
  • 0
  • 1603